sys_marvel.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /*
  2. * linux/arch/alpha/kernel/sys_marvel.c
  3. *
  4. * Marvel / IO7 support
  5. */
  6. #include <linux/kernel.h>
  7. #include <linux/types.h>
  8. #include <linux/mm.h>
  9. #include <linux/sched.h>
  10. #include <linux/pci.h>
  11. #include <linux/init.h>
  12. #include <linux/bitops.h>
  13. #include <asm/ptrace.h>
  14. #include <asm/dma.h>
  15. #include <asm/irq.h>
  16. #include <asm/mmu_context.h>
  17. #include <asm/io.h>
  18. #include <asm/pgtable.h>
  19. #include <asm/core_marvel.h>
  20. #include <asm/hwrpb.h>
  21. #include <asm/tlbflush.h>
  22. #include <asm/vga.h>
  23. #include <asm/rtc.h>
  24. #include "proto.h"
  25. #include "err_impl.h"
  26. #include "irq_impl.h"
  27. #include "pci_impl.h"
  28. #include "machvec_impl.h"
  29. #if NR_IRQS < MARVEL_NR_IRQS
  30. # error NR_IRQS < MARVEL_NR_IRQS !!!
  31. #endif
  32. /*
  33. * Interrupt handling.
  34. */
  35. static void
  36. io7_device_interrupt(unsigned long vector)
  37. {
  38. unsigned int pid;
  39. unsigned int irq;
  40. /*
  41. * Vector is 0x800 + (interrupt)
  42. *
  43. * where (interrupt) is:
  44. *
  45. * ...16|15 14|13 4|3 0
  46. * -----+-----+--------+---
  47. * PE | 0 | irq | 0
  48. *
  49. * where (irq) is
  50. *
  51. * 0x0800 - 0x0ff0 - 0x0800 + (LSI id << 4)
  52. * 0x1000 - 0x2ff0 - 0x1000 + (MSI_DAT<8:0> << 4)
  53. */
  54. pid = vector >> 16;
  55. irq = ((vector & 0xffff) - 0x800) >> 4;
  56. irq += 16; /* offset for legacy */
  57. irq &= MARVEL_IRQ_VEC_IRQ_MASK; /* not too many bits */
  58. irq |= pid << MARVEL_IRQ_VEC_PE_SHIFT; /* merge the pid */
  59. handle_irq(irq);
  60. }
  61. static volatile unsigned long *
  62. io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
  63. {
  64. volatile unsigned long *ctl;
  65. unsigned int pid;
  66. struct io7 *io7;
  67. pid = irq >> MARVEL_IRQ_VEC_PE_SHIFT;
  68. if (!(io7 = marvel_find_io7(pid))) {
  69. printk(KERN_ERR
  70. "%s for nonexistent io7 -- vec %x, pid %d\n",
  71. __func__, irq, pid);
  72. return NULL;
  73. }
  74. irq &= MARVEL_IRQ_VEC_IRQ_MASK; /* isolate the vector */
  75. irq -= 16; /* subtract legacy bias */
  76. if (irq >= 0x180) {
  77. printk(KERN_ERR
  78. "%s for invalid irq -- pid %d adjusted irq %x\n",
  79. __func__, pid, irq);
  80. return NULL;
  81. }
  82. ctl = &io7->csrs->PO7_LSI_CTL[irq & 0xff].csr; /* assume LSI */
  83. if (irq >= 0x80) /* MSI */
  84. ctl = &io7->csrs->PO7_MSI_CTL[((irq - 0x80) >> 5) & 0x0f].csr;
  85. if (pio7) *pio7 = io7;
  86. return ctl;
  87. }
  88. static void
  89. io7_enable_irq(struct irq_data *d)
  90. {
  91. volatile unsigned long *ctl;
  92. unsigned int irq = d->irq;
  93. struct io7 *io7;
  94. ctl = io7_get_irq_ctl(irq, &io7);
  95. if (!ctl || !io7) {
  96. printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
  97. __func__, irq);
  98. return;
  99. }
  100. spin_lock(&io7->irq_lock);
  101. *ctl |= 1UL << 24;
  102. mb();
  103. *ctl;
  104. spin_unlock(&io7->irq_lock);
  105. }
  106. static void
  107. io7_disable_irq(struct irq_data *d)
  108. {
  109. volatile unsigned long *ctl;
  110. unsigned int irq = d->irq;
  111. struct io7 *io7;
  112. ctl = io7_get_irq_ctl(irq, &io7);
  113. if (!ctl || !io7) {
  114. printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
  115. __func__, irq);
  116. return;
  117. }
  118. spin_lock(&io7->irq_lock);
  119. *ctl &= ~(1UL << 24);
  120. mb();
  121. *ctl;
  122. spin_unlock(&io7->irq_lock);
  123. }
  124. static void
  125. marvel_irq_noop(struct irq_data *d)
  126. {
  127. return;
  128. }
  129. static struct irq_chip marvel_legacy_irq_type = {
  130. .name = "LEGACY",
  131. .irq_mask = marvel_irq_noop,
  132. .irq_unmask = marvel_irq_noop,
  133. };
  134. static struct irq_chip io7_lsi_irq_type = {
  135. .name = "LSI",
  136. .irq_unmask = io7_enable_irq,
  137. .irq_mask = io7_disable_irq,
  138. .irq_mask_ack = io7_disable_irq,
  139. };
  140. static struct irq_chip io7_msi_irq_type = {
  141. .name = "MSI",
  142. .irq_unmask = io7_enable_irq,
  143. .irq_mask = io7_disable_irq,
  144. .irq_ack = marvel_irq_noop,
  145. };
  146. static void
  147. io7_redirect_irq(struct io7 *io7,
  148. volatile unsigned long *csr,
  149. unsigned int where)
  150. {
  151. unsigned long val;
  152. val = *csr;
  153. val &= ~(0x1ffUL << 24); /* clear the target pid */
  154. val |= ((unsigned long)where << 24); /* set the new target pid */
  155. *csr = val;
  156. mb();
  157. *csr;
  158. }
  159. static void
  160. io7_redirect_one_lsi(struct io7 *io7, unsigned int which, unsigned int where)
  161. {
  162. unsigned long val;
  163. /*
  164. * LSI_CTL has target PID @ 14
  165. */
  166. val = io7->csrs->PO7_LSI_CTL[which].csr;
  167. val &= ~(0x1ffUL << 14); /* clear the target pid */
  168. val |= ((unsigned long)where << 14); /* set the new target pid */
  169. io7->csrs->PO7_LSI_CTL[which].csr = val;
  170. mb();
  171. io7->csrs->PO7_LSI_CTL[which].csr;
  172. }
  173. static void
  174. io7_redirect_one_msi(struct io7 *io7, unsigned int which, unsigned int where)
  175. {
  176. unsigned long val;
  177. /*
  178. * MSI_CTL has target PID @ 14
  179. */
  180. val = io7->csrs->PO7_MSI_CTL[which].csr;
  181. val &= ~(0x1ffUL << 14); /* clear the target pid */
  182. val |= ((unsigned long)where << 14); /* set the new target pid */
  183. io7->csrs->PO7_MSI_CTL[which].csr = val;
  184. mb();
  185. io7->csrs->PO7_MSI_CTL[which].csr;
  186. }
  187. static void __init
  188. init_one_io7_lsi(struct io7 *io7, unsigned int which, unsigned int where)
  189. {
  190. /*
  191. * LSI_CTL has target PID @ 14
  192. */
  193. io7->csrs->PO7_LSI_CTL[which].csr = ((unsigned long)where << 14);
  194. mb();
  195. io7->csrs->PO7_LSI_CTL[which].csr;
  196. }
  197. static void __init
  198. init_one_io7_msi(struct io7 *io7, unsigned int which, unsigned int where)
  199. {
  200. /*
  201. * MSI_CTL has target PID @ 14
  202. */
  203. io7->csrs->PO7_MSI_CTL[which].csr = ((unsigned long)where << 14);
  204. mb();
  205. io7->csrs->PO7_MSI_CTL[which].csr;
  206. }
  207. static void __init
  208. init_io7_irqs(struct io7 *io7,
  209. struct irq_chip *lsi_ops,
  210. struct irq_chip *msi_ops)
  211. {
  212. long base = (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT) + 16;
  213. long i;
  214. printk("Initializing interrupts for IO7 at PE %u - base %lx\n",
  215. io7->pe, base);
  216. /*
  217. * Where should interrupts from this IO7 go?
  218. *
  219. * They really should be sent to the local CPU to avoid having to
  220. * traverse the mesh, but if it's not an SMP kernel, they have to
  221. * go to the boot CPU. Send them all to the boot CPU for now,
  222. * as each secondary starts, it can redirect it's local device
  223. * interrupts.
  224. */
  225. printk(" Interrupts reported to CPU at PE %u\n", boot_cpuid);
  226. spin_lock(&io7->irq_lock);
  227. /* set up the error irqs */
  228. io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, boot_cpuid);
  229. io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, boot_cpuid);
  230. io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, boot_cpuid);
  231. io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, boot_cpuid);
  232. io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, boot_cpuid);
  233. /* Set up the lsi irqs. */
  234. for (i = 0; i < 128; ++i) {
  235. irq_set_chip_and_handler(base + i, lsi_ops, handle_level_irq);
  236. irq_set_status_flags(i, IRQ_LEVEL);
  237. }
  238. /* Disable the implemented irqs in hardware. */
  239. for (i = 0; i < 0x60; ++i)
  240. init_one_io7_lsi(io7, i, boot_cpuid);
  241. init_one_io7_lsi(io7, 0x74, boot_cpuid);
  242. init_one_io7_lsi(io7, 0x75, boot_cpuid);
  243. /* Set up the msi irqs. */
  244. for (i = 128; i < (128 + 512); ++i) {
  245. irq_set_chip_and_handler(base + i, msi_ops, handle_level_irq);
  246. irq_set_status_flags(i, IRQ_LEVEL);
  247. }
  248. for (i = 0; i < 16; ++i)
  249. init_one_io7_msi(io7, i, boot_cpuid);
  250. spin_unlock(&io7->irq_lock);
  251. }
  252. static void __init
  253. marvel_init_irq(void)
  254. {
  255. int i;
  256. struct io7 *io7 = NULL;
  257. /* Reserve the legacy irqs. */
  258. for (i = 0; i < 16; ++i) {
  259. irq_set_chip_and_handler(i, &marvel_legacy_irq_type,
  260. handle_level_irq);
  261. }
  262. /* Init the io7 irqs. */
  263. for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
  264. init_io7_irqs(io7, &io7_lsi_irq_type, &io7_msi_irq_type);
  265. }
  266. static int
  267. marvel_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
  268. {
  269. struct pci_controller *hose = dev->sysdata;
  270. struct io7_port *io7_port = hose->sysdata;
  271. struct io7 *io7 = io7_port->io7;
  272. int msi_loc, msi_data_off;
  273. u16 msg_ctl;
  274. u16 msg_dat;
  275. u8 intline;
  276. int irq;
  277. pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
  278. irq = intline;
  279. msi_loc = pci_find_capability(dev, PCI_CAP_ID_MSI);
  280. msg_ctl = 0;
  281. if (msi_loc)
  282. pci_read_config_word(dev, msi_loc + PCI_MSI_FLAGS, &msg_ctl);
  283. if (msg_ctl & PCI_MSI_FLAGS_ENABLE) {
  284. msi_data_off = PCI_MSI_DATA_32;
  285. if (msg_ctl & PCI_MSI_FLAGS_64BIT)
  286. msi_data_off = PCI_MSI_DATA_64;
  287. pci_read_config_word(dev, msi_loc + msi_data_off, &msg_dat);
  288. irq = msg_dat & 0x1ff; /* we use msg_data<8:0> */
  289. irq += 0x80; /* offset for lsi */
  290. #if 1
  291. printk("PCI:%d:%d:%d (hose %d) is using MSI\n",
  292. dev->bus->number,
  293. PCI_SLOT(dev->devfn),
  294. PCI_FUNC(dev->devfn),
  295. hose->index);
  296. printk(" %d message(s) from 0x%04x\n",
  297. 1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
  298. msg_dat);
  299. printk(" reporting on %d IRQ(s) from %d (0x%x)\n",
  300. 1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
  301. (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT),
  302. (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT));
  303. #endif
  304. #if 0
  305. pci_write_config_word(dev, msi_loc + PCI_MSI_FLAGS,
  306. msg_ctl & ~PCI_MSI_FLAGS_ENABLE);
  307. pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
  308. irq = intline;
  309. printk(" forcing LSI interrupt on irq %d [0x%x]\n", irq, irq);
  310. #endif
  311. }
  312. irq += 16; /* offset for legacy */
  313. irq |= io7->pe << MARVEL_IRQ_VEC_PE_SHIFT; /* merge the pid */
  314. return irq;
  315. }
  316. static void __init
  317. marvel_init_pci(void)
  318. {
  319. struct io7 *io7;
  320. marvel_register_error_handlers();
  321. /* Indicate that we trust the console to configure things properly */
  322. pci_set_flags(PCI_PROBE_ONLY);
  323. common_init_pci();
  324. locate_and_init_vga(NULL);
  325. /* Clear any io7 errors. */
  326. for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
  327. io7_clear_errors(io7);
  328. }
  329. static void __init
  330. marvel_init_rtc(void)
  331. {
  332. init_rtc_irq();
  333. }
  334. struct marvel_rtc_time {
  335. struct rtc_time *time;
  336. int retval;
  337. };
  338. #ifdef CONFIG_SMP
  339. static void
  340. smp_get_rtc_time(void *data)
  341. {
  342. struct marvel_rtc_time *mrt = data;
  343. mrt->retval = __get_rtc_time(mrt->time);
  344. }
  345. static void
  346. smp_set_rtc_time(void *data)
  347. {
  348. struct marvel_rtc_time *mrt = data;
  349. mrt->retval = __set_rtc_time(mrt->time);
  350. }
  351. #endif
  352. static unsigned int
  353. marvel_get_rtc_time(struct rtc_time *time)
  354. {
  355. #ifdef CONFIG_SMP
  356. struct marvel_rtc_time mrt;
  357. if (smp_processor_id() != boot_cpuid) {
  358. mrt.time = time;
  359. smp_call_function_single(boot_cpuid, smp_get_rtc_time, &mrt, 1);
  360. return mrt.retval;
  361. }
  362. #endif
  363. return __get_rtc_time(time);
  364. }
  365. static int
  366. marvel_set_rtc_time(struct rtc_time *time)
  367. {
  368. #ifdef CONFIG_SMP
  369. struct marvel_rtc_time mrt;
  370. if (smp_processor_id() != boot_cpuid) {
  371. mrt.time = time;
  372. smp_call_function_single(boot_cpuid, smp_set_rtc_time, &mrt, 1);
  373. return mrt.retval;
  374. }
  375. #endif
  376. return __set_rtc_time(time);
  377. }
  378. static void
  379. marvel_smp_callin(void)
  380. {
  381. int cpuid = hard_smp_processor_id();
  382. struct io7 *io7 = marvel_find_io7(cpuid);
  383. unsigned int i;
  384. if (!io7)
  385. return;
  386. /*
  387. * There is a local IO7 - redirect all of its interrupts here.
  388. */
  389. printk("Redirecting IO7 interrupts to local CPU at PE %u\n", cpuid);
  390. /* Redirect the error IRQS here. */
  391. io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, cpuid);
  392. io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, cpuid);
  393. io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, cpuid);
  394. io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, cpuid);
  395. io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, cpuid);
  396. /* Redirect the implemented LSIs here. */
  397. for (i = 0; i < 0x60; ++i)
  398. io7_redirect_one_lsi(io7, i, cpuid);
  399. io7_redirect_one_lsi(io7, 0x74, cpuid);
  400. io7_redirect_one_lsi(io7, 0x75, cpuid);
  401. /* Redirect the MSIs here. */
  402. for (i = 0; i < 16; ++i)
  403. io7_redirect_one_msi(io7, i, cpuid);
  404. }
  405. /*
  406. * System Vectors
  407. */
  408. struct alpha_machine_vector marvel_ev7_mv __initmv = {
  409. .vector_name = "MARVEL/EV7",
  410. DO_EV7_MMU,
  411. .rtc_port = 0x70,
  412. .rtc_get_time = marvel_get_rtc_time,
  413. .rtc_set_time = marvel_set_rtc_time,
  414. DO_MARVEL_IO,
  415. .machine_check = marvel_machine_check,
  416. .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
  417. .min_io_address = DEFAULT_IO_BASE,
  418. .min_mem_address = DEFAULT_MEM_BASE,
  419. .pci_dac_offset = IO7_DAC_OFFSET,
  420. .nr_irqs = MARVEL_NR_IRQS,
  421. .device_interrupt = io7_device_interrupt,
  422. .agp_info = marvel_agp_info,
  423. .smp_callin = marvel_smp_callin,
  424. .init_arch = marvel_init_arch,
  425. .init_irq = marvel_init_irq,
  426. .init_rtc = marvel_init_rtc,
  427. .init_pci = marvel_init_pci,
  428. .kill_arch = marvel_kill_arch,
  429. .pci_map_irq = marvel_map_irq,
  430. .pci_swizzle = common_swizzle,
  431. .pa_to_nid = marvel_pa_to_nid,
  432. .cpuid_to_nid = marvel_cpuid_to_nid,
  433. .node_mem_start = marvel_node_mem_start,
  434. .node_mem_size = marvel_node_mem_size,
  435. };
  436. ALIAS_MV(marvel_ev7)