1 /* $OpenBSD: pciecam.c,v 1.6 2023/10/10 18:40:34 miod Exp $ */ 2 /* 3 * Copyright (c) 2013,2017 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/malloc.h> 21 #include <sys/extent.h> 22 #include <sys/device.h> 23 24 #include <machine/intr.h> 25 #include <machine/bus.h> 26 #include <machine/fdt.h> 27 28 #include <dev/pci/pcivar.h> 29 30 #include <dev/ofw/fdt.h> 31 #include <dev/ofw/ofw_pci.h> 32 #include <dev/ofw/openfirm.h> 33 34 /* Assembling ECAM Configuration Address */ 35 #define PCIE_BUS_SHIFT 20 36 #define PCIE_SLOT_SHIFT 15 37 #define PCIE_FUNC_SHIFT 12 38 #define PCIE_BUS_MASK 0xff 39 #define PCIE_SLOT_MASK 0x1f 40 #define PCIE_FUNC_MASK 0x7 41 #define PCIE_REG_MASK 0xfff 42 43 #define PCIE_ADDR_OFFSET(bus, slot, func, reg) \ 44 ((((bus) & PCIE_BUS_MASK) << PCIE_BUS_SHIFT) | \ 45 (((slot) & PCIE_SLOT_MASK) << PCIE_SLOT_SHIFT) | \ 46 (((func) & PCIE_FUNC_MASK) << PCIE_FUNC_SHIFT) | \ 47 ((reg) & PCIE_REG_MASK)) 48 49 #define HREAD4(sc, reg) \ 50 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 51 #define HWRITE4(sc, reg, val) \ 52 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 53 #define HSET4(sc, reg, bits) \ 54 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 55 #define HCLR4(sc, reg, bits) \ 56 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 57 58 struct pciecam_range { 59 uint32_t flags; 60 uint64_t pci_base; 61 uint64_t phys_base; 62 uint64_t size; 63 }; 64 65 struct pciecam_softc { 66 struct device sc_dev; 67 int sc_node; 68 bus_space_tag_t sc_iot; 69 bus_space_handle_t sc_ioh; 70 bus_dma_tag_t sc_dmat; 71 72 int sc_acells; 73 int sc_scells; 74 int sc_pacells; 75 int sc_pscells; 76 77 struct bus_space sc_bus; 78 struct pciecam_range *sc_pciranges; 79 int sc_pcirangeslen; 80 struct extent *sc_ioex; 81 struct extent *sc_memex; 82 char sc_ioex_name[32]; 83 char sc_memex_name[32]; 84 struct arm32_pci_chipset sc_pc; 85 }; 86 87 int pciecam_match(struct device *, void *, void *); 88 void pciecam_attach(struct device *, struct device *, void *); 89 void pciecam_attach_hook(struct device *, struct device *, struct pcibus_attach_args *); 90 int pciecam_bus_maxdevs(void *, int); 91 pcitag_t pciecam_make_tag(void *, int, int, int); 92 void pciecam_decompose_tag(void *, pcitag_t, int *, int *, int *); 93 int pciecam_conf_size(void *, pcitag_t); 94 pcireg_t pciecam_conf_read(void *, pcitag_t, int); 95 void pciecam_conf_write(void *, pcitag_t, int, pcireg_t); 96 int pciecam_probe_device_hook(void *, struct pci_attach_args *); 97 int pciecam_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 98 int pciecam_intr_map_msi(struct pci_attach_args *, pci_intr_handle_t *); 99 int pciecam_intr_map_msix(struct pci_attach_args *, int, pci_intr_handle_t *); 100 const char *pciecam_intr_string(void *, pci_intr_handle_t); 101 void *pciecam_intr_establish(void *, pci_intr_handle_t, int, struct cpu_info *, 102 int (*func)(void *), void *, char *); 103 void pciecam_intr_disestablish(void *, void *); 104 int pciecam_bs_map(void *, uint64_t, bus_size_t, int, bus_space_handle_t *); 105 106 const struct cfattach pciecam_ca = { 107 sizeof (struct pciecam_softc), pciecam_match, pciecam_attach 108 }; 109 110 struct cfdriver pciecam_cd = { 111 NULL, "pciecam", DV_DULL 112 }; 113 114 int 115 pciecam_match(struct device *parent, void *match, void *aux) 116 { 117 struct fdt_attach_args *faa = aux; 118 119 return OF_is_compatible(faa->fa_node, "pci-host-ecam-generic"); 120 } 121 122 void 123 pciecam_attach(struct device *parent, struct device *self, void *aux) 124 { 125 struct fdt_attach_args *faa = aux; 126 struct pciecam_softc *sc = (struct pciecam_softc *) self; 127 struct pcibus_attach_args pba; 128 uint32_t *ranges; 129 int i, j, nranges, rangeslen; 130 131 sc->sc_node = faa->fa_node; 132 sc->sc_iot = faa->fa_iot; 133 sc->sc_dmat = faa->fa_dmat; 134 135 sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells", 136 faa->fa_acells); 137 sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells", 138 faa->fa_scells); 139 sc->sc_pacells = faa->fa_acells; 140 sc->sc_pscells = faa->fa_scells; 141 142 rangeslen = OF_getproplen(sc->sc_node, "ranges"); 143 if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) || 144 (rangeslen / sizeof(uint32_t)) % (sc->sc_acells + 145 sc->sc_pacells + sc->sc_scells)) 146 panic("pciecam_attach: invalid ranges property"); 147 148 ranges = malloc(rangeslen, M_TEMP, M_WAITOK); 149 OF_getpropintarray(sc->sc_node, "ranges", ranges, 150 rangeslen); 151 152 nranges = (rangeslen / sizeof(uint32_t)) / 153 (sc->sc_acells + sc->sc_pacells + sc->sc_scells); 154 sc->sc_pciranges = mallocarray(nranges, 155 sizeof(struct pciecam_range), M_TEMP, M_WAITOK); 156 sc->sc_pcirangeslen = nranges; 157 158 for (i = 0, j = 0; i < nranges; i++) { 159 sc->sc_pciranges[i].flags = ranges[j++]; 160 sc->sc_pciranges[i].pci_base = ranges[j++]; 161 if (sc->sc_acells - 1 == 2) { 162 sc->sc_pciranges[i].pci_base <<= 32; 163 sc->sc_pciranges[i].pci_base |= ranges[j++]; 164 } 165 sc->sc_pciranges[i].phys_base = ranges[j++]; 166 if (sc->sc_pacells == 2) { 167 sc->sc_pciranges[i].phys_base <<= 32; 168 sc->sc_pciranges[i].phys_base |= ranges[j++]; 169 } 170 sc->sc_pciranges[i].size = ranges[j++]; 171 if (sc->sc_scells == 2) { 172 sc->sc_pciranges[i].size <<= 32; 173 sc->sc_pciranges[i].size |= ranges[j++]; 174 } 175 } 176 177 free(ranges, M_TEMP, rangeslen); 178 179 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 180 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 181 panic("pciecam_attach: bus_space_map failed!"); 182 183 printf("\n"); 184 185 /* 186 * Map PCIe address space. 187 */ 188 snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name), 189 "%s pciio", sc->sc_dev.dv_xname); 190 sc->sc_ioex = extent_create(sc->sc_ioex_name, 0, (u_long)-1L, 191 M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED); 192 193 snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name), 194 "%s pcimem", sc->sc_dev.dv_xname); 195 sc->sc_memex = extent_create(sc->sc_memex_name, 0, (u_long)-1L, 196 M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED); 197 198 for (i = 0; i < nranges; i++) { 199 switch (sc->sc_pciranges[i].flags & OFW_PCI_PHYS_HI_SPACEMASK) { 200 case OFW_PCI_PHYS_HI_SPACE_IO: 201 extent_free(sc->sc_ioex, sc->sc_pciranges[i].pci_base, 202 sc->sc_pciranges[i].size, EX_NOWAIT); 203 break; 204 case OFW_PCI_PHYS_HI_SPACE_MEM64: 205 if (sc->sc_pciranges[i].pci_base + 206 sc->sc_pciranges[i].size >= (1ULL << 32)) 207 break; 208 /* FALLTHROUGH */ 209 case OFW_PCI_PHYS_HI_SPACE_MEM32: 210 extent_free(sc->sc_memex, sc->sc_pciranges[i].pci_base, 211 sc->sc_pciranges[i].size, EX_NOWAIT); 212 break; 213 } 214 } 215 216 memcpy(&sc->sc_bus, sc->sc_iot, sizeof(sc->sc_bus)); 217 sc->sc_bus.bs_cookie = sc; 218 sc->sc_bus.bs_map = pciecam_bs_map; 219 220 sc->sc_pc.pc_conf_v = sc; 221 sc->sc_pc.pc_attach_hook = pciecam_attach_hook; 222 sc->sc_pc.pc_bus_maxdevs = pciecam_bus_maxdevs; 223 sc->sc_pc.pc_make_tag = pciecam_make_tag; 224 sc->sc_pc.pc_decompose_tag = pciecam_decompose_tag; 225 sc->sc_pc.pc_conf_size = pciecam_conf_size; 226 sc->sc_pc.pc_conf_read = pciecam_conf_read; 227 sc->sc_pc.pc_conf_write = pciecam_conf_write; 228 sc->sc_pc.pc_probe_device_hook = pciecam_probe_device_hook; 229 230 sc->sc_pc.pc_intr_v = sc; 231 sc->sc_pc.pc_intr_map = pciecam_intr_map; 232 sc->sc_pc.pc_intr_map_msi = pciecam_intr_map_msi; 233 sc->sc_pc.pc_intr_map_msix = pciecam_intr_map_msix; 234 sc->sc_pc.pc_intr_string = pciecam_intr_string; 235 sc->sc_pc.pc_intr_establish = pciecam_intr_establish; 236 sc->sc_pc.pc_intr_disestablish = pciecam_intr_disestablish; 237 238 bzero(&pba, sizeof(pba)); 239 pba.pba_dmat = sc->sc_dmat; 240 241 pba.pba_busname = "pci"; 242 pba.pba_iot = &sc->sc_bus; 243 pba.pba_memt = &sc->sc_bus; 244 pba.pba_ioex = sc->sc_ioex; 245 pba.pba_memex = sc->sc_memex; 246 pba.pba_pc = &sc->sc_pc; 247 pba.pba_domain = pci_ndomains++; 248 pba.pba_bus = 0; 249 250 config_found(self, &pba, NULL); 251 } 252 253 void 254 pciecam_attach_hook(struct device *parent, struct device *self, 255 struct pcibus_attach_args *pba) 256 { 257 } 258 259 int 260 pciecam_bus_maxdevs(void *sc, int busno) { 261 return (32); 262 } 263 264 #define BUS_SHIFT 24 265 #define DEVICE_SHIFT 19 266 #define FNC_SHIFT 16 267 268 pcitag_t 269 pciecam_make_tag(void *sc, int bus, int dev, int fnc) 270 { 271 return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT); 272 } 273 274 void 275 pciecam_decompose_tag(void *sc, pcitag_t tag, int *busp, int *devp, int *fncp) 276 { 277 if (busp != NULL) 278 *busp = (tag >> BUS_SHIFT) & 0xff; 279 if (devp != NULL) 280 *devp = (tag >> DEVICE_SHIFT) & 0x1f; 281 if (fncp != NULL) 282 *fncp = (tag >> FNC_SHIFT) & 0x7; 283 } 284 285 int 286 pciecam_conf_size(void *sc, pcitag_t tag) 287 { 288 return PCIE_CONFIG_SPACE_SIZE; 289 } 290 291 pcireg_t 292 pciecam_conf_read(void *v, pcitag_t tag, int reg) 293 { 294 struct pciecam_softc *sc = (struct pciecam_softc *)v; 295 int bus, dev, fn; 296 297 pciecam_decompose_tag(sc, tag, &bus, &dev, &fn); 298 299 return HREAD4(sc, PCIE_ADDR_OFFSET(bus, dev, fn, reg & ~0x3)); 300 } 301 302 void 303 pciecam_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) 304 { 305 struct pciecam_softc *sc = (struct pciecam_softc *)v; 306 int bus, dev, fn; 307 308 pciecam_decompose_tag(sc, tag, &bus, &dev, &fn); 309 310 HWRITE4(sc, PCIE_ADDR_OFFSET(bus, dev, fn, reg & ~0x3), data); 311 } 312 313 int 314 pciecam_probe_device_hook(void *v, struct pci_attach_args *pa) 315 { 316 return 0; 317 } 318 319 struct pciecam_intr_handle { 320 pci_chipset_tag_t ih_pc; 321 pcitag_t ih_tag; 322 int ih_intrpin; 323 int ih_msi; 324 }; 325 326 int 327 pciecam_intr_map(struct pci_attach_args *pa, 328 pci_intr_handle_t *ihp) 329 { 330 struct pciecam_intr_handle *ih; 331 ih = malloc(sizeof(struct pciecam_intr_handle), M_DEVBUF, M_WAITOK); 332 ih->ih_pc = pa->pa_pc; 333 ih->ih_tag = pa->pa_intrtag; 334 ih->ih_intrpin = pa->pa_intrpin; 335 ih->ih_msi = 0; 336 *ihp = (pci_intr_handle_t)ih; 337 return 0; 338 } 339 340 int 341 pciecam_intr_map_msi(struct pci_attach_args *pa, 342 pci_intr_handle_t *ihp) 343 { 344 pci_chipset_tag_t pc = pa->pa_pc; 345 pcitag_t tag = pa->pa_tag; 346 struct pciecam_intr_handle *ih; 347 348 if (pci_get_capability(pc, tag, PCI_CAP_MSI, NULL, NULL) == 0) 349 return 1; 350 351 ih = malloc(sizeof(struct pciecam_intr_handle), M_DEVBUF, M_WAITOK); 352 ih->ih_pc = pa->pa_pc; 353 ih->ih_tag = pa->pa_tag; 354 ih->ih_intrpin = pa->pa_intrpin; 355 ih->ih_msi = 1; 356 *ihp = (pci_intr_handle_t)ih; 357 358 return 0; 359 } 360 361 int 362 pciecam_intr_map_msix(struct pci_attach_args *pa, 363 int vec, pci_intr_handle_t *ihp) 364 { 365 *ihp = (pci_intr_handle_t) pa->pa_pc; 366 return -1; 367 } 368 369 const char * 370 pciecam_intr_string(void *sc, pci_intr_handle_t ihp) 371 { 372 struct pciecam_intr_handle *ih = (struct pciecam_intr_handle *)ihp; 373 374 if (ih->ih_msi) 375 return "msi"; 376 377 return "irq"; 378 } 379 380 void * 381 pciecam_intr_establish(void *self, pci_intr_handle_t ihp, int level, 382 struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 383 { 384 struct pciecam_softc *sc = (struct pciecam_softc *)self; 385 struct pciecam_intr_handle *ih = (struct pciecam_intr_handle *)ihp; 386 void *cookie; 387 388 if (ih->ih_msi) { 389 uint64_t addr, data; 390 pcireg_t reg; 391 int off; 392 393 cookie = arm_intr_establish_fdt_msi_cpu(sc->sc_node, &addr, 394 &data, level, ci, func, arg, (void *)name); 395 if (cookie == NULL) 396 return NULL; 397 398 /* TODO: translate address to the PCI device's view */ 399 400 if (pci_get_capability(ih->ih_pc, ih->ih_tag, PCI_CAP_MSI, 401 &off, ®) == 0) 402 panic("%s: no msi capability", __func__); 403 404 if (reg & PCI_MSI_MC_C64) { 405 pci_conf_write(ih->ih_pc, ih->ih_tag, 406 off + PCI_MSI_MA, addr); 407 pci_conf_write(ih->ih_pc, ih->ih_tag, 408 off + PCI_MSI_MAU32, addr >> 32); 409 pci_conf_write(ih->ih_pc, ih->ih_tag, 410 off + PCI_MSI_MD64, data); 411 } else { 412 pci_conf_write(ih->ih_pc, ih->ih_tag, 413 off + PCI_MSI_MA, addr); 414 pci_conf_write(ih->ih_pc, ih->ih_tag, 415 off + PCI_MSI_MD32, data); 416 } 417 pci_conf_write(ih->ih_pc, ih->ih_tag, 418 off, reg | PCI_MSI_MC_MSIE); 419 } else { 420 int bus, dev, fn; 421 uint32_t reg[4]; 422 423 pciecam_decompose_tag(sc, ih->ih_tag, &bus, &dev, &fn); 424 425 reg[0] = bus << 16 | dev << 11 | fn << 8; 426 reg[1] = reg[2] = 0; 427 reg[3] = ih->ih_intrpin; 428 429 cookie = arm_intr_establish_fdt_imap_cpu(sc->sc_node, reg, 430 sizeof(reg), level, ci, func, arg, name); 431 } 432 433 free(ih, M_DEVBUF, sizeof(struct pciecam_intr_handle)); 434 return cookie; 435 } 436 437 void 438 pciecam_intr_disestablish(void *sc, void *cookie) 439 { 440 /* do something */ 441 } 442 443 /* 444 * Translate memory address if needed. 445 */ 446 int 447 pciecam_bs_map(void *t, uint64_t bpa, bus_size_t size, 448 int flag, bus_space_handle_t *bshp) 449 { 450 struct pciecam_softc *sc = t; 451 uint64_t physbase, pcibase, psize; 452 int i; 453 454 for (i = 0; i < sc->sc_pcirangeslen; i++) { 455 physbase = sc->sc_pciranges[i].phys_base; 456 pcibase = sc->sc_pciranges[i].pci_base; 457 psize = sc->sc_pciranges[i].size; 458 459 if (bpa >= pcibase && bpa + size <= pcibase + psize) 460 return bus_space_map(sc->sc_iot, 461 bpa - pcibase + physbase, size, flag, bshp); 462 } 463 464 return ENXIO; 465 } 466