1 /* $OpenBSD: pci_machdep.c,v 1.7 2016/07/04 09:30:18 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2013 Martin Pieuchot 5 * Copyright (c) 1997 Per Fogelstrom 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 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 32 #include <machine/bus.h> 33 #include <machine/autoconf.h> 34 35 #include <dev/pci/pcireg.h> 36 #include <dev/pci/pcivar.h> 37 38 #include <dev/ofw/openfirm.h> 39 #include <dev/ofw/ofw_pci.h> 40 41 42 struct powerpc_bus_dma_tag pci_bus_dma_tag = { 43 NULL, 44 _dmamap_create, 45 _dmamap_destroy, 46 _dmamap_load, 47 _dmamap_load_mbuf, 48 _dmamap_load_uio, 49 _dmamap_load_raw, 50 _dmamap_unload, 51 _dmamap_sync, 52 _dmamem_alloc, 53 _dmamem_alloc_range, 54 _dmamem_free, 55 _dmamem_map, 56 _dmamem_unmap, 57 _dmamem_mmap 58 }; 59 60 void 61 pci_attach_hook(struct device *parent, struct device *self, 62 struct pcibus_attach_args *pba) 63 { 64 } 65 66 int 67 pci_bus_maxdevs(pci_chipset_tag_t pc, int busno) 68 { 69 return (32); 70 } 71 72 pcitag_t 73 pci_make_tag(pci_chipset_tag_t pc, int b, int d, int f) 74 { 75 struct ofw_pci_register reg; 76 pcitag_t tag; 77 int node, busrange[2]; 78 79 if (pc->busnode[b]) 80 return PCITAG_CREATE(0, b, d, f); 81 82 node = pc->pc_node; 83 84 /* 85 * Because ht(4) controller nodes do not have a "bus-range" 86 * property, we need to start iterating from one of their 87 * PCI bridge nodes to be able to find our devices. 88 */ 89 if (OF_getprop(node, "bus-range", &busrange, sizeof(busrange)) < 0) 90 node = OF_child(pc->pc_node); 91 92 for (; node; node = OF_peer(node)) { 93 /* 94 * Check for PCI-PCI bridges. If the device we want is 95 * in the bus-range for that bridge, work our way down. 96 */ 97 while ((OF_getprop(node, "bus-range", &busrange, 98 sizeof(busrange)) == sizeof(busrange)) && 99 (b >= busrange[0] && b <= busrange[1])) { 100 node = OF_child(node); 101 } 102 103 if (OF_getprop(node, "reg", ®, sizeof(reg)) < sizeof(reg)) 104 continue; 105 106 if (b != OFW_PCI_PHYS_HI_BUS(reg.phys_hi)) 107 continue; 108 if (d != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi)) 109 continue; 110 if (f != OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi)) 111 continue; 112 113 tag = PCITAG_CREATE(node, b, d, f); 114 115 return (tag); 116 } 117 118 return (PCITAG_CREATE(-1, b, d, f)); 119 } 120 121 void 122 pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *b, int *d, int *f) 123 { 124 if (b != NULL) 125 *b = PCITAG_BUS(tag); 126 if (d != NULL) 127 *d = PCITAG_DEV(tag); 128 if (f != NULL) 129 *f = PCITAG_FUN(tag); 130 } 131 132 int 133 pci_conf_size(pci_chipset_tag_t pc, pcitag_t tag) 134 { 135 return (PCI_CONFIG_SPACE_SIZE); 136 } 137 138 pcireg_t 139 pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) 140 { 141 if (PCITAG_NODE(tag) != -1) 142 return (*(pc)->pc_conf_read)(pc->pc_conf_v, tag, reg); 143 144 return ((pcireg_t)~0); 145 } 146 147 void 148 pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) 149 { 150 if (PCITAG_NODE(tag) != -1) 151 (*(pc)->pc_conf_write)(pc->pc_conf_v, tag, reg, data); 152 } 153 154 int 155 pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 156 { 157 struct ofw_pci_register reg; 158 int node = PCITAG_NODE(pa->pa_tag); 159 int intr[4], len; 160 161 if (OF_getprop(node, "reg", ®, sizeof(reg)) < sizeof(reg)) 162 return (ENODEV); 163 164 /* Try to get the old Apple OFW interrupt property first. */ 165 len = OF_getprop(node, "AAPL,interrupts", &intr, sizeof(intr)); 166 if (len == sizeof(intr[0])) 167 goto found; 168 169 len = OF_getprop(node, "interrupts", intr, sizeof(intr)); 170 if (len < sizeof(intr[0])) 171 return (ENODEV); 172 173 reg.size_hi = intr[0]; 174 if (ofw_intr_map(OF_parent(node), (uint32_t *)®, intr)) { 175 /* 176 * This can fail on some machines where the parent's 177 * node doesn't have any "interrupt-map" and friends. 178 * 179 * In this case just trust what we got in "interrupts". 180 */ 181 } 182 183 found: 184 *ihp = intr[0]; 185 186 return (0); 187 } 188 189 int 190 pci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 191 { 192 return (-1); 193 } 194 195 int 196 pci_intr_line(pci_chipset_tag_t pc, pci_intr_handle_t ih) 197 { 198 return (ih); 199 } 200 201 const char * 202 pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih) 203 { 204 static char str[16]; 205 206 snprintf(str, sizeof(str), "irq %ld", ih); 207 208 return (str); 209 } 210 211 void * 212 pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int lvl, 213 int (*func)(void *), void *arg, const char *what) 214 { 215 return (*intr_establish_func)(pc, ih, IST_LEVEL, lvl, func, arg, what); 216 } 217 218 void 219 pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie) 220 { 221 (*intr_disestablish_func)(pc, cookie); 222 } 223 224 int 225 pci_ether_hw_addr(pci_chipset_tag_t pc, uint8_t *oaddr) 226 { 227 uint8_t laddr[6]; 228 int node, len; 229 230 node = OF_finddevice("enet"); 231 len = OF_getprop(node, "local-mac-address", laddr, sizeof(laddr)); 232 if (sizeof(laddr) == len) { 233 memcpy(oaddr, laddr, sizeof(laddr)); 234 return (1); 235 } 236 237 oaddr[0] = oaddr[1] = oaddr[2] = 0xff; 238 oaddr[3] = oaddr[4] = oaddr[5] = 0xff; 239 240 return (0); 241 } 242 243 int 244 ofw_enumerate_pcibus(struct pci_softc *sc, 245 int (*match)(struct pci_attach_args *), struct pci_attach_args *pap) 246 { 247 pci_chipset_tag_t pc = sc->sc_pc; 248 struct ofw_pci_register reg; 249 int len, node, b, d, f, ret; 250 uint32_t val = 0; 251 char compat[32]; 252 pcireg_t bhlcr; 253 pcitag_t tag; 254 255 if (sc->sc_bridgetag) 256 node = PCITAG_NODE(*sc->sc_bridgetag); 257 else 258 node = pc->pc_node; 259 260 /* The AGP bridge is not in the device-tree. */ 261 len = OF_getprop(node, "compatible", compat, sizeof(compat)); 262 if (len > 0 && strcmp(compat, "u3-agp") == 0) { 263 tag = PCITAG_CREATE(0, sc->sc_bus, 11, 0); 264 ret = pci_probe_device(sc, tag, match, pap); 265 if (match != NULL && ret != 0) 266 return (ret); 267 } 268 269 /* 270 * An HT-PCI bridge is needed for interrupt mapping, attach it first 271 */ 272 if (len > 0 && strcmp(compat, "u3-ht") == 0) { 273 int snode; 274 275 for (snode = OF_child(node); snode; snode = OF_peer(snode)) { 276 val = 0; 277 if ((OF_getprop(snode, "shasta-interrupt-sequencer", 278 &val, sizeof(val)) < sizeof(val)) || val != 1) 279 continue; 280 281 if (OF_getprop(snode, "reg", ®, sizeof(reg)) 282 < sizeof(reg)) 283 continue; 284 285 b = OFW_PCI_PHYS_HI_BUS(reg.phys_hi); 286 d = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi); 287 f = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi); 288 289 tag = PCITAG_CREATE(snode, b, d, f); 290 291 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); 292 if (PCI_HDRTYPE_TYPE(bhlcr) > 2) 293 continue; 294 295 ret = pci_probe_device(sc, tag, match, pap); 296 if (match != NULL && ret != 0) 297 return (ret); 298 } 299 } 300 301 for (node = OF_child(node); node; node = OF_peer(node)) { 302 if (OF_getprop(node, "reg", ®, sizeof(reg)) < sizeof(reg)) 303 continue; 304 305 /* 306 * Skip HT-PCI bridge, it has been attached before. 307 */ 308 val = 0; 309 if ((OF_getprop(node, "shasta-interrupt-sequencer", &val, 310 sizeof(val)) >= sizeof(val)) && val == 1) 311 continue; 312 313 b = OFW_PCI_PHYS_HI_BUS(reg.phys_hi); 314 d = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi); 315 f = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi); 316 317 tag = PCITAG_CREATE(node, b, d, f); 318 319 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); 320 if (PCI_HDRTYPE_TYPE(bhlcr) > 2) 321 continue; 322 323 ret = pci_probe_device(sc, tag, match, pap); 324 if (match != NULL && ret != 0) 325 return (ret); 326 } 327 328 return (0); 329 } 330 331 int 332 ofw_intr_map(int node, uint32_t *addr, uint32_t *intr) 333 { 334 uint32_t imap[144], mmask[8], *mp, *mp1; 335 uint32_t acells, icells, mcells; 336 int ilen, mlen, i, step = 0; 337 int parent; 338 339 ilen = OF_getprop(node, "interrupt-map", imap, sizeof(imap)); 340 mlen = OF_getprop(node, "interrupt-map-mask", mmask, sizeof(mmask)); 341 if (ilen < 0 || mlen < 0) 342 return (-1); 343 344 if ((OF_getprop(node, "#address-cells", &acells, 4) < 0) || 345 (OF_getprop(node, "#interrupt-cells", &icells, 4) < 0)) 346 return (-1); 347 348 mcells = acells + icells; 349 if (mcells != (mlen / sizeof(mmask[0]))) 350 return (-1); 351 352 for (i = 0; i < mcells; i++) 353 addr[i] &= mmask[i]; 354 355 /* interrupt-map is formatted as follows 356 * int * #address-cells, int * #interrupt-cells, int, int, int 357 * eg 358 * address-cells = 3 359 * interrupt-cells = 1 360 * 00001000 00000000 00000000 00000000 ff911258 00000034 00000001 361 * 00001800 00000000 00000000 00000000 ff911258 00000035 00000001 362 * 00002000 00000000 00000000 00000000 ff911258 00000036 00000001 363 * | address cells | | intr | |node| | irq | |edge/level| 364 * | cells| | interrupt cells | 365 * | of node | 366 * or at least something close to that. 367 */ 368 for (mp = imap; ilen > mlen; mp += step) { 369 mp1 = mp + mcells; 370 parent = *mp1; 371 372 if (bcmp(mp, addr, mlen) == 0) { 373 char ic[20]; 374 375 /* 376 * If we have a match and the parent is not an 377 * interrupt controller continue recursively. 378 */ 379 if (OF_getprop(parent, "interrupt-controller", ic, 20)) 380 return ofw_intr_map(parent, &mp1[1], intr); 381 382 *intr = mp1[1]; 383 return (0); 384 } 385 386 if (OF_getprop(parent, "#address-cells", &acells, 4) < 0) 387 acells = 0; 388 if (OF_getprop(parent, "#interrupt-cells", &icells, 4) < 0) 389 break; 390 391 step = mcells + 1 + acells + icells; 392 ilen -= step * sizeof(imap[0]); 393 } 394 395 return (-1); 396 } 397