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 58struct pciecam_range { 59 uint32_t flags; 60 uint64_t pci_base; 61 uint64_t phys_base; 62 uint64_t size; 63}; 64 65struct 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 87int pciecam_match(struct device *, void *, void *); 88void pciecam_attach(struct device *, struct device *, void *); 89void pciecam_attach_hook(struct device *, struct device *, struct pcibus_attach_args *); 90int pciecam_bus_maxdevs(void *, int); 91pcitag_t pciecam_make_tag(void *, int, int, int); 92void pciecam_decompose_tag(void *, pcitag_t, int *, int *, int *); 93int pciecam_conf_size(void *, pcitag_t); 94pcireg_t pciecam_conf_read(void *, pcitag_t, int); 95void pciecam_conf_write(void *, pcitag_t, int, pcireg_t); 96int pciecam_probe_device_hook(void *, struct pci_attach_args *); 97int pciecam_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 98int pciecam_intr_map_msi(struct pci_attach_args *, pci_intr_handle_t *); 99int pciecam_intr_map_msix(struct pci_attach_args *, int, pci_intr_handle_t *); 100const char *pciecam_intr_string(void *, pci_intr_handle_t); 101void *pciecam_intr_establish(void *, pci_intr_handle_t, int, struct cpu_info *, 102 int (*func)(void *), void *, char *); 103void pciecam_intr_disestablish(void *, void *); 104int pciecam_bs_map(void *, uint64_t, bus_size_t, int, bus_space_handle_t *); 105 106const struct cfattach pciecam_ca = { 107 sizeof (struct pciecam_softc), pciecam_match, pciecam_attach 108}; 109 110struct cfdriver pciecam_cd = { 111 NULL, "pciecam", DV_DULL 112}; 113 114int 115pciecam_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 122void 123pciecam_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 253void 254pciecam_attach_hook(struct device *parent, struct device *self, 255 struct pcibus_attach_args *pba) 256{ 257} 258 259int 260pciecam_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 268pcitag_t 269pciecam_make_tag(void *sc, int bus, int dev, int fnc) 270{ 271 return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT); 272} 273 274void 275pciecam_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 285int 286pciecam_conf_size(void *sc, pcitag_t tag) 287{ 288 return PCIE_CONFIG_SPACE_SIZE; 289} 290 291pcireg_t 292pciecam_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 302void 303pciecam_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 313int 314pciecam_probe_device_hook(void *v, struct pci_attach_args *pa) 315{ 316 return 0; 317} 318 319struct 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 326int 327pciecam_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 340int 341pciecam_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 361int 362pciecam_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 369const char * 370pciecam_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 380void * 381pciecam_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 437void 438pciecam_intr_disestablish(void *sc, void *cookie) 439{ 440 /* do something */ 441} 442 443/* 444 * Translate memory address if needed. 445 */ 446int 447pciecam_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