sys_marvel.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * linux/arch/alpha/kernel/sys_marvel.c
  4. *
  5. * Marvel / IO7 support
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/types.h>
  9. #include <linux/mm.h>
  10. #include <linux/sched.h>
  11. #include <linux/pci.h>
  12. #include <linux/init.h>
  13. #include <linux/bitops.h>
  14. #include <asm/ptrace.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 "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. raw_spin_lock(&io7->irq_lock);
  101. *ctl |= 1UL << 24;
  102. mb();
  103. *ctl;
  104. raw_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. raw_spin_lock(&io7->irq_lock);
  119. *ctl &= ~(1UL << 24);
  120. mb();
  121. *ctl;
  122. raw_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. raw_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. raw_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(const struct pci_dev *cdev, u8 slot, u8 pin)
  268. {
  269. struct pci_dev *dev = (struct pci_dev *)cdev;
  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 = dev->msi_cap;
  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. /* Indicate that we trust the console to configure things properly */
  323. pci_set_flags(PCI_PROBE_ONLY);
  324. common_init_pci();
  325. locate_and_init_vga(NULL);
  326. /* Clear any io7 errors. */
  327. for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
  328. io7_clear_errors(io7);
  329. }
  330. static void __init
  331. marvel_init_rtc(void)
  332. {
  333. init_rtc_irq();
  334. }
  335. static void
  336. marvel_smp_callin(void)
  337. {
  338. int cpuid = hard_smp_processor_id();
  339. struct io7 *io7 = marvel_find_io7(cpuid);
  340. unsigned int i;
  341. if (!io7)
  342. return;
  343. /*
  344. * There is a local IO7 - redirect all of its interrupts here.
  345. */
  346. printk("Redirecting IO7 interrupts to local CPU at PE %u\n", cpuid);
  347. /* Redirect the error IRQS here. */
  348. io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, cpuid);
  349. io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, cpuid);
  350. io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, cpuid);
  351. io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, cpuid);
  352. io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, cpuid);
  353. /* Redirect the implemented LSIs here. */
  354. for (i = 0; i < 0x60; ++i)
  355. io7_redirect_one_lsi(io7, i, cpuid);
  356. io7_redirect_one_lsi(io7, 0x74, cpuid);
  357. io7_redirect_one_lsi(io7, 0x75, cpuid);
  358. /* Redirect the MSIs here. */
  359. for (i = 0; i < 16; ++i)
  360. io7_redirect_one_msi(io7, i, cpuid);
  361. }
  362. /*
  363. * System Vectors
  364. */
  365. struct alpha_machine_vector marvel_ev7_mv __initmv = {
  366. .vector_name = "MARVEL/EV7",
  367. DO_EV7_MMU,
  368. .rtc_port = 0x70,
  369. .rtc_boot_cpu_only = 1,
  370. DO_MARVEL_IO,
  371. .machine_check = marvel_machine_check,
  372. .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
  373. .min_io_address = DEFAULT_IO_BASE,
  374. .min_mem_address = DEFAULT_MEM_BASE,
  375. .pci_dac_offset = IO7_DAC_OFFSET,
  376. .nr_irqs = MARVEL_NR_IRQS,
  377. .device_interrupt = io7_device_interrupt,
  378. .agp_info = marvel_agp_info,
  379. .smp_callin = marvel_smp_callin,
  380. .init_arch = marvel_init_arch,
  381. .init_irq = marvel_init_irq,
  382. .init_rtc = marvel_init_rtc,
  383. .init_pci = marvel_init_pci,
  384. .kill_arch = marvel_kill_arch,
  385. .pci_map_irq = marvel_map_irq,
  386. .pci_swizzle = common_swizzle,
  387. .pa_to_nid = marvel_pa_to_nid,
  388. .cpuid_to_nid = marvel_cpuid_to_nid,
  389. .node_mem_start = marvel_node_mem_start,
  390. .node_mem_size = marvel_node_mem_size,
  391. };
  392. ALIAS_MV(marvel_ev7)