sys_marvel.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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(struct irq_data *d)
  91. {
  92. volatile unsigned long *ctl;
  93. unsigned int irq = d->irq;
  94. struct io7 *io7;
  95. ctl = io7_get_irq_ctl(irq, &io7);
  96. if (!ctl || !io7) {
  97. printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
  98. __func__, irq);
  99. return;
  100. }
  101. spin_lock(&io7->irq_lock);
  102. *ctl |= 1UL << 24;
  103. mb();
  104. *ctl;
  105. spin_unlock(&io7->irq_lock);
  106. }
  107. static void
  108. io7_disable_irq(struct irq_data *d)
  109. {
  110. volatile unsigned long *ctl;
  111. unsigned int irq = d->irq;
  112. struct io7 *io7;
  113. ctl = io7_get_irq_ctl(irq, &io7);
  114. if (!ctl || !io7) {
  115. printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
  116. __func__, irq);
  117. return;
  118. }
  119. spin_lock(&io7->irq_lock);
  120. *ctl &= ~(1UL << 24);
  121. mb();
  122. *ctl;
  123. spin_unlock(&io7->irq_lock);
  124. }
  125. static void
  126. marvel_irq_noop(struct irq_data *d)
  127. {
  128. return;
  129. }
  130. static struct irq_chip marvel_legacy_irq_type = {
  131. .name = "LEGACY",
  132. .irq_mask = marvel_irq_noop,
  133. .irq_unmask = marvel_irq_noop,
  134. };
  135. static struct irq_chip io7_lsi_irq_type = {
  136. .name = "LSI",
  137. .irq_unmask = io7_enable_irq,
  138. .irq_mask = io7_disable_irq,
  139. .irq_mask_ack = io7_disable_irq,
  140. };
  141. static struct irq_chip io7_msi_irq_type = {
  142. .name = "MSI",
  143. .irq_unmask = io7_enable_irq,
  144. .irq_mask = io7_disable_irq,
  145. .irq_ack = marvel_irq_noop,
  146. };
  147. static void
  148. io7_redirect_irq(struct io7 *io7,
  149. volatile unsigned long *csr,
  150. unsigned int where)
  151. {
  152. unsigned long val;
  153. val = *csr;
  154. val &= ~(0x1ffUL << 24); /* clear the target pid */
  155. val |= ((unsigned long)where << 24); /* set the new target pid */
  156. *csr = val;
  157. mb();
  158. *csr;
  159. }
  160. static void
  161. io7_redirect_one_lsi(struct io7 *io7, unsigned int which, unsigned int where)
  162. {
  163. unsigned long val;
  164. /*
  165. * LSI_CTL has target PID @ 14
  166. */
  167. val = io7->csrs->PO7_LSI_CTL[which].csr;
  168. val &= ~(0x1ffUL << 14); /* clear the target pid */
  169. val |= ((unsigned long)where << 14); /* set the new target pid */
  170. io7->csrs->PO7_LSI_CTL[which].csr = val;
  171. mb();
  172. io7->csrs->PO7_LSI_CTL[which].csr;
  173. }
  174. static void
  175. io7_redirect_one_msi(struct io7 *io7, unsigned int which, unsigned int where)
  176. {
  177. unsigned long val;
  178. /*
  179. * MSI_CTL has target PID @ 14
  180. */
  181. val = io7->csrs->PO7_MSI_CTL[which].csr;
  182. val &= ~(0x1ffUL << 14); /* clear the target pid */
  183. val |= ((unsigned long)where << 14); /* set the new target pid */
  184. io7->csrs->PO7_MSI_CTL[which].csr = val;
  185. mb();
  186. io7->csrs->PO7_MSI_CTL[which].csr;
  187. }
  188. static void __init
  189. init_one_io7_lsi(struct io7 *io7, unsigned int which, unsigned int where)
  190. {
  191. /*
  192. * LSI_CTL has target PID @ 14
  193. */
  194. io7->csrs->PO7_LSI_CTL[which].csr = ((unsigned long)where << 14);
  195. mb();
  196. io7->csrs->PO7_LSI_CTL[which].csr;
  197. }
  198. static void __init
  199. init_one_io7_msi(struct io7 *io7, unsigned int which, unsigned int where)
  200. {
  201. /*
  202. * MSI_CTL has target PID @ 14
  203. */
  204. io7->csrs->PO7_MSI_CTL[which].csr = ((unsigned long)where << 14);
  205. mb();
  206. io7->csrs->PO7_MSI_CTL[which].csr;
  207. }
  208. static void __init
  209. init_io7_irqs(struct io7 *io7,
  210. struct irq_chip *lsi_ops,
  211. struct irq_chip *msi_ops)
  212. {
  213. long base = (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT) + 16;
  214. long i;
  215. printk("Initializing interrupts for IO7 at PE %u - base %lx\n",
  216. io7->pe, base);
  217. /*
  218. * Where should interrupts from this IO7 go?
  219. *
  220. * They really should be sent to the local CPU to avoid having to
  221. * traverse the mesh, but if it's not an SMP kernel, they have to
  222. * go to the boot CPU. Send them all to the boot CPU for now,
  223. * as each secondary starts, it can redirect it's local device
  224. * interrupts.
  225. */
  226. printk(" Interrupts reported to CPU at PE %u\n", boot_cpuid);
  227. spin_lock(&io7->irq_lock);
  228. /* set up the error irqs */
  229. io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, boot_cpuid);
  230. io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, boot_cpuid);
  231. io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, boot_cpuid);
  232. io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, boot_cpuid);
  233. io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, boot_cpuid);
  234. /* Set up the lsi irqs. */
  235. for (i = 0; i < 128; ++i) {
  236. irq_set_chip_and_handler(base + i, lsi_ops, handle_level_irq);
  237. irq_set_status_flags(i, IRQ_LEVEL);
  238. }
  239. /* Disable the implemented irqs in hardware. */
  240. for (i = 0; i < 0x60; ++i)
  241. init_one_io7_lsi(io7, i, boot_cpuid);
  242. init_one_io7_lsi(io7, 0x74, boot_cpuid);
  243. init_one_io7_lsi(io7, 0x75, boot_cpuid);
  244. /* Set up the msi irqs. */
  245. for (i = 128; i < (128 + 512); ++i) {
  246. irq_set_chip_and_handler(base + i, msi_ops, handle_level_irq);
  247. irq_set_status_flags(i, IRQ_LEVEL);
  248. }
  249. for (i = 0; i < 16; ++i)
  250. init_one_io7_msi(io7, i, boot_cpuid);
  251. spin_unlock(&io7->irq_lock);
  252. }
  253. static void __init
  254. marvel_init_irq(void)
  255. {
  256. int i;
  257. struct io7 *io7 = NULL;
  258. /* Reserve the legacy irqs. */
  259. for (i = 0; i < 16; ++i) {
  260. irq_set_chip_and_handler(i, &marvel_legacy_irq_type,
  261. handle_level_irq);
  262. }
  263. /* Init the io7 irqs. */
  264. for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
  265. init_io7_irqs(io7, &io7_lsi_irq_type, &io7_msi_irq_type);
  266. }
  267. static int
  268. marvel_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
  269. {
  270. struct pci_controller *hose = dev->sysdata;
  271. struct io7_port *io7_port = hose->sysdata;
  272. struct io7 *io7 = io7_port->io7;
  273. int msi_loc, msi_data_off;
  274. u16 msg_ctl;
  275. u16 msg_dat;
  276. u8 intline;
  277. int irq;
  278. pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
  279. irq = intline;
  280. msi_loc = pci_find_capability(dev, PCI_CAP_ID_MSI);
  281. msg_ctl = 0;
  282. if (msi_loc)
  283. pci_read_config_word(dev, msi_loc + PCI_MSI_FLAGS, &msg_ctl);
  284. if (msg_ctl & PCI_MSI_FLAGS_ENABLE) {
  285. msi_data_off = PCI_MSI_DATA_32;
  286. if (msg_ctl & PCI_MSI_FLAGS_64BIT)
  287. msi_data_off = PCI_MSI_DATA_64;
  288. pci_read_config_word(dev, msi_loc + msi_data_off, &msg_dat);
  289. irq = msg_dat & 0x1ff; /* we use msg_data<8:0> */
  290. irq += 0x80; /* offset for lsi */
  291. #if 1
  292. printk("PCI:%d:%d:%d (hose %d) is using MSI\n",
  293. dev->bus->number,
  294. PCI_SLOT(dev->devfn),
  295. PCI_FUNC(dev->devfn),
  296. hose->index);
  297. printk(" %d message(s) from 0x%04x\n",
  298. 1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
  299. msg_dat);
  300. printk(" reporting on %d IRQ(s) from %d (0x%x)\n",
  301. 1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
  302. (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT),
  303. (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT));
  304. #endif
  305. #if 0
  306. pci_write_config_word(dev, msi_loc + PCI_MSI_FLAGS,
  307. msg_ctl & ~PCI_MSI_FLAGS_ENABLE);
  308. pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
  309. irq = intline;
  310. printk(" forcing LSI interrupt on irq %d [0x%x]\n", irq, irq);
  311. #endif
  312. }
  313. irq += 16; /* offset for legacy */
  314. irq |= io7->pe << MARVEL_IRQ_VEC_PE_SHIFT; /* merge the pid */
  315. return irq;
  316. }
  317. static void __init
  318. marvel_init_pci(void)
  319. {
  320. struct io7 *io7;
  321. marvel_register_error_handlers();
  322. pci_probe_only = 1;
  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)