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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Code to handle IP32 IRQs
  3.  *
  4.  * This file is subject to the terms and conditions of the GNU General Public
  5.  * License.  See the file "COPYING" in the main directory of this archive
  6.  * for more details.
  7.  *
  8.  * Copyright (C) 2000 Harald Koerfgen
  9.  * Copyright (C) 2001 Keith M Wesolowski
  10.  */
  11. #include <linux/init.h>
  12. #include <linux/kernel_stat.h>
  13. #include <linux/types.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/bitops.h>
  16. #include <linux/kernel.h>
  17. #include <linux/slab.h>
  18. #include <linux/mm.h>
  19. #include <linux/random.h>
  20. #include <linux/sched.h>
  21. #include <asm/bitops.h>
  22. #include <asm/mipsregs.h>
  23. #include <asm/system.h>
  24. #include <asm/ip32/ip32_ints.h>
  25. #include <asm/ip32/crime.h>
  26. #include <asm/ip32/mace.h>
  27. #include <asm/signal.h>
  28. #undef DEBUG_IRQ
  29. #ifdef DEBUG_IRQ
  30. #define DBG(x...) printk(x)
  31. #else
  32. #define DBG(x...)
  33. #endif
  34. /* O2 irq map
  35.  *
  36.  * IP0 -> software (ignored)
  37.  * IP1 -> software (ignored)
  38.  * IP2 -> (irq0) C crime 1.1 all interrupts; crime 1.5 ???
  39.  * IP3 -> (irq1) X unknown
  40.  * IP4 -> (irq2) X unknown
  41.  * IP5 -> (irq3) X unknown
  42.  * IP6 -> (irq4) X unknown
  43.  * IP7 -> (irq5) 0 CPU count/compare timer (system timer)
  44.  *
  45.  * crime: (C)
  46.  *
  47.  * CRIME_INT_STAT 31:0:
  48.  *
  49.  * 0 -> 1 Video in 1
  50.  * 1 -> 2 Video in 2
  51.  * 2 -> 3 Video out
  52.  * 3 -> 4 Mace ethernet
  53.  * 4 -> S  SuperIO sub-interrupt
  54.  * 5 -> M  Miscellaneous sub-interrupt
  55.  * 6 -> A  Audio sub-interrupt
  56.  * 7 -> 8  PCI bridge errors
  57.  * 8 -> 9  PCI SCSI aic7xxx 0
  58.  * 9 -> 10  PCI SCSI aic7xxx 1
  59.  * 10 -> 11 PCI slot 0
  60.  * 11 -> 12 unused (PCI slot 1)
  61.  * 12 -> 13 unused (PCI slot 2)
  62.  * 13 -> 14 unused (PCI shared 0)
  63.  * 14 -> 15 unused (PCI shared 1)
  64.  * 15 -> 16 unused (PCI shared 2)
  65.  * 16 -> 17 GBE0 (E)
  66.  * 17 -> 18 GBE1 (E)
  67.  * 18 -> 19 GBE2 (E)
  68.  * 19 -> 20 GBE3 (E)
  69.  * 20 -> 21 CPU errors
  70.  * 21 -> 22 Memory errors
  71.  * 22 -> 23 RE empty edge (E)
  72.  * 23 -> 24 RE full edge (E)
  73.  * 24 -> 25 RE idle edge (E)
  74.  * 25 -> 26 RE empty level
  75.  * 26 -> 27 RE full level
  76.  * 27 -> 28 RE idle level
  77.  * 28 -> 29  unused (software 0) (E)
  78.  * 29 -> 30  unused (software 1) (E)
  79.  * 30 -> 31  unused (software 2) - crime 1.5 CPU SysCorError (E)
  80.  * 31 -> 32 VICE
  81.  *
  82.  * S, M, A: Use the MACE ISA interrupt register
  83.  * MACE_ISA_INT_STAT 31:0
  84.  *
  85.  * 0-7 -> 33-40 Audio
  86.  * 8 -> 41 RTC
  87.  * 9 -> 42 Keyboard
  88.  * 10 -> X Keyboard polled
  89.  * 11 -> 44 Mouse
  90.  * 12 -> X Mouse polled
  91.  * 13-15 -> 46-48 Count/compare timers
  92.  * 16-19 -> 49-52 Parallel (16 E)
  93.  * 20-25 -> 53-58 Serial 1 (22 E)
  94.  * 26-31 -> 59-64 Serial 2 (28 E)
  95.  *
  96.  * Note that this means IRQs 5-7, 43, and 45 do not exist.  This is a
  97.  * different IRQ map than IRIX uses, but that's OK as Linux irq handling
  98.  * is quite different anyway.
  99.  */
  100. /* Some initial interrupts to set up */
  101. extern void crime_memerr_intr (unsigned int irq, void *dev_id,
  102.        struct pt_regs *regs);
  103. extern void crime_cpuerr_intr (unsigned int irq, void *dev_id,
  104.        struct pt_regs *regs);
  105. struct irqaction memerr_irq = { crime_memerr_intr, SA_INTERRUPT,
  106.        0, "CRIME memory error", NULL,
  107.        NULL };
  108. struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT,
  109.        0, "CRIME CPU error", NULL,
  110.        NULL };
  111. extern void ip32_handle_int (void);
  112. asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
  113. /*
  114.  * For interrupts wired from a single device to the CPU.  Only the clock
  115.  * uses this it seems, which is IRQ 0 and IP7.
  116.  */
  117. static void enable_cpu_irq(unsigned int irq)
  118. {
  119. set_cp0_status(STATUSF_IP7);
  120. }
  121. static unsigned int startup_cpu_irq(unsigned int irq)
  122. {
  123. enable_cpu_irq(irq);
  124. return 0;
  125. }
  126. static void disable_cpu_irq(unsigned int irq)
  127. {
  128. clear_cp0_status(STATUSF_IP7);
  129. }
  130. static void end_cpu_irq(unsigned int irq)
  131. {
  132. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  133. enable_cpu_irq (irq);
  134. }
  135. #define shutdown_cpu_irq disable_cpu_irq
  136. #define mask_and_ack_cpu_irq disable_cpu_irq
  137. static struct hw_interrupt_type ip32_cpu_interrupt = {
  138. "IP32 CPU",
  139. startup_cpu_irq,
  140. shutdown_cpu_irq,
  141. enable_cpu_irq,
  142. disable_cpu_irq,
  143. mask_and_ack_cpu_irq,
  144. end_cpu_irq,
  145. NULL
  146. };
  147. /*
  148.  * This is for pure CRIME interrupts - ie not MACE.  The advantage?
  149.  * We get to split the register in half and do faster lookups.
  150.  */
  151. static void enable_crime_irq(unsigned int irq)
  152. {
  153. u64 crime_mask;
  154. unsigned long flags;
  155. save_and_cli(flags);
  156. crime_mask = crime_read_64(CRIME_INT_MASK);
  157. crime_mask |= 1 << (irq - 1);
  158. crime_write_64(CRIME_INT_MASK, crime_mask);
  159. restore_flags(flags);
  160. }
  161. static unsigned int startup_crime_irq(unsigned int irq)
  162. {
  163. enable_crime_irq(irq);
  164. return 0; /* This is probably not right; we could have pending irqs */
  165. }
  166. static void disable_crime_irq(unsigned int irq)
  167. {
  168. u64 crime_mask;
  169. unsigned long flags;
  170. save_and_cli(flags);
  171. crime_mask = crime_read_64(CRIME_INT_MASK);
  172. crime_mask &= ~(1 << (irq - 1));
  173. crime_write_64(CRIME_INT_MASK, crime_mask);
  174. restore_flags(flags);
  175. }
  176. static void mask_and_ack_crime_irq (unsigned int irq)
  177. {
  178. u64 crime_mask;
  179. unsigned long flags;
  180. /* Edge triggered interrupts must be cleared. */
  181. if ((irq >= CRIME_GBE0_IRQ && irq <= CRIME_GBE3_IRQ)
  182.     || (irq >= CRIME_RE_EMPTY_E_IRQ && irq <= CRIME_RE_IDLE_E_IRQ)
  183.     || (irq >= CRIME_SOFT0_IRQ && irq <= CRIME_SOFT2_IRQ)) {
  184. save_and_cli(flags);
  185. crime_mask = crime_read_64(CRIME_HARD_INT);
  186. crime_mask &= ~(1 << (irq - 1));
  187. crime_write_64(CRIME_HARD_INT, crime_mask);
  188. restore_flags(flags);
  189. }
  190. disable_crime_irq(irq);
  191. }
  192. static void end_crime_irq(unsigned int irq)
  193. {
  194. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  195. enable_crime_irq (irq);
  196. }
  197. #define shutdown_crime_irq disable_crime_irq
  198. static struct hw_interrupt_type ip32_crime_interrupt = {
  199. "IP32 CRIME",
  200. startup_crime_irq,
  201. shutdown_crime_irq,
  202. enable_crime_irq,
  203. disable_crime_irq,
  204. mask_and_ack_crime_irq,
  205. end_crime_irq,
  206. NULL
  207. };
  208. /*
  209.  * This is for MACE PCI interrupts.  We can decrease bus traffic by masking
  210.  * as close to the source as possible.  This also means we can take the
  211.  * next chunk of the CRIME register in one piece.
  212.  */
  213. static void enable_macepci_irq(unsigned int irq)
  214. {
  215. u32 mace_mask;
  216. u64 crime_mask;
  217. unsigned long flags;
  218. save_and_cli(flags);
  219. mace_mask = mace_read_32(MACEPCI_CONTROL);
  220. mace_mask |= MACEPCI_CONTROL_INT(irq - 9);
  221. mace_write_32(MACEPCI_CONTROL, mace_mask);
  222. /*
  223.  * In case the CRIME interrupt isn't enabled, we must enable it;
  224.  * however, we never disable interrupts at that level.
  225.  */
  226. crime_mask = crime_read_64(CRIME_INT_MASK);
  227. crime_mask |= 1 << (irq - 1);
  228. crime_write_64(CRIME_INT_MASK, crime_mask);
  229. restore_flags(flags);
  230. }
  231. static unsigned int startup_macepci_irq(unsigned int irq)
  232. {
  233. enable_macepci_irq (irq);
  234. return 0; /* XXX */
  235. }
  236. static void disable_macepci_irq(unsigned int irq)
  237. {
  238. u32 mace_mask;
  239. unsigned long flags;
  240. save_and_cli(flags);
  241. mace_mask = mace_read_32(MACEPCI_CONTROL);
  242. mace_mask &= ~MACEPCI_CONTROL_INT(irq - 9);
  243. mace_write_32(MACEPCI_CONTROL, mace_mask);
  244. restore_flags(flags);
  245. }
  246. static void end_macepci_irq(unsigned int irq)
  247. {
  248. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  249. enable_macepci_irq (irq);
  250. }
  251. #define shutdown_macepci_irq disable_macepci_irq
  252. #define mask_and_ack_macepci_irq disable_macepci_irq
  253. static struct hw_interrupt_type ip32_macepci_interrupt = {
  254. "IP32 MACE PCI",
  255. startup_macepci_irq,
  256. shutdown_macepci_irq,
  257. enable_macepci_irq,
  258. disable_macepci_irq,
  259. mask_and_ack_macepci_irq,
  260. end_macepci_irq,
  261. NULL
  262. };
  263. /* This is used for MACE ISA interrupts.  That means bits 4-6 in the
  264.  * CRIME register.
  265.  */
  266. static void enable_maceisa_irq (unsigned int irq)
  267. {
  268. u64 crime_mask;
  269. u32 mace_mask;
  270. unsigned int crime_int = 0;
  271. unsigned long flags;
  272. DBG ("maceisa enable: %un", irq);
  273. switch (irq) {
  274. case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ:
  275. crime_int = MACE_AUDIO_INT;
  276. break;
  277. case MACEISA_RTC_IRQ ... MACEISA_TIMER2_IRQ:
  278. crime_int = MACE_MISC_INT;
  279. break;
  280. case MACEISA_PARALLEL_IRQ ... MACEISA_SERIAL2_RDMAOR_IRQ:
  281. crime_int = MACE_SUPERIO_INT;
  282. break;
  283. }
  284. DBG ("crime_int %016lx enabledn", crime_int);
  285. save_and_cli(flags);
  286. crime_mask = crime_read_64(CRIME_INT_MASK);
  287. crime_mask |= crime_int;
  288. crime_write_64(CRIME_INT_MASK, crime_mask);
  289. mace_mask = mace_read_32(MACEISA_INT_MASK);
  290. mace_mask |= 1 << (irq - 33);
  291. mace_write_32(MACEISA_INT_MASK, mace_mask);
  292. restore_flags(flags);
  293. }
  294. static unsigned int startup_maceisa_irq (unsigned int irq)
  295. {
  296. enable_maceisa_irq(irq);
  297. return 0;
  298. }
  299. static void disable_maceisa_irq(unsigned int irq)
  300. {
  301. u32 mace_mask;
  302. unsigned long flags;
  303. save_and_cli (flags);
  304. mace_mask = mace_read_32(MACEISA_INT_MASK);
  305. mace_mask &= ~(1 << (irq - 33));
  306. mace_write_32(MACEISA_INT_MASK, mace_mask);
  307. restore_flags(flags);
  308. }
  309. static void mask_and_ack_maceisa_irq(unsigned int irq)
  310. {
  311. u32 mace_mask;
  312. unsigned long flags;
  313. switch (irq) {
  314. case MACEISA_PARALLEL_IRQ:
  315. case MACEISA_SERIAL1_TDMAPR_IRQ:
  316. case MACEISA_SERIAL2_TDMAPR_IRQ:
  317. save_and_cli(flags);
  318. mace_mask = mace_read_32(MACEISA_INT_STAT);
  319. mace_mask &= ~(1 << (irq - 33));
  320. mace_write_32(MACEISA_INT_STAT, mace_mask);
  321. restore_flags(flags);
  322. break;
  323. }
  324. disable_maceisa_irq(irq);
  325. }
  326. static void end_maceisa_irq(unsigned irq)
  327. {
  328. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  329. enable_maceisa_irq (irq);
  330. }
  331. #define shutdown_maceisa_irq disable_maceisa_irq
  332. static struct hw_interrupt_type ip32_maceisa_interrupt = {
  333. "IP32 MACE ISA",
  334. startup_maceisa_irq,
  335. shutdown_maceisa_irq,
  336. enable_maceisa_irq,
  337. disable_maceisa_irq,
  338. mask_and_ack_maceisa_irq,
  339. end_maceisa_irq,
  340. NULL
  341. };
  342. /* This is used for regular non-ISA, non-PCI MACE interrupts.  That means
  343.  * bits 0-3 and 7 in the CRIME register.
  344.  */
  345. static void enable_mace_irq(unsigned int irq)
  346. {
  347. u64 crime_mask;
  348. unsigned long flags;
  349. save_and_cli (flags);
  350. crime_mask = crime_read_64 (CRIME_INT_MASK);
  351. crime_mask |= 1 << (irq - 1);
  352. crime_write_64 (CRIME_INT_MASK, crime_mask);
  353. restore_flags (flags);
  354. }
  355. static unsigned int startup_mace_irq(unsigned int irq)
  356. {
  357. enable_mace_irq(irq);
  358. return 0;
  359. }
  360. static void disable_mace_irq(unsigned int irq)
  361. {
  362. u64 crime_mask;
  363. unsigned long flags;
  364. save_and_cli (flags);
  365. crime_mask = crime_read_64 (CRIME_INT_MASK);
  366. crime_mask &= ~(1 << (irq - 1));
  367. crime_write_64 (CRIME_INT_MASK, crime_mask);
  368. restore_flags(flags);
  369. }
  370. static void end_mace_irq(unsigned int irq)
  371. {
  372. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  373. enable_mace_irq (irq);
  374. }
  375. #define shutdown_mace_irq disable_mace_irq
  376. #define mask_and_ack_mace_irq disable_mace_irq
  377. static struct hw_interrupt_type ip32_mace_interrupt = {
  378. "IP32 MACE",
  379. startup_mace_irq,
  380. shutdown_mace_irq,
  381. enable_mace_irq,
  382. disable_mace_irq,
  383. mask_and_ack_mace_irq,
  384. end_mace_irq,
  385. NULL
  386. };
  387. static void ip32_unknown_interrupt (struct pt_regs *regs)
  388. {
  389. u64 crime;
  390. u32 mace;
  391. printk ("Unknown interrupt occurred!n");
  392. printk ("cp0_status: %08xtcp0_cause: %08xn",
  393. read_32bit_cp0_register (CP0_STATUS),
  394. read_32bit_cp0_register (CP0_CAUSE));
  395. crime = crime_read_64 (CRIME_INT_MASK);
  396. printk ("CRIME interrupt mask: %016lxn", crime);
  397. crime = crime_read_64 (CRIME_INT_STAT);
  398. printk ("CRIME interrupt status: %016lxn", crime);
  399. crime = crime_read_64 (CRIME_HARD_INT);
  400. printk ("CRIME hardware interrupt register: %016lxn", crime);
  401. mace = mace_read_32 (MACEISA_INT_MASK);
  402. printk ("MACE ISA interrupt mask: %08xn", mace);
  403. mace = mace_read_32 (MACEISA_INT_STAT);
  404. printk ("MACE ISA interrupt status: %08xn", mace);
  405. mace = mace_read_32 (MACEPCI_CONTROL);
  406. printk ("MACE PCI control register: %08xn", mace);
  407. printk("Register dump:n");
  408. show_regs(regs);
  409. printk("Please mail this report to linux-mips@oss.sgi.comn");
  410. printk("Spinning...");
  411. while(1) ;
  412. }
  413. /* CRIME 1.1 appears to deliver all interrupts to this one pin. */
  414. void ip32_irq0(struct pt_regs *regs)
  415. {
  416. u64 crime_int;
  417. u64 crime_mask;
  418. int irq = 0;
  419. unsigned long flags;
  420. save_and_cli (flags);
  421. /* disable crime interrupts */
  422. crime_mask = crime_read_64(CRIME_INT_MASK);
  423. crime_write_64(CRIME_INT_MASK, 0);
  424. crime_int = crime_read_64(CRIME_INT_STAT);
  425. if (crime_int & CRIME_MACE_INT_MASK) {
  426. crime_int &= CRIME_MACE_INT_MASK;
  427. irq = ffs (crime_int);
  428. } else if (crime_int & CRIME_MACEISA_INT_MASK) {
  429. u32 mace_int;
  430. mace_int = mace_read_32 (MACEISA_INT_STAT);
  431. if (mace_int == 0)
  432. irq = 0;
  433. else
  434. irq = ffs (mace_int) + 32;
  435. } else if (crime_int & CRIME_MACEPCI_INT_MASK) {
  436. crime_int &= CRIME_MACEPCI_INT_MASK;
  437. crime_int >>= 8;
  438. irq = ffs (crime_int) + 8;
  439. } else if (crime_int & 0xffff0000) {
  440. crime_int >>= 16;
  441. irq = ffs (crime_int) + 16;
  442. }
  443. if (irq == 0)
  444. ip32_unknown_interrupt(regs);
  445. DBG("*irq %u*n", irq);
  446. do_IRQ(irq, regs);
  447. /* enable crime interrupts */
  448. crime_write_64(CRIME_INT_MASK, crime_mask);
  449. restore_flags (flags);
  450. }
  451. void ip32_irq1(struct pt_regs *regs)
  452. {
  453. ip32_unknown_interrupt (regs);
  454. }
  455. void ip32_irq2(struct pt_regs *regs)
  456. {
  457. ip32_unknown_interrupt (regs);
  458. }
  459. void ip32_irq3(struct pt_regs *regs)
  460. {
  461. ip32_unknown_interrupt (regs);
  462. }
  463. void ip32_irq4(struct pt_regs *regs)
  464. {
  465. ip32_unknown_interrupt (regs);
  466. }
  467. void ip32_irq5(struct pt_regs *regs)
  468. {
  469. do_IRQ (CLOCK_IRQ, regs);
  470. }
  471. void __init init_IRQ(void)
  472. {
  473. unsigned int irq;
  474. int i;
  475. /* Install our interrupt handler, then clear and disable all
  476.  * CRIME and MACE interrupts.
  477.  */
  478. crime_write_64(CRIME_INT_MASK, 0);
  479. crime_write_64(CRIME_HARD_INT, 0);
  480. crime_write_64(CRIME_SOFT_INT, 0);
  481. mace_write_32(MACEISA_INT_STAT, 0);
  482. mace_write_32(MACEISA_INT_MASK, 0);
  483. set_except_vector(0, ip32_handle_int);
  484. for (i = 0; i < NR_IRQS; i++) {
  485. irq_desc[i].status  = IRQ_DISABLED;
  486. irq_desc[i].action  = NULL;
  487. irq_desc[i].depth   = 1;
  488. irq_desc[i].handler = &no_irq_type;
  489. }
  490. for (irq = 0; irq <= IP32_IRQ_MAX; irq++) {
  491. hw_irq_controller *controller;
  492. if (irq == CLOCK_IRQ)
  493. controller = &ip32_cpu_interrupt;
  494. else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ)
  495. controller = &ip32_mace_interrupt;
  496. else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ)
  497. controller = &ip32_macepci_interrupt;
  498. else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ)
  499. controller = &ip32_crime_interrupt;
  500. else
  501. controller = &ip32_maceisa_interrupt;
  502. irq_desc[irq].status = IRQ_DISABLED;
  503. irq_desc[irq].action = 0;
  504. irq_desc[irq].depth = 0;
  505. irq_desc[irq].handler = controller;
  506. }
  507. setup_irq(CRIME_MEMERR_IRQ, &memerr_irq);
  508. setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq);
  509. }