sys_marvel.c 12 KB

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