cpcht.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. /*-
  2. * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  3. *
  4. * Copyright (C) 2008-2010 Nathan Whitehorn
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  20. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  21. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  22. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  23. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  24. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  25. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <sys/cdefs.h>
  28. __FBSDID("$FreeBSD$");
  29. #include <sys/param.h>
  30. #include <sys/systm.h>
  31. #include <sys/module.h>
  32. #include <sys/bus.h>
  33. #include <sys/conf.h>
  34. #include <sys/kernel.h>
  35. #include <sys/lock.h>
  36. #include <sys/mutex.h>
  37. #include <sys/pciio.h>
  38. #include <sys/rman.h>
  39. #include <dev/ofw/openfirm.h>
  40. #include <dev/ofw/ofw_pci.h>
  41. #include <dev/pci/pcivar.h>
  42. #include <dev/pci/pcireg.h>
  43. #include <machine/bus.h>
  44. #include <machine/intr_machdep.h>
  45. #include <machine/md_var.h>
  46. #include <machine/openpicreg.h>
  47. #include <machine/openpicvar.h>
  48. #include <machine/pio.h>
  49. #include <machine/resource.h>
  50. #include <dev/ofw/ofw_bus.h>
  51. #include <dev/ofw/ofw_bus_subr.h>
  52. #include <dev/ofw/ofwpci.h>
  53. #include <vm/vm.h>
  54. #include <vm/pmap.h>
  55. #include "pcib_if.h"
  56. #include <dev/pci/pcib_private.h>
  57. #include "pic_if.h"
  58. /*
  59. * IBM CPC9X5 Hypertransport Device interface.
  60. */
  61. static int cpcht_probe(device_t);
  62. static int cpcht_attach(device_t);
  63. static void cpcht_configure_htbridge(device_t, phandle_t);
  64. /*
  65. * pcib interface.
  66. */
  67. static u_int32_t cpcht_read_config(device_t, u_int, u_int, u_int,
  68. u_int, int);
  69. static void cpcht_write_config(device_t, u_int, u_int, u_int,
  70. u_int, u_int32_t, int);
  71. static int cpcht_route_interrupt(device_t, device_t, int);
  72. static int cpcht_alloc_msi(device_t dev, device_t child,
  73. int count, int maxcount, int *irqs);
  74. static int cpcht_release_msi(device_t dev, device_t child,
  75. int count, int *irqs);
  76. static int cpcht_alloc_msix(device_t dev, device_t child,
  77. int *irq);
  78. static int cpcht_release_msix(device_t dev, device_t child,
  79. int irq);
  80. static int cpcht_map_msi(device_t dev, device_t child,
  81. int irq, uint64_t *addr, uint32_t *data);
  82. /*
  83. * Driver methods.
  84. */
  85. static device_method_t cpcht_methods[] = {
  86. /* Device interface */
  87. DEVMETHOD(device_probe, cpcht_probe),
  88. DEVMETHOD(device_attach, cpcht_attach),
  89. /* pcib interface */
  90. DEVMETHOD(pcib_read_config, cpcht_read_config),
  91. DEVMETHOD(pcib_write_config, cpcht_write_config),
  92. DEVMETHOD(pcib_route_interrupt, cpcht_route_interrupt),
  93. DEVMETHOD(pcib_alloc_msi, cpcht_alloc_msi),
  94. DEVMETHOD(pcib_release_msi, cpcht_release_msi),
  95. DEVMETHOD(pcib_alloc_msix, cpcht_alloc_msix),
  96. DEVMETHOD(pcib_release_msix, cpcht_release_msix),
  97. DEVMETHOD(pcib_map_msi, cpcht_map_msi),
  98. DEVMETHOD(pcib_request_feature, pcib_request_feature_allow),
  99. DEVMETHOD_END
  100. };
  101. struct cpcht_irq {
  102. enum {
  103. IRQ_NONE, IRQ_HT, IRQ_MSI, IRQ_INTERNAL
  104. } irq_type;
  105. int ht_source;
  106. vm_offset_t ht_base;
  107. vm_offset_t apple_eoi;
  108. uint32_t eoi_data;
  109. int edge;
  110. };
  111. static struct cpcht_irq *cpcht_irqmap = NULL;
  112. uint32_t cpcht_msipic = 0;
  113. struct cpcht_softc {
  114. struct ofw_pci_softc pci_sc;
  115. vm_offset_t sc_data;
  116. uint64_t sc_populated_slots;
  117. struct cpcht_irq htirq_map[128];
  118. struct mtx htirq_mtx;
  119. };
  120. static devclass_t cpcht_devclass;
  121. DEFINE_CLASS_1(pcib, cpcht_driver, cpcht_methods, sizeof(struct cpcht_softc),
  122. ofw_pci_driver);
  123. EARLY_DRIVER_MODULE(cpcht, ofwbus, cpcht_driver, cpcht_devclass, 0, 0,
  124. BUS_PASS_BUS);
  125. #define CPCHT_IOPORT_BASE 0xf4000000UL /* Hardwired */
  126. #define CPCHT_IOPORT_SIZE 0x00400000UL
  127. #define HTAPIC_REQUEST_EOI 0x20
  128. #define HTAPIC_TRIGGER_LEVEL 0x02
  129. #define HTAPIC_MASK 0x01
  130. static int
  131. cpcht_probe(device_t dev)
  132. {
  133. const char *type, *compatible;
  134. type = ofw_bus_get_type(dev);
  135. compatible = ofw_bus_get_compat(dev);
  136. if (type == NULL || compatible == NULL)
  137. return (ENXIO);
  138. if (strcmp(type, "ht") != 0)
  139. return (ENXIO);
  140. if (strcmp(compatible, "u3-ht") != 0)
  141. return (ENXIO);
  142. device_set_desc(dev, "IBM CPC9X5 HyperTransport Tunnel");
  143. return (0);
  144. }
  145. static int
  146. cpcht_attach(device_t dev)
  147. {
  148. struct cpcht_softc *sc;
  149. phandle_t node, child;
  150. u_int32_t reg[3];
  151. int i;
  152. node = ofw_bus_get_node(dev);
  153. sc = device_get_softc(dev);
  154. if (OF_getencprop(node, "reg", reg, sizeof(reg)) < 12)
  155. return (ENXIO);
  156. if (OF_getproplen(node, "ranges") <= 0)
  157. sc->pci_sc.sc_quirks = OFW_PCI_QUIRK_RANGES_ON_CHILDREN;
  158. sc->sc_populated_slots = 0;
  159. sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1], reg[2]);
  160. /*
  161. * Set up the resource manager and the HT->MPIC mapping. For cpcht,
  162. * the ranges are properties of the child bridges, and this is also
  163. * where we get the HT interrupts properties.
  164. */
  165. #if 0
  166. /* I/O port mappings are usually not in the device tree */
  167. rman_manage_region(&sc->pci_sc.sc_io_rman, 0, CPCHT_IOPORT_SIZE - 1);
  168. #endif
  169. bzero(sc->htirq_map, sizeof(sc->htirq_map));
  170. mtx_init(&sc->htirq_mtx, "cpcht irq", NULL, MTX_DEF);
  171. for (i = 0; i < 8; i++)
  172. sc->htirq_map[i].irq_type = IRQ_INTERNAL;
  173. for (child = OF_child(node); child != 0; child = OF_peer(child))
  174. cpcht_configure_htbridge(dev, child);
  175. /* Now make the mapping table available to the MPIC */
  176. cpcht_irqmap = sc->htirq_map;
  177. return (ofw_pci_attach(dev));
  178. }
  179. static void
  180. cpcht_configure_htbridge(device_t dev, phandle_t child)
  181. {
  182. struct cpcht_softc *sc;
  183. struct ofw_pci_register pcir;
  184. int ptr, nextptr;
  185. uint32_t vend, val;
  186. int i, nirq, irq;
  187. u_int b, f, s;
  188. sc = device_get_softc(dev);
  189. if (OF_getencprop(child, "reg", (pcell_t *)&pcir, sizeof(pcir)) == -1)
  190. return;
  191. b = OFW_PCI_PHYS_HI_BUS(pcir.phys_hi);
  192. s = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
  193. f = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
  194. /*
  195. * Mark this slot is populated. The remote south bridge does
  196. * not like us talking to unpopulated slots on the root bus.
  197. */
  198. sc->sc_populated_slots |= (1 << s);
  199. /*
  200. * Next build up any HT->MPIC mappings for this sub-bus. One would
  201. * naively hope that enabling, disabling, and EOIing interrupts would
  202. * cause the appropriate HT bus transactions to that effect. This is
  203. * not the case.
  204. *
  205. * Instead, we have to muck about on the HT peer's root PCI bridges,
  206. * figure out what interrupts they send, enable them, and cache
  207. * the location of their WaitForEOI registers so that we can
  208. * send EOIs later.
  209. */
  210. /* All the devices we are interested in have caps */
  211. if (!(PCIB_READ_CONFIG(dev, b, s, f, PCIR_STATUS, 2)
  212. & PCIM_STATUS_CAPPRESENT))
  213. return;
  214. nextptr = PCIB_READ_CONFIG(dev, b, s, f, PCIR_CAP_PTR, 1);
  215. while (nextptr != 0) {
  216. ptr = nextptr;
  217. nextptr = PCIB_READ_CONFIG(dev, b, s, f,
  218. ptr + PCICAP_NEXTPTR, 1);
  219. /* Find the HT IRQ capabilities */
  220. if (PCIB_READ_CONFIG(dev, b, s, f,
  221. ptr + PCICAP_ID, 1) != PCIY_HT)
  222. continue;
  223. val = PCIB_READ_CONFIG(dev, b, s, f, ptr + PCIR_HT_COMMAND, 2);
  224. if ((val & PCIM_HTCMD_CAP_MASK) != PCIM_HTCAP_INTERRUPT)
  225. continue;
  226. /* Ask for the IRQ count */
  227. PCIB_WRITE_CONFIG(dev, b, s, f, ptr + PCIR_HT_COMMAND, 0x1, 1);
  228. nirq = PCIB_READ_CONFIG(dev, b, s, f, ptr + 4, 4);
  229. nirq = ((nirq >> 16) & 0xff) + 1;
  230. device_printf(dev, "%d HT IRQs on device %d.%d\n", nirq, s, f);
  231. for (i = 0; i < nirq; i++) {
  232. PCIB_WRITE_CONFIG(dev, b, s, f,
  233. ptr + PCIR_HT_COMMAND, 0x10 + (i << 1), 1);
  234. irq = PCIB_READ_CONFIG(dev, b, s, f, ptr + 4, 4);
  235. /*
  236. * Mask this interrupt for now.
  237. */
  238. PCIB_WRITE_CONFIG(dev, b, s, f, ptr + 4,
  239. irq | HTAPIC_MASK, 4);
  240. irq = (irq >> 16) & 0xff;
  241. sc->htirq_map[irq].irq_type = IRQ_HT;
  242. sc->htirq_map[irq].ht_source = i;
  243. sc->htirq_map[irq].ht_base = sc->sc_data +
  244. (((((s & 0x1f) << 3) | (f & 0x07)) << 8) | (ptr));
  245. PCIB_WRITE_CONFIG(dev, b, s, f,
  246. ptr + PCIR_HT_COMMAND, 0x11 + (i << 1), 1);
  247. sc->htirq_map[irq].eoi_data =
  248. PCIB_READ_CONFIG(dev, b, s, f, ptr + 4, 4) |
  249. 0x80000000;
  250. /*
  251. * Apple uses a non-compliant IO/APIC that differs
  252. * in how we signal EOIs. Check if this device was
  253. * made by Apple, and act accordingly.
  254. */
  255. vend = PCIB_READ_CONFIG(dev, b, s, f,
  256. PCIR_DEVVENDOR, 4);
  257. if ((vend & 0xffff) == 0x106b)
  258. sc->htirq_map[irq].apple_eoi =
  259. (sc->htirq_map[irq].ht_base - ptr) + 0x60;
  260. }
  261. }
  262. }
  263. static u_int32_t
  264. cpcht_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
  265. int width)
  266. {
  267. struct cpcht_softc *sc;
  268. vm_offset_t caoff;
  269. sc = device_get_softc(dev);
  270. caoff = sc->sc_data +
  271. (((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
  272. if (bus == 0 && (!(sc->sc_populated_slots & (1 << slot)) || func > 0))
  273. return (0xffffffff);
  274. if (bus > 0)
  275. caoff += 0x01000000UL + (bus << 16);
  276. switch (width) {
  277. case 1:
  278. return (in8rb(caoff));
  279. break;
  280. case 2:
  281. return (in16rb(caoff));
  282. break;
  283. case 4:
  284. return (in32rb(caoff));
  285. break;
  286. }
  287. return (0xffffffff);
  288. }
  289. static void
  290. cpcht_write_config(device_t dev, u_int bus, u_int slot, u_int func,
  291. u_int reg, u_int32_t val, int width)
  292. {
  293. struct cpcht_softc *sc;
  294. vm_offset_t caoff;
  295. sc = device_get_softc(dev);
  296. caoff = sc->sc_data +
  297. (((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
  298. if (bus == 0 && (!(sc->sc_populated_slots & (1 << slot)) || func > 0))
  299. return;
  300. if (bus > 0)
  301. caoff += 0x01000000UL + (bus << 16);
  302. switch (width) {
  303. case 1:
  304. out8rb(caoff, val);
  305. break;
  306. case 2:
  307. out16rb(caoff, val);
  308. break;
  309. case 4:
  310. out32rb(caoff, val);
  311. break;
  312. }
  313. }
  314. static int
  315. cpcht_route_interrupt(device_t bus, device_t dev, int pin)
  316. {
  317. return (pin);
  318. }
  319. static int
  320. cpcht_alloc_msi(device_t dev, device_t child, int count, int maxcount,
  321. int *irqs)
  322. {
  323. struct cpcht_softc *sc;
  324. int i, j;
  325. sc = device_get_softc(dev);
  326. j = 0;
  327. /* Bail if no MSI PIC yet */
  328. if (cpcht_msipic == 0)
  329. return (ENXIO);
  330. mtx_lock(&sc->htirq_mtx);
  331. for (i = 8; i < 124 - count; i++) {
  332. for (j = 0; j < count; j++) {
  333. if (sc->htirq_map[i+j].irq_type != IRQ_NONE)
  334. break;
  335. }
  336. if (j == count)
  337. break;
  338. i += j; /* We know there isn't a large enough run */
  339. }
  340. if (j != count) {
  341. mtx_unlock(&sc->htirq_mtx);
  342. return (ENXIO);
  343. }
  344. for (j = 0; j < count; j++) {
  345. irqs[j] = MAP_IRQ(cpcht_msipic, i+j);
  346. sc->htirq_map[i+j].irq_type = IRQ_MSI;
  347. }
  348. mtx_unlock(&sc->htirq_mtx);
  349. return (0);
  350. }
  351. static int
  352. cpcht_release_msi(device_t dev, device_t child, int count, int *irqs)
  353. {
  354. struct cpcht_softc *sc;
  355. int i;
  356. sc = device_get_softc(dev);
  357. mtx_lock(&sc->htirq_mtx);
  358. for (i = 0; i < count; i++)
  359. sc->htirq_map[irqs[i] & 0xff].irq_type = IRQ_NONE;
  360. mtx_unlock(&sc->htirq_mtx);
  361. return (0);
  362. }
  363. static int
  364. cpcht_alloc_msix(device_t dev, device_t child, int *irq)
  365. {
  366. struct cpcht_softc *sc;
  367. int i;
  368. sc = device_get_softc(dev);
  369. /* Bail if no MSI PIC yet */
  370. if (cpcht_msipic == 0)
  371. return (ENXIO);
  372. mtx_lock(&sc->htirq_mtx);
  373. for (i = 8; i < 124; i++) {
  374. if (sc->htirq_map[i].irq_type == IRQ_NONE) {
  375. sc->htirq_map[i].irq_type = IRQ_MSI;
  376. *irq = MAP_IRQ(cpcht_msipic, i);
  377. mtx_unlock(&sc->htirq_mtx);
  378. return (0);
  379. }
  380. }
  381. mtx_unlock(&sc->htirq_mtx);
  382. return (ENXIO);
  383. }
  384. static int
  385. cpcht_release_msix(device_t dev, device_t child, int irq)
  386. {
  387. struct cpcht_softc *sc;
  388. sc = device_get_softc(dev);
  389. mtx_lock(&sc->htirq_mtx);
  390. sc->htirq_map[irq & 0xff].irq_type = IRQ_NONE;
  391. mtx_unlock(&sc->htirq_mtx);
  392. return (0);
  393. }
  394. static int
  395. cpcht_map_msi(device_t dev, device_t child, int irq, uint64_t *addr,
  396. uint32_t *data)
  397. {
  398. device_t pcib;
  399. struct pci_devinfo *dinfo;
  400. struct pcicfg_ht *ht = NULL;
  401. for (pcib = child; pcib != dev; pcib =
  402. device_get_parent(device_get_parent(pcib))) {
  403. dinfo = device_get_ivars(pcib);
  404. ht = &dinfo->cfg.ht;
  405. if (ht == NULL)
  406. continue;
  407. }
  408. if (ht == NULL)
  409. return (ENXIO);
  410. *addr = ht->ht_msiaddr;
  411. *data = irq & 0xff;
  412. return (0);
  413. }
  414. /*
  415. * Driver for the integrated MPIC on U3/U4 (CPC925/CPC945)
  416. */
  417. static int openpic_cpcht_probe(device_t);
  418. static int openpic_cpcht_attach(device_t);
  419. static void openpic_cpcht_config(device_t, u_int irq,
  420. enum intr_trigger trig, enum intr_polarity pol);
  421. static void openpic_cpcht_enable(device_t, u_int irq, u_int vector,
  422. void **priv);
  423. static void openpic_cpcht_unmask(device_t, u_int irq, void *priv);
  424. static void openpic_cpcht_eoi(device_t, u_int irq, void *priv);
  425. static device_method_t openpic_cpcht_methods[] = {
  426. /* Device interface */
  427. DEVMETHOD(device_probe, openpic_cpcht_probe),
  428. DEVMETHOD(device_attach, openpic_cpcht_attach),
  429. /* PIC interface */
  430. DEVMETHOD(pic_bind, openpic_bind),
  431. DEVMETHOD(pic_config, openpic_cpcht_config),
  432. DEVMETHOD(pic_dispatch, openpic_dispatch),
  433. DEVMETHOD(pic_enable, openpic_cpcht_enable),
  434. DEVMETHOD(pic_eoi, openpic_cpcht_eoi),
  435. DEVMETHOD(pic_ipi, openpic_ipi),
  436. DEVMETHOD(pic_mask, openpic_mask),
  437. DEVMETHOD(pic_unmask, openpic_cpcht_unmask),
  438. { 0, 0 },
  439. };
  440. struct openpic_cpcht_softc {
  441. struct openpic_softc sc_openpic;
  442. struct mtx sc_ht_mtx;
  443. };
  444. static driver_t openpic_cpcht_driver = {
  445. "htpic",
  446. openpic_cpcht_methods,
  447. sizeof(struct openpic_cpcht_softc),
  448. };
  449. EARLY_DRIVER_MODULE(openpic, unin, openpic_cpcht_driver, openpic_devclass,
  450. 0, 0, BUS_PASS_INTERRUPT);
  451. static int
  452. openpic_cpcht_probe(device_t dev)
  453. {
  454. const char *type = ofw_bus_get_type(dev);
  455. if (strcmp(type, "open-pic") != 0)
  456. return (ENXIO);
  457. device_set_desc(dev, OPENPIC_DEVSTR);
  458. return (0);
  459. }
  460. static int
  461. openpic_cpcht_attach(device_t dev)
  462. {
  463. struct openpic_cpcht_softc *sc;
  464. phandle_t node;
  465. int err, irq;
  466. node = ofw_bus_get_node(dev);
  467. err = openpic_common_attach(dev, node);
  468. if (err != 0)
  469. return (err);
  470. /*
  471. * The HT APIC stuff is not thread-safe, so we need a mutex to
  472. * protect it.
  473. */
  474. sc = device_get_softc(dev);
  475. mtx_init(&sc->sc_ht_mtx, "htpic", NULL, MTX_SPIN);
  476. /*
  477. * Interrupts 0-3 are internally sourced and are level triggered
  478. * active low. Interrupts 4-123 are connected to a pulse generator
  479. * and should be programmed as edge triggered low-to-high.
  480. *
  481. * IBM CPC945 Manual, Section 9.3.
  482. */
  483. for (irq = 0; irq < 4; irq++)
  484. openpic_config(dev, irq, INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
  485. for (irq = 4; irq < 124; irq++)
  486. openpic_config(dev, irq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
  487. /*
  488. * Use this PIC for MSI only if it is the root PIC. This may not
  489. * be necessary, but Linux does it, and I cannot find any U3 machines
  490. * with MSI devices to test.
  491. */
  492. if (dev == root_pic)
  493. cpcht_msipic = node;
  494. return (0);
  495. }
  496. static void
  497. openpic_cpcht_config(device_t dev, u_int irq, enum intr_trigger trig,
  498. enum intr_polarity pol)
  499. {
  500. struct openpic_cpcht_softc *sc;
  501. uint32_t ht_irq;
  502. /*
  503. * The interrupt settings for the MPIC are completely determined
  504. * by the internal wiring in the northbridge. Real changes to these
  505. * settings need to be negotiated with the remote IO-APIC on the HT
  506. * link.
  507. */
  508. sc = device_get_softc(dev);
  509. if (cpcht_irqmap != NULL && irq < 128 &&
  510. cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) {
  511. mtx_lock_spin(&sc->sc_ht_mtx);
  512. /* Program the data port */
  513. out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
  514. 0x10 + (cpcht_irqmap[irq].ht_source << 1));
  515. /* Grab the IRQ config register */
  516. ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
  517. /* Mask the IRQ while we fiddle settings */
  518. out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq | HTAPIC_MASK);
  519. /* Program the interrupt sense */
  520. ht_irq &= ~(HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI);
  521. if (trig == INTR_TRIGGER_EDGE) {
  522. cpcht_irqmap[irq].edge = 1;
  523. } else {
  524. cpcht_irqmap[irq].edge = 0;
  525. ht_irq |= HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI;
  526. }
  527. out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
  528. mtx_unlock_spin(&sc->sc_ht_mtx);
  529. }
  530. }
  531. static void
  532. openpic_cpcht_enable(device_t dev, u_int irq, u_int vec, void **priv)
  533. {
  534. struct openpic_cpcht_softc *sc;
  535. uint32_t ht_irq;
  536. openpic_enable(dev, irq, vec, priv);
  537. sc = device_get_softc(dev);
  538. if (cpcht_irqmap != NULL && irq < 128 &&
  539. cpcht_irqmap[irq].ht_base > 0) {
  540. mtx_lock_spin(&sc->sc_ht_mtx);
  541. /* Program the data port */
  542. out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
  543. 0x10 + (cpcht_irqmap[irq].ht_source << 1));
  544. /* Unmask the interrupt */
  545. ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
  546. ht_irq &= ~HTAPIC_MASK;
  547. out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
  548. mtx_unlock_spin(&sc->sc_ht_mtx);
  549. }
  550. openpic_cpcht_eoi(dev, irq, *priv);
  551. }
  552. static void
  553. openpic_cpcht_unmask(device_t dev, u_int irq, void *priv)
  554. {
  555. struct openpic_cpcht_softc *sc;
  556. uint32_t ht_irq;
  557. openpic_unmask(dev, irq, priv);
  558. sc = device_get_softc(dev);
  559. if (cpcht_irqmap != NULL && irq < 128 &&
  560. cpcht_irqmap[irq].ht_base > 0) {
  561. mtx_lock_spin(&sc->sc_ht_mtx);
  562. /* Program the data port */
  563. out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
  564. 0x10 + (cpcht_irqmap[irq].ht_source << 1));
  565. /* Unmask the interrupt */
  566. ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
  567. ht_irq &= ~HTAPIC_MASK;
  568. out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
  569. mtx_unlock_spin(&sc->sc_ht_mtx);
  570. }
  571. openpic_cpcht_eoi(dev, irq, priv);
  572. }
  573. static void
  574. openpic_cpcht_eoi(device_t dev, u_int irq, void *priv)
  575. {
  576. struct openpic_cpcht_softc *sc;
  577. uint32_t off, mask;
  578. if (irq == 255)
  579. return;
  580. sc = device_get_softc(dev);
  581. if (cpcht_irqmap != NULL && irq < 128 &&
  582. cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) {
  583. /* If this is an HT IRQ, acknowledge it at the remote APIC */
  584. if (cpcht_irqmap[irq].apple_eoi) {
  585. off = (cpcht_irqmap[irq].ht_source >> 3) & ~3;
  586. mask = 1 << (cpcht_irqmap[irq].ht_source & 0x1f);
  587. out32rb(cpcht_irqmap[irq].apple_eoi + off, mask);
  588. } else {
  589. mtx_lock_spin(&sc->sc_ht_mtx);
  590. out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
  591. 0x11 + (cpcht_irqmap[irq].ht_source << 1));
  592. out32rb(cpcht_irqmap[irq].ht_base + 4,
  593. cpcht_irqmap[irq].eoi_data);
  594. mtx_unlock_spin(&sc->sc_ht_mtx);
  595. }
  596. }
  597. openpic_eoi(dev, irq, priv);
  598. }