irq.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:11k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * BRIEF MODULE DESCRIPTION
  3.  * Code to handle irqs on GT64120A boards
  4.  *  Derived from mips/orion and Cort <cort@fsmlabs.com>
  5.  *
  6.  * Copyright (C) 2000 RidgeRun, Inc.
  7.  * Author: RidgeRun, Inc.
  8.  *   glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
  9.  *
  10.  *  This program is free software; you can redistribute  it and/or modify it
  11.  *  under  the terms of  the GNU General  Public License as published by the
  12.  *  Free Software Foundation;  either version 2 of the  License, or (at your
  13.  *  option) any later version.
  14.  *
  15.  *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
  16.  *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
  17.  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
  18.  *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
  19.  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20.  *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
  21.  *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  22.  *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
  23.  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24.  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.  *
  26.  *  You should have received a copy of the  GNU General Public License along
  27.  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  28.  *  675 Mass Ave, Cambridge, MA 02139, USA.
  29.  */
  30. #include <linux/config.h>
  31. #include <linux/errno.h>
  32. #include <linux/init.h>
  33. #include <linux/kernel_stat.h>
  34. #include <linux/module.h>
  35. #include <linux/signal.h>
  36. #include <linux/sched.h>
  37. #include <linux/types.h>
  38. #include <linux/interrupt.h>
  39. #include <linux/ioport.h>
  40. #include <linux/timex.h>
  41. #include <linux/slab.h>
  42. #include <linux/random.h>
  43. #include <asm/bitops.h>
  44. #include <asm/bootinfo.h>
  45. #include <asm/io.h>
  46. #include <asm/mipsregs.h>
  47. #include <asm/system.h>
  48. #include <asm/galileo-boards/ev64120int.h>
  49. #undef IRQ_DEBUG
  50. #ifdef IRQ_DEBUG
  51. #define DBG(x...) printk(x)
  52. #else
  53. #define DBG(x...)
  54. #endif
  55. asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
  56. #define MAX_AGENTS_PER_INT 21 /*  Random number  */
  57. unsigned char pci_int_irq[MAX_AGENTS_PER_INT];
  58. static int max_interrupts = 0;
  59. /*  Duplicate interrupt handlers.  */
  60. /********************************************************************
  61.  *pci_int(A/B/C/D) -
  62.  *
  63.  *Calls all the handlers connected to PCI interrupt A/B/C/D
  64.  *
  65.  *Inputs :
  66.  *
  67.  *Outpus :
  68.  *
  69.  *********************************************************************/
  70. asmlinkage __inline__ void pci_intA(struct pt_regs *regs)
  71. {
  72. unsigned int count = 0;
  73. DBG(KERN_INFO "pci_intA, max_interrupts %dn", max_interrupts);
  74. for (count = 0; count < max_interrupts; count++) {
  75. do_IRQ(pci_int_irq[count], regs);
  76. }
  77. }
  78. asmlinkage __inline__ void pci_intD(struct pt_regs *regs)
  79. {
  80. unsigned int count = 0;
  81. DBG(KERN_INFO "pci_intD, max_interrupts %dn", max_interrupts);
  82. for (count = 0; count < max_interrupts; count++) {
  83. do_IRQ(pci_int_irq[count], regs);
  84. }
  85. }
  86. /* Function for careful CP0 interrupt mask access */
  87. static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
  88. {
  89. unsigned long status = read_32bit_cp0_register(CP0_STATUS);
  90. DBG(KERN_INFO "modify_cp0_intmask clr %x, set %xn", clr_mask,
  91.     set_mask);
  92. DBG(KERN_INFO "modify_cp0_intmask status %xn", status);
  93. status &= ~((clr_mask & 0xFF) << 8);
  94. status |= (set_mask & 0xFF) << 8;
  95. DBG(KERN_INFO "modify_cp0_intmask status %xn", status);
  96. write_32bit_cp0_register(CP0_STATUS, status);
  97. }
  98. static inline void mask_irq(unsigned int irq_nr)
  99. {
  100. modify_cp0_intmask(irq_nr, 0);
  101. }
  102. static inline void unmask_irq(unsigned int irq_nr)
  103. {
  104. modify_cp0_intmask(0, irq_nr);
  105. }
  106. void disable_irq(unsigned int irq_nr)
  107. {
  108. unsigned long flags;
  109. DBG(KERN_INFO "disable_irq, irq %dn", irq_nr);
  110. save_and_cli(flags);
  111. if (irq_nr >= 8) { // All PCI interrupts are on line 5 or 2
  112. mask_irq(9 << 2);
  113. } else {
  114. mask_irq(1 << irq_nr);
  115. }
  116. restore_flags(flags);
  117. }
  118. void enable_irq(unsigned int irq_nr)
  119. {
  120. unsigned long flags;
  121. DBG(KERN_INFO "enable_irq, irq %dn", irq_nr);
  122. save_and_cli(flags);
  123. if (irq_nr >= 8) { // All PCI interrupts are on line 5 or 2
  124. DBG(KERN_INFO __FUNCTION__ " pci interrupt %dn", irq_nr);
  125. unmask_irq(9 << 2);
  126. } else {
  127. DBG(KERN_INFO __FUNCTION__ " interrupt set mask %dn",
  128.     1 << irq_nr);
  129. unmask_irq(1 << irq_nr);
  130. }
  131. restore_flags(flags);
  132. }
  133. /*
  134.  * Generic no controller code
  135.  */
  136. static void no_irq_enable_disable(unsigned int irq)
  137. {
  138. }
  139. static unsigned int no_irq_startup(unsigned int irq)
  140. {
  141. return 0;
  142. }
  143. #if 0
  144. static void no_irq_ack(unsigned int irq)
  145. {
  146. printk(KERN_CRIT "Unexpected IRQ trap at vector %un", irq);
  147. }
  148. #endif
  149. struct hw_interrupt_type no_irq_type = {
  150. typename:"none",
  151. startup:no_irq_startup,
  152. shutdown:no_irq_enable_disable,
  153. enable:no_irq_enable_disable,
  154. disable:no_irq_enable_disable,
  155. ack:NULL,
  156. end:no_irq_enable_disable,
  157. };
  158. //      ack:            no_irq_ack,                re-enable later -- SKJ
  159. /*
  160.  * Controller mappings for all interrupt sources:
  161.  */
  162. irq_desc_t irq_desc[NR_IRQS];
  163. atomic_t irq_err_count;
  164. int get_irq_list(char *buf)
  165. {
  166. int i, len = 0, j;
  167. struct irqaction *action;
  168. len += sprintf(buf + len, "           ");
  169. for (j = 0; j < smp_num_cpus; j++)
  170. len += sprintf(buf + len, "CPU%d       ", j);
  171. *(char *) (buf + len++) = 'n';
  172. for (i = 0; i < NR_IRQS; i++) {
  173. action = irq_desc[i].action;
  174. if (!action || !action->handler)
  175. continue;
  176. len += sprintf(buf + len, "%3d: ", i);
  177. len += sprintf(buf + len, "%10u ", kstat_irqs(i));
  178. if (irq_desc[i].handler)
  179. len +=
  180.     sprintf(buf + len, " %s ",
  181.     irq_desc[i].handler->typename);
  182. else
  183. len += sprintf(buf + len, "  None      ");
  184. len += sprintf(buf + len, "    %s", action->name);
  185. for (action = action->next; action; action = action->next) {
  186. len += sprintf(buf + len, ", %s", action->name);
  187. }
  188. len += sprintf(buf + len, "n");
  189. }
  190. len += sprintf(buf + len, "BAD: %10lun", atomic_read(&irq_err_count));
  191. return len;
  192. }
  193. asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
  194. {
  195. struct irqaction *action;
  196. int cpu;
  197. #ifdef IRQ_DEBUG
  198. if (irq != TIMER)
  199. DBG(KERN_INFO __FUNCTION__ " irq = %dn", irq);
  200. if (irq != TIMER)
  201. DBG(KERN_INFO "cause register = %xn",
  202.     read_32bit_cp0_register(CP0_CAUSE));
  203. if (irq != TIMER)
  204. DBG(KERN_INFO "status register = %xn",
  205.     read_32bit_cp0_register(CP0_STATUS));
  206. #endif
  207. cpu = smp_processor_id();
  208. irq_enter(cpu, irq);
  209. kstat.irqs[cpu][irq]++;
  210. if (irq_desc[irq].handler->ack) {
  211. irq_desc[irq].handler->ack(irq);
  212. }
  213. disable_irq(irq);
  214. action = irq_desc[irq].action;
  215. if (action && action->handler) {
  216. #ifdef IRQ_DEBUG
  217. if (irq != TIMER)
  218. DBG(KERN_INFO
  219.     "rr: irq %d action %p and handler %pn", irq,
  220.     action, action->handler);
  221. #endif
  222. if (!(action->flags & SA_INTERRUPT))
  223. __sti();
  224. do {
  225. action->handler(irq, action->dev_id, regs);
  226. action = action->next;
  227. } while (action);
  228. __cli();
  229. if (irq_desc[irq].handler) {
  230. if (irq_desc[irq].handler->end)
  231. irq_desc[irq].handler->end(irq);
  232. else if (irq_desc[irq].handler->enable)
  233. irq_desc[irq].handler->enable(irq);
  234. }
  235. }
  236. enable_irq(irq);
  237. irq_exit(cpu, irq);
  238. if (softirq_pending(cpu))
  239. do_softirq();
  240. /* unmasking and bottom half handling is done magically for us. */
  241. }
  242. int request_irq(unsigned int irq,
  243. void (*handler) (int, void *, struct pt_regs *),
  244. unsigned long irqflags, const char *devname, void *dev_id)
  245. {
  246. struct irqaction *old, **p, *action;
  247. unsigned long flags;
  248. DBG(KERN_INFO "rr:dev %s irq %d handler %xn", devname, irq,
  249.     handler);
  250. if (irq >= NR_IRQS)
  251. return -EINVAL;
  252. action = (struct irqaction *)
  253.     kmalloc(sizeof(struct irqaction), GFP_KERNEL);
  254. if (!action)
  255. return -ENOMEM;
  256. action->handler = handler;
  257. action->flags = irqflags;
  258. action->mask = 0;
  259. action->name = devname;
  260. action->dev_id = dev_id;
  261. action->next = NULL;
  262. save_flags(flags);
  263. cli();
  264. p = &irq_desc[irq].action;
  265. if ((old = *p) != NULL) {
  266. /* Can't share interrupts unless both agree to */
  267. if (!(old->flags & action->flags & SA_SHIRQ))
  268. return -EBUSY;
  269. /* add new interrupt at end of irq queue */
  270. do {
  271. p = &old->next;
  272. old = *p;
  273. } while (old);
  274. }
  275. *p = action;
  276. restore_flags(flags);
  277. if (irq >= 8) {
  278. DBG(KERN_INFO "request_irq, max_interrupts %dn",
  279.     max_interrupts);
  280. pci_int_irq[max_interrupts++] = irq; // NOTE:  Add error-handling if > max
  281. }
  282. enable_irq(irq);
  283. return 0;
  284. }
  285. void free_irq(unsigned int irq, void *dev_id)
  286. {
  287. struct irqaction *p, *old = NULL;
  288. unsigned long flags;
  289. int count, tmp, removed = 0;
  290. for (p = irq_desc[irq].action; p != NULL; old = p, p = p->next) {
  291. /* Found the IRQ, is it the correct dev_id?  */
  292. if (dev_id == p->dev_id) {
  293. save_flags(flags);
  294. cli();
  295. // remove link from list
  296. if (old)
  297. old->next = p->next;
  298. else
  299. irq_desc[irq].action = p->next;
  300. restore_flags(flags);
  301. kfree(p);
  302. removed = 1;
  303. break;
  304. }
  305. }
  306. /*
  307.    Remove PCI interrupts from the pci_int_irq list.  Make sure
  308.    that some handler was removed before decrementing max_interrupts.
  309.  */
  310. if ((irq >= 8) && (removed)) {
  311. for (count = 0; count < max_interrupts; count++) {
  312. if (pci_int_irq[count] == irq) {
  313. for (tmp = count; tmp < max_interrupts;
  314.      tmp++) {
  315. pci_int_irq[tmp] =
  316.     pci_int_irq[tmp + 1];
  317. }
  318. }
  319. }
  320. max_interrupts--;
  321. DBG(KERN_INFO "free_irq, max_interrupts %dn",
  322.     max_interrupts);
  323. }
  324. }
  325. unsigned long probe_irq_on(void)
  326. {
  327. printk(KERN_INFO "probe_irq_onn");
  328. return 0;
  329. }
  330. int probe_irq_off(unsigned long irqs)
  331. {
  332. printk(KERN_INFO "probe_irq_offn");
  333. return 0;
  334. }
  335. /********************************************************************
  336.  *galileo_irq_setup -
  337.  *
  338.  *Initializes CPU interrupts
  339.  *
  340.  *
  341.  *Inputs :
  342.  *
  343.  *Outpus :
  344.  *
  345.  *********************************************************************/
  346. void galileo_irq_setup(void)
  347. {
  348. extern asmlinkage void galileo_handle_int(void);
  349. extern void galileo_irq_init(void);
  350. DBG(KERN_INFO "rr: galileo_irq_setup entryn");
  351. galileo_irq_init();
  352. /*
  353.  * Clear all of the interrupts while we change the able around a bit.
  354.  */
  355. clear_cp0_status(ST0_IM);
  356. /* Sets the exception_handler array. */
  357. set_except_vector(0, galileo_handle_int);
  358. cli();
  359. /*
  360.  * Enable timer.  Other interrupts will be enabled as they are
  361.  * registered.
  362.  */
  363. set_cp0_status(IE_IRQ2);
  364. #ifdef CONFIG_REMOTE_DEBUG
  365. {
  366. extern int DEBUG_CHANNEL;
  367. serial_init(DEBUG_CHANNEL);
  368. serial_set(DEBUG_CHANNEL, 115200);
  369. set_debug_traps();
  370. breakpoint(); /* you may move this line to whereever you want :-) */
  371. }
  372. #endif
  373. }
  374. void init_irq_proc(void)
  375. {
  376. /* Nothing, for now.  */
  377. }
  378. void __init init_IRQ(void)
  379. {
  380. int i;
  381. DBG(KERN_INFO "rr:init_IRQn");
  382. /*  Let's initialize our IRQ descriptors  */
  383. for (i = 0; i < NR_IRQS; i++) {
  384. irq_desc[i].status = 0;
  385. irq_desc[i].handler = &no_irq_type;
  386. irq_desc[i].action = NULL;
  387. irq_desc[i].depth = 0;
  388. irq_desc[i].lock = SPIN_LOCK_UNLOCKED;
  389. }
  390. galileo_irq_setup();
  391. }