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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*  $Id: sun4d_irq.c,v 1.28 2001/07/17 16:17:33 anton Exp $
  2.  *  arch/sparc/kernel/sun4d_irq.c:
  3.  * SS1000/SC2000 interrupt handling.
  4.  *
  5.  *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  6.  *  Heavily based on arch/sparc/kernel/irq.c.
  7.  */
  8. #include <linux/config.h>
  9. #include <linux/ptrace.h>
  10. #include <linux/errno.h>
  11. #include <linux/linkage.h>
  12. #include <linux/kernel_stat.h>
  13. #include <linux/signal.h>
  14. #include <linux/sched.h>
  15. #include <linux/interrupt.h>
  16. #include <linux/slab.h>
  17. #include <linux/random.h>
  18. #include <linux/init.h>
  19. #include <linux/smp.h>
  20. #include <linux/smp_lock.h>
  21. #include <linux/spinlock.h>
  22. #include <asm/ptrace.h>
  23. #include <asm/processor.h>
  24. #include <asm/system.h>
  25. #include <asm/psr.h>
  26. #include <asm/smp.h>
  27. #include <asm/vaddrs.h>
  28. #include <asm/timer.h>
  29. #include <asm/openprom.h>
  30. #include <asm/oplib.h>
  31. #include <asm/traps.h>
  32. #include <asm/irq.h>
  33. #include <asm/io.h>
  34. #include <asm/pgalloc.h>
  35. #include <asm/pgtable.h>
  36. #include <asm/sbus.h>
  37. #include <asm/sbi.h>
  38. /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
  39. /* #define DISTRIBUTE_IRQS */
  40. struct sun4d_timer_regs *sun4d_timers;
  41. #define TIMER_IRQ 10
  42. #define MAX_STATIC_ALLOC 4
  43. extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
  44. extern int static_irq_count;
  45. unsigned char cpu_leds[32];
  46. #ifdef CONFIG_SMP
  47. unsigned char sbus_tid[32];
  48. #endif
  49. extern struct irqaction *irq_action[];
  50. struct sbus_action {
  51. struct irqaction *action;
  52. /* For SMP this needs to be extended */
  53. } *sbus_actions;
  54. static int pil_to_sbus[] = {
  55. 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
  56. };
  57. static int sbus_to_pil[] = {
  58. 0, 2, 3, 5, 7, 9, 11, 13,
  59. };
  60. static int nsbi;
  61. #ifdef CONFIG_SMP
  62. spinlock_t sun4d_imsk_lock = SPIN_LOCK_UNLOCKED;
  63. #endif
  64. int sun4d_get_irq_list(char *buf)
  65. {
  66. int i, j = 0, k = 0, len = 0, sbusl;
  67. struct irqaction * action;
  68. #ifdef CONFIG_SMP
  69. int x;
  70. #endif
  71. for (i = 0 ; i < NR_IRQS ; i++) {
  72. sbusl = pil_to_sbus[i];
  73. if (!sbusl) {
  74.   action = *(i + irq_action);
  75. if (!action) 
  76.          continue;
  77. } else {
  78. for (j = 0; j < nsbi; j++) {
  79. for (k = 0; k < 4; k++)
  80. if ((action = sbus_actions [(j << 5) + (sbusl << 2) + k].action))
  81. goto found_it;
  82. }
  83. continue;
  84. }
  85. found_it: len += sprintf(buf+len, "%3d: ", i);
  86. #ifndef CONFIG_SMP
  87. len += sprintf(buf+len, "%10u ", kstat_irqs(i));
  88. #else
  89. for (x = 0; x < smp_num_cpus; x++)
  90. len += sprintf(buf+len, "%10u ",
  91.        kstat.irqs[cpu_logical_map(x)][i]);
  92. #endif
  93. len += sprintf(buf+len, "%c %s",
  94. (action->flags & SA_INTERRUPT) ? '+' : ' ',
  95. action->name);
  96. action = action->next;
  97. for (;;) {
  98. for (; action; action = action->next) {
  99. len += sprintf(buf+len, ",%s %s",
  100. (action->flags & SA_INTERRUPT) ? " +" : "",
  101. action->name);
  102. }
  103. if (!sbusl) break;
  104. k++;
  105. if (k < 4)
  106. action = sbus_actions [(j << 5) + (sbusl << 2) + k].action;
  107. else {
  108. j++;
  109. if (j == nsbi) break;
  110. k = 0;
  111. action = sbus_actions [(j << 5) + (sbusl << 2)].action;
  112. }
  113. }
  114. len += sprintf(buf+len, "n");
  115. }
  116. return len;
  117. }
  118. void sun4d_free_irq(unsigned int irq, void *dev_id)
  119. {
  120. struct irqaction *action, **actionp;
  121. struct irqaction *tmp = NULL;
  122.         unsigned long flags;
  123. if (irq < 15)
  124. actionp = irq + irq_action;
  125. else
  126. actionp = &(sbus_actions[irq - (1 << 5)].action);
  127. action = *actionp;
  128. if (!action) {
  129. printk("Trying to free free IRQ%dn",irq);
  130. return;
  131. }
  132. if (dev_id) {
  133. for (; action; action = action->next) {
  134. if (action->dev_id == dev_id)
  135. break;
  136. tmp = action;
  137. }
  138. if (!action) {
  139. printk("Trying to free free shared IRQ%dn",irq);
  140. return;
  141. }
  142. } else if (action->flags & SA_SHIRQ) {
  143. printk("Trying to free shared IRQ%d with NULL device IDn", irq);
  144. return;
  145. }
  146. if (action->flags & SA_STATIC_ALLOC)
  147. {
  148.     /* This interrupt is marked as specially allocated
  149.      * so it is a bad idea to free it.
  150.      */
  151.     printk("Attempt to free statically allocated IRQ%d (%s)n",
  152.    irq, action->name);
  153.     return;
  154. }
  155.         save_and_cli(flags);
  156. if (action && tmp)
  157. tmp->next = action->next;
  158. else
  159. *actionp = action->next;
  160. kfree(action);
  161. if (!(*actionp))
  162. disable_irq(irq);
  163. restore_flags(flags);
  164. }
  165. extern void unexpected_irq(int, void *, struct pt_regs *);
  166. void sun4d_handler_irq(int irq, struct pt_regs * regs)
  167. {
  168. struct irqaction * action;
  169. int cpu = smp_processor_id();
  170. /* SBUS IRQ level (1 - 7) */
  171. int sbusl = pil_to_sbus[irq];
  172. /* FIXME: Is this necessary?? */
  173. cc_get_ipen();
  174. cc_set_iclr(1 << irq);
  175. irq_enter(cpu, irq);
  176. kstat.irqs[cpu][irq]++;
  177. if (!sbusl) {
  178. action = *(irq + irq_action);
  179. if (!action)
  180. unexpected_irq(irq, 0, regs);
  181. do {
  182. action->handler(irq, action->dev_id, regs);
  183. action = action->next;
  184. } while (action);
  185. } else {
  186. int bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
  187. int sbino;
  188. struct sbus_action *actionp;
  189. unsigned mask, slot;
  190. int sbil = (sbusl << 2);
  191. bw_clear_intr_mask(sbusl, bus_mask);
  192. /* Loop for each pending SBI */
  193. for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1)
  194. if (bus_mask & 1) {
  195. mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
  196. mask &= (0xf << sbil);
  197. actionp = sbus_actions + (sbino << 5) + (sbil);
  198. /* Loop for each pending SBI slot */
  199. for (slot = (1 << sbil); mask; slot <<= 1, actionp++)
  200. if (mask & slot) {
  201. mask &= ~slot;
  202. action = actionp->action;
  203. if (!action)
  204. unexpected_irq(irq, 0, regs);
  205. do {
  206. action->handler(irq, action->dev_id, regs);
  207. action = action->next;
  208. } while (action);
  209. release_sbi(SBI2DEVID(sbino), slot);
  210. }
  211. }
  212. }
  213. irq_exit(cpu, irq);
  214. if (softirq_pending(cpu))
  215. do_softirq();
  216. }
  217. unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
  218. {
  219. int sbusl = pil_to_sbus[irq];
  220. if (sbusl)
  221. return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot;
  222. else
  223. return irq;
  224. }
  225. int sun4d_request_irq(unsigned int irq,
  226. void (*handler)(int, void *, struct pt_regs *),
  227. unsigned long irqflags, const char * devname, void *dev_id)
  228. {
  229. struct irqaction *action, *tmp = NULL, **actionp;
  230. unsigned long flags;
  231. if(irq > 14 && irq < (1 << 5))
  232. return -EINVAL;
  233. if (!handler)
  234.     return -EINVAL;
  235. if (irq >= (1 << 5))
  236. actionp = &(sbus_actions[irq - (1 << 5)].action);
  237. else
  238. actionp = irq + irq_action;
  239. action = *actionp;
  240. if (action) {
  241. if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
  242. for (tmp = action; tmp->next; tmp = tmp->next);
  243. } else {
  244. return -EBUSY;
  245. }
  246. if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
  247. printk("Attempt to mix fast and slow interrupts on IRQ%d deniedn", irq);
  248. return -EBUSY;
  249. }   
  250. action = NULL; /* Or else! */
  251. }
  252. save_and_cli(flags);
  253. /* If this is flagged as statically allocated then we use our
  254.  * private struct which is never freed.
  255.  */
  256. if (irqflags & SA_STATIC_ALLOC) {
  257.     if (static_irq_count < MAX_STATIC_ALLOC)
  258. action = &static_irqaction[static_irq_count++];
  259.     else
  260. printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmallocn",irq, devname);
  261. }
  262. if (action == NULL)
  263.     action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
  264.  GFP_KERNEL);
  265. if (!action) { 
  266. restore_flags(flags);
  267. return -ENOMEM;
  268. }
  269. action->handler = handler;
  270. action->flags = irqflags;
  271. action->mask = 0;
  272. action->name = devname;
  273. action->next = NULL;
  274. action->dev_id = dev_id;
  275. if (tmp)
  276. tmp->next = action;
  277. else
  278. *actionp = action;
  279. enable_irq(irq);
  280. restore_flags(flags);
  281. return 0;
  282. }
  283. static void sun4d_disable_irq(unsigned int irq)
  284. {
  285. #ifdef CONFIG_SMP
  286. int tid = sbus_tid[(irq >> 5) - 1];
  287. unsigned long flags;
  288. #endif
  289. if (irq < NR_IRQS) return;
  290. #ifdef CONFIG_SMP
  291. spin_lock_irqsave(&sun4d_imsk_lock, flags);
  292. cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
  293. spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
  294. #else
  295. cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7]));
  296. #endif
  297. }
  298. static void sun4d_enable_irq(unsigned int irq)
  299. {
  300. #ifdef CONFIG_SMP
  301. int tid = sbus_tid[(irq >> 5) - 1];
  302. unsigned long flags;
  303. #endif
  304. if (irq < NR_IRQS) return;
  305. #ifdef CONFIG_SMP
  306. spin_lock_irqsave(&sun4d_imsk_lock, flags);
  307. cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
  308. spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
  309. #else
  310. cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
  311. #endif
  312. }
  313. #ifdef CONFIG_SMP
  314. static void sun4d_set_cpu_int(int cpu, int level)
  315. {
  316. sun4d_send_ipi(cpu, level);
  317. }
  318. static void sun4d_clear_ipi(int cpu, int level)
  319. {
  320. }
  321. static void sun4d_set_udt(int cpu)
  322. {
  323. }
  324. /* Setup IRQ distribution scheme. */
  325. void __init sun4d_distribute_irqs(void)
  326. {
  327. #ifdef DISTRIBUTE_IRQS
  328. struct sbus_bus *sbus;
  329. unsigned long sbus_serving_map;
  330. sbus_serving_map = cpu_present_map;
  331. for_each_sbus(sbus) {
  332. if ((sbus->board * 2) == boot_cpu_id && (cpu_present_map & (1 << (sbus->board * 2 + 1))))
  333. sbus_tid[sbus->board] = (sbus->board * 2 + 1);
  334. else if (cpu_present_map & (1 << (sbus->board * 2)))
  335. sbus_tid[sbus->board] = (sbus->board * 2);
  336. else if (cpu_present_map & (1 << (sbus->board * 2 + 1)))
  337. sbus_tid[sbus->board] = (sbus->board * 2 + 1);
  338. else
  339. sbus_tid[sbus->board] = 0xff;
  340. if (sbus_tid[sbus->board] != 0xff)
  341. sbus_serving_map &= ~(1 << sbus_tid[sbus->board]);
  342. }
  343. for_each_sbus(sbus)
  344. if (sbus_tid[sbus->board] == 0xff) {
  345. int i = 31;
  346. if (!sbus_serving_map)
  347. sbus_serving_map = cpu_present_map;
  348. while (!(sbus_serving_map & (1 << i)))
  349. i--;
  350. sbus_tid[sbus->board] = i;
  351. sbus_serving_map &= ~(1 << i);
  352. }
  353. for_each_sbus(sbus) {
  354. printk("sbus%d IRQs directed to CPU%dn", sbus->board, sbus_tid[sbus->board]);
  355. set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3);
  356. }
  357. #else
  358. struct sbus_bus *sbus;
  359. int cpuid = cpu_logical_map(1);
  360. if (cpuid == -1)
  361. cpuid = cpu_logical_map(0);
  362. for_each_sbus(sbus) {
  363. sbus_tid[sbus->board] = cpuid;
  364. set_sbi_tid(sbus->devid, cpuid << 3);
  365. }
  366. printk("All sbus IRQs directed to CPU%dn", cpuid);
  367. #endif
  368. }
  369. #endif
  370.  
  371. static void sun4d_clear_clock_irq(void)
  372. {
  373. volatile unsigned int clear_intr;
  374. clear_intr = sun4d_timers->l10_timer_limit;
  375. }
  376. static void sun4d_clear_profile_irq(int cpu)
  377. {
  378. bw_get_prof_limit(cpu);
  379. }
  380. static void sun4d_load_profile_irq(int cpu, unsigned int limit)
  381. {
  382. bw_set_prof_limit(cpu, limit);
  383. }
  384. static void __init sun4d_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))
  385. {
  386. int irq;
  387. extern struct prom_cpuinfo linux_cpus[NR_CPUS];
  388. int cpu;
  389. struct resource r;
  390. /* Map the User Timer registers. */
  391. memset(&r, 0, sizeof(r));
  392. #ifdef CONFIG_SMP
  393. r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
  394. #else
  395. r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
  396. #endif
  397. r.flags = 0xf;
  398. sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0,
  399.     PAGE_SIZE, "user timer");
  400. sun4d_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
  401. master_l10_counter = &sun4d_timers->l10_cur_count;
  402. master_l10_limit = &sun4d_timers->l10_timer_limit;
  403. irq = request_irq(TIMER_IRQ,
  404.   counter_fn,
  405.   (SA_INTERRUPT | SA_STATIC_ALLOC),
  406.   "timer", NULL);
  407. if (irq) {
  408. prom_printf("time_init: unable to attach IRQ%dn",TIMER_IRQ);
  409. prom_halt();
  410. }
  411. /* Enable user timer free run for CPU 0 in BW */
  412. /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
  413.     
  414. for(cpu = 0; cpu < linux_num_cpus; cpu++)
  415. sun4d_load_profile_irq((linux_cpus[cpu].mid >> 3), 0);
  416. #ifdef CONFIG_SMP
  417. {
  418. unsigned long flags;
  419. extern unsigned long lvl14_save[4];
  420. struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
  421. extern unsigned int real_irq_entry[], smp4d_ticker[];
  422. extern unsigned int patchme_maybe_smp_msg[];
  423. /* Adjust so that we jump directly to smp4d_ticker */
  424. lvl14_save[2] += smp4d_ticker - real_irq_entry;
  425. /* For SMP we use the level 14 ticker, however the bootup code
  426.  * has copied the firmwares level 14 vector into boot cpu's
  427.  * trap table, we must fix this now or we get squashed.
  428.  */
  429. __save_and_cli(flags);
  430. patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
  431. trap_table->inst_one = lvl14_save[0];
  432. trap_table->inst_two = lvl14_save[1];
  433. trap_table->inst_three = lvl14_save[2];
  434. trap_table->inst_four = lvl14_save[3];
  435. local_flush_cache_all();
  436. __restore_flags(flags);
  437. }
  438. #endif
  439. }
  440. void __init sun4d_init_sbi_irq(void)
  441. {
  442. struct sbus_bus *sbus;
  443. unsigned mask;
  444. nsbi = 0;
  445. for_each_sbus(sbus)
  446. nsbi++;
  447. sbus_actions = (struct sbus_action *)kmalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
  448. memset (sbus_actions, 0, (nsbi * 8 * 4 * sizeof(struct sbus_action)));
  449. for_each_sbus(sbus) {
  450. #ifdef CONFIG_SMP
  451. extern unsigned char boot_cpu_id;
  452. set_sbi_tid(sbus->devid, boot_cpu_id << 3);
  453. sbus_tid[sbus->board] = boot_cpu_id;
  454. #endif
  455. /* Get rid of pending irqs from PROM */
  456. mask = acquire_sbi(sbus->devid, 0xffffffff);
  457. if (mask) {
  458. printk ("Clearing pending IRQs %08x on SBI %dn", mask, sbus->board);
  459. release_sbi(sbus->devid, mask);
  460. }
  461. }
  462. }
  463. static char *sun4d_irq_itoa(unsigned int irq)
  464. {
  465. static char buff[16];
  466. if (irq < (1 << 5))
  467. sprintf(buff, "%d", irq);
  468. else
  469. sprintf(buff, "%d,%x", sbus_to_pil[(irq >> 2) & 7], irq);
  470. return buff;
  471. }
  472. void __init sun4d_init_IRQ(void)
  473. {
  474. __cli();
  475. BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
  476. BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
  477. BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
  478. BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
  479. BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
  480. BTFIXUPSET_CALL(__irq_itoa, sun4d_irq_itoa, BTFIXUPCALL_NORM);
  481. init_timers = sun4d_init_timers;
  482. #ifdef CONFIG_SMP
  483. BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
  484. BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
  485. BTFIXUPSET_CALL(set_irq_udt, sun4d_set_udt, BTFIXUPCALL_NOP);
  486. #endif
  487. /* Cannot enable interrupts until OBP ticker is disabled. */
  488. }