1*d633c629Smiod /* $OpenBSD: pciecam.c,v 1.6 2023/10/10 18:40:34 miod Exp $ */
25375f030Spatrick /*
35375f030Spatrick * Copyright (c) 2013,2017 Patrick Wildt <patrick@blueri.se>
45375f030Spatrick *
55375f030Spatrick * Permission to use, copy, modify, and distribute this software for any
65375f030Spatrick * purpose with or without fee is hereby granted, provided that the above
75375f030Spatrick * copyright notice and this permission notice appear in all copies.
85375f030Spatrick *
95375f030Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
105375f030Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
115375f030Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
125375f030Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
135375f030Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
145375f030Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
155375f030Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
165375f030Spatrick */
175375f030Spatrick
185375f030Spatrick #include <sys/param.h>
195375f030Spatrick #include <sys/systm.h>
205375f030Spatrick #include <sys/malloc.h>
215375f030Spatrick #include <sys/extent.h>
225375f030Spatrick #include <sys/device.h>
235375f030Spatrick
245375f030Spatrick #include <machine/intr.h>
255375f030Spatrick #include <machine/bus.h>
265375f030Spatrick #include <machine/fdt.h>
275375f030Spatrick
285375f030Spatrick #include <dev/pci/pcivar.h>
295375f030Spatrick
305375f030Spatrick #include <dev/ofw/fdt.h>
31*d633c629Smiod #include <dev/ofw/ofw_pci.h>
325375f030Spatrick #include <dev/ofw/openfirm.h>
335375f030Spatrick
345375f030Spatrick /* Assembling ECAM Configuration Address */
355375f030Spatrick #define PCIE_BUS_SHIFT 20
365375f030Spatrick #define PCIE_SLOT_SHIFT 15
375375f030Spatrick #define PCIE_FUNC_SHIFT 12
385375f030Spatrick #define PCIE_BUS_MASK 0xff
395375f030Spatrick #define PCIE_SLOT_MASK 0x1f
405375f030Spatrick #define PCIE_FUNC_MASK 0x7
415375f030Spatrick #define PCIE_REG_MASK 0xfff
425375f030Spatrick
435375f030Spatrick #define PCIE_ADDR_OFFSET(bus, slot, func, reg) \
445375f030Spatrick ((((bus) & PCIE_BUS_MASK) << PCIE_BUS_SHIFT) | \
455375f030Spatrick (((slot) & PCIE_SLOT_MASK) << PCIE_SLOT_SHIFT) | \
465375f030Spatrick (((func) & PCIE_FUNC_MASK) << PCIE_FUNC_SHIFT) | \
475375f030Spatrick ((reg) & PCIE_REG_MASK))
485375f030Spatrick
495375f030Spatrick #define HREAD4(sc, reg) \
505375f030Spatrick (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
515375f030Spatrick #define HWRITE4(sc, reg, val) \
525375f030Spatrick bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
535375f030Spatrick #define HSET4(sc, reg, bits) \
545375f030Spatrick HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
555375f030Spatrick #define HCLR4(sc, reg, bits) \
565375f030Spatrick HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
575375f030Spatrick
585375f030Spatrick struct pciecam_range {
595375f030Spatrick uint32_t flags;
605375f030Spatrick uint64_t pci_base;
615375f030Spatrick uint64_t phys_base;
625375f030Spatrick uint64_t size;
635375f030Spatrick };
645375f030Spatrick
655375f030Spatrick struct pciecam_softc {
665375f030Spatrick struct device sc_dev;
675375f030Spatrick int sc_node;
685375f030Spatrick bus_space_tag_t sc_iot;
695375f030Spatrick bus_space_handle_t sc_ioh;
705375f030Spatrick bus_dma_tag_t sc_dmat;
715375f030Spatrick
725375f030Spatrick int sc_acells;
735375f030Spatrick int sc_scells;
745375f030Spatrick int sc_pacells;
755375f030Spatrick int sc_pscells;
765375f030Spatrick
775375f030Spatrick struct bus_space sc_bus;
785375f030Spatrick struct pciecam_range *sc_pciranges;
795375f030Spatrick int sc_pcirangeslen;
805375f030Spatrick struct extent *sc_ioex;
815375f030Spatrick struct extent *sc_memex;
825375f030Spatrick char sc_ioex_name[32];
835375f030Spatrick char sc_memex_name[32];
845375f030Spatrick struct arm32_pci_chipset sc_pc;
855375f030Spatrick };
865375f030Spatrick
875375f030Spatrick int pciecam_match(struct device *, void *, void *);
885375f030Spatrick void pciecam_attach(struct device *, struct device *, void *);
895375f030Spatrick void pciecam_attach_hook(struct device *, struct device *, struct pcibus_attach_args *);
905375f030Spatrick int pciecam_bus_maxdevs(void *, int);
915375f030Spatrick pcitag_t pciecam_make_tag(void *, int, int, int);
925375f030Spatrick void pciecam_decompose_tag(void *, pcitag_t, int *, int *, int *);
935375f030Spatrick int pciecam_conf_size(void *, pcitag_t);
945375f030Spatrick pcireg_t pciecam_conf_read(void *, pcitag_t, int);
955375f030Spatrick void pciecam_conf_write(void *, pcitag_t, int, pcireg_t);
96619b146dSpatrick int pciecam_probe_device_hook(void *, struct pci_attach_args *);
975375f030Spatrick int pciecam_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
985375f030Spatrick int pciecam_intr_map_msi(struct pci_attach_args *, pci_intr_handle_t *);
995375f030Spatrick int pciecam_intr_map_msix(struct pci_attach_args *, int, pci_intr_handle_t *);
1005375f030Spatrick const char *pciecam_intr_string(void *, pci_intr_handle_t);
101d67371fdSpatrick void *pciecam_intr_establish(void *, pci_intr_handle_t, int, struct cpu_info *,
102d67371fdSpatrick int (*func)(void *), void *, char *);
1035375f030Spatrick void pciecam_intr_disestablish(void *, void *);
1045375f030Spatrick int pciecam_bs_map(void *, uint64_t, bus_size_t, int, bus_space_handle_t *);
1055375f030Spatrick
1069fdf0c62Smpi const struct cfattach pciecam_ca = {
1075375f030Spatrick sizeof (struct pciecam_softc), pciecam_match, pciecam_attach
1085375f030Spatrick };
1095375f030Spatrick
1105375f030Spatrick struct cfdriver pciecam_cd = {
1115375f030Spatrick NULL, "pciecam", DV_DULL
1125375f030Spatrick };
1135375f030Spatrick
1145375f030Spatrick int
pciecam_match(struct device * parent,void * match,void * aux)1155375f030Spatrick pciecam_match(struct device *parent, void *match, void *aux)
1165375f030Spatrick {
1175375f030Spatrick struct fdt_attach_args *faa = aux;
1185375f030Spatrick
1195375f030Spatrick return OF_is_compatible(faa->fa_node, "pci-host-ecam-generic");
1205375f030Spatrick }
1215375f030Spatrick
1225375f030Spatrick void
pciecam_attach(struct device * parent,struct device * self,void * aux)1235375f030Spatrick pciecam_attach(struct device *parent, struct device *self, void *aux)
1245375f030Spatrick {
1255375f030Spatrick struct fdt_attach_args *faa = aux;
1265375f030Spatrick struct pciecam_softc *sc = (struct pciecam_softc *) self;
1275375f030Spatrick struct pcibus_attach_args pba;
1285375f030Spatrick uint32_t *ranges;
1295375f030Spatrick int i, j, nranges, rangeslen;
1305375f030Spatrick
1315375f030Spatrick sc->sc_node = faa->fa_node;
1325375f030Spatrick sc->sc_iot = faa->fa_iot;
1335375f030Spatrick sc->sc_dmat = faa->fa_dmat;
1345375f030Spatrick
1355375f030Spatrick sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells",
1365375f030Spatrick faa->fa_acells);
1375375f030Spatrick sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
1385375f030Spatrick faa->fa_scells);
1395375f030Spatrick sc->sc_pacells = faa->fa_acells;
1405375f030Spatrick sc->sc_pscells = faa->fa_scells;
1415375f030Spatrick
1425375f030Spatrick rangeslen = OF_getproplen(sc->sc_node, "ranges");
1435375f030Spatrick if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) ||
1445375f030Spatrick (rangeslen / sizeof(uint32_t)) % (sc->sc_acells +
1455375f030Spatrick sc->sc_pacells + sc->sc_scells))
1465375f030Spatrick panic("pciecam_attach: invalid ranges property");
1475375f030Spatrick
1485375f030Spatrick ranges = malloc(rangeslen, M_TEMP, M_WAITOK);
1495375f030Spatrick OF_getpropintarray(sc->sc_node, "ranges", ranges,
1505375f030Spatrick rangeslen);
1515375f030Spatrick
1525375f030Spatrick nranges = (rangeslen / sizeof(uint32_t)) /
1535375f030Spatrick (sc->sc_acells + sc->sc_pacells + sc->sc_scells);
1545375f030Spatrick sc->sc_pciranges = mallocarray(nranges,
1555375f030Spatrick sizeof(struct pciecam_range), M_TEMP, M_WAITOK);
1565375f030Spatrick sc->sc_pcirangeslen = nranges;
1575375f030Spatrick
1585375f030Spatrick for (i = 0, j = 0; i < nranges; i++) {
1595375f030Spatrick sc->sc_pciranges[i].flags = ranges[j++];
1605375f030Spatrick sc->sc_pciranges[i].pci_base = ranges[j++];
1615375f030Spatrick if (sc->sc_acells - 1 == 2) {
1625375f030Spatrick sc->sc_pciranges[i].pci_base <<= 32;
1635375f030Spatrick sc->sc_pciranges[i].pci_base |= ranges[j++];
1645375f030Spatrick }
1655375f030Spatrick sc->sc_pciranges[i].phys_base = ranges[j++];
1665375f030Spatrick if (sc->sc_pacells == 2) {
1675375f030Spatrick sc->sc_pciranges[i].phys_base <<= 32;
1685375f030Spatrick sc->sc_pciranges[i].phys_base |= ranges[j++];
1695375f030Spatrick }
1705375f030Spatrick sc->sc_pciranges[i].size = ranges[j++];
1715375f030Spatrick if (sc->sc_scells == 2) {
1725375f030Spatrick sc->sc_pciranges[i].size <<= 32;
1735375f030Spatrick sc->sc_pciranges[i].size |= ranges[j++];
1745375f030Spatrick }
1755375f030Spatrick }
1765375f030Spatrick
1775375f030Spatrick free(ranges, M_TEMP, rangeslen);
1785375f030Spatrick
1795375f030Spatrick if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
1805375f030Spatrick faa->fa_reg[0].size, 0, &sc->sc_ioh))
1815375f030Spatrick panic("pciecam_attach: bus_space_map failed!");
1825375f030Spatrick
1835375f030Spatrick printf("\n");
1845375f030Spatrick
1855375f030Spatrick /*
1865375f030Spatrick * Map PCIe address space.
1875375f030Spatrick */
1885375f030Spatrick snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name),
1895375f030Spatrick "%s pciio", sc->sc_dev.dv_xname);
1905375f030Spatrick sc->sc_ioex = extent_create(sc->sc_ioex_name, 0, (u_long)-1L,
1915375f030Spatrick M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED);
1925375f030Spatrick
1935375f030Spatrick snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name),
1945375f030Spatrick "%s pcimem", sc->sc_dev.dv_xname);
1955375f030Spatrick sc->sc_memex = extent_create(sc->sc_memex_name, 0, (u_long)-1L,
1965375f030Spatrick M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED);
1975375f030Spatrick
1985375f030Spatrick for (i = 0; i < nranges; i++) {
199*d633c629Smiod switch (sc->sc_pciranges[i].flags & OFW_PCI_PHYS_HI_SPACEMASK) {
200*d633c629Smiod case OFW_PCI_PHYS_HI_SPACE_IO:
2015375f030Spatrick extent_free(sc->sc_ioex, sc->sc_pciranges[i].pci_base,
2025375f030Spatrick sc->sc_pciranges[i].size, EX_NOWAIT);
203*d633c629Smiod break;
204*d633c629Smiod case OFW_PCI_PHYS_HI_SPACE_MEM64:
205*d633c629Smiod if (sc->sc_pciranges[i].pci_base +
206*d633c629Smiod sc->sc_pciranges[i].size >= (1ULL << 32))
207*d633c629Smiod break;
208*d633c629Smiod /* FALLTHROUGH */
209*d633c629Smiod case OFW_PCI_PHYS_HI_SPACE_MEM32:
2105375f030Spatrick extent_free(sc->sc_memex, sc->sc_pciranges[i].pci_base,
2115375f030Spatrick sc->sc_pciranges[i].size, EX_NOWAIT);
212*d633c629Smiod break;
213*d633c629Smiod }
2145375f030Spatrick }
2155375f030Spatrick
2165375f030Spatrick memcpy(&sc->sc_bus, sc->sc_iot, sizeof(sc->sc_bus));
2175375f030Spatrick sc->sc_bus.bs_cookie = sc;
2185375f030Spatrick sc->sc_bus.bs_map = pciecam_bs_map;
2195375f030Spatrick
2205375f030Spatrick sc->sc_pc.pc_conf_v = sc;
2215375f030Spatrick sc->sc_pc.pc_attach_hook = pciecam_attach_hook;
2225375f030Spatrick sc->sc_pc.pc_bus_maxdevs = pciecam_bus_maxdevs;
2235375f030Spatrick sc->sc_pc.pc_make_tag = pciecam_make_tag;
2245375f030Spatrick sc->sc_pc.pc_decompose_tag = pciecam_decompose_tag;
2255375f030Spatrick sc->sc_pc.pc_conf_size = pciecam_conf_size;
2265375f030Spatrick sc->sc_pc.pc_conf_read = pciecam_conf_read;
2275375f030Spatrick sc->sc_pc.pc_conf_write = pciecam_conf_write;
228619b146dSpatrick sc->sc_pc.pc_probe_device_hook = pciecam_probe_device_hook;
2295375f030Spatrick
2305375f030Spatrick sc->sc_pc.pc_intr_v = sc;
2315375f030Spatrick sc->sc_pc.pc_intr_map = pciecam_intr_map;
2325375f030Spatrick sc->sc_pc.pc_intr_map_msi = pciecam_intr_map_msi;
2335375f030Spatrick sc->sc_pc.pc_intr_map_msix = pciecam_intr_map_msix;
2345375f030Spatrick sc->sc_pc.pc_intr_string = pciecam_intr_string;
2355375f030Spatrick sc->sc_pc.pc_intr_establish = pciecam_intr_establish;
2365375f030Spatrick sc->sc_pc.pc_intr_disestablish = pciecam_intr_disestablish;
2375375f030Spatrick
2385375f030Spatrick bzero(&pba, sizeof(pba));
2395375f030Spatrick pba.pba_dmat = sc->sc_dmat;
2405375f030Spatrick
2415375f030Spatrick pba.pba_busname = "pci";
2425375f030Spatrick pba.pba_iot = &sc->sc_bus;
2435375f030Spatrick pba.pba_memt = &sc->sc_bus;
2445375f030Spatrick pba.pba_ioex = sc->sc_ioex;
2455375f030Spatrick pba.pba_memex = sc->sc_memex;
2465375f030Spatrick pba.pba_pc = &sc->sc_pc;
2475375f030Spatrick pba.pba_domain = pci_ndomains++;
2485375f030Spatrick pba.pba_bus = 0;
2495375f030Spatrick
2505375f030Spatrick config_found(self, &pba, NULL);
2515375f030Spatrick }
2525375f030Spatrick
2535375f030Spatrick void
pciecam_attach_hook(struct device * parent,struct device * self,struct pcibus_attach_args * pba)2545375f030Spatrick pciecam_attach_hook(struct device *parent, struct device *self,
2555375f030Spatrick struct pcibus_attach_args *pba)
2565375f030Spatrick {
2575375f030Spatrick }
2585375f030Spatrick
2595375f030Spatrick int
pciecam_bus_maxdevs(void * sc,int busno)2605375f030Spatrick pciecam_bus_maxdevs(void *sc, int busno) {
2615375f030Spatrick return (32);
2625375f030Spatrick }
2635375f030Spatrick
2645375f030Spatrick #define BUS_SHIFT 24
2655375f030Spatrick #define DEVICE_SHIFT 19
2665375f030Spatrick #define FNC_SHIFT 16
2675375f030Spatrick
2685375f030Spatrick pcitag_t
pciecam_make_tag(void * sc,int bus,int dev,int fnc)2695375f030Spatrick pciecam_make_tag(void *sc, int bus, int dev, int fnc)
2705375f030Spatrick {
2715375f030Spatrick return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT);
2725375f030Spatrick }
2735375f030Spatrick
2745375f030Spatrick void
pciecam_decompose_tag(void * sc,pcitag_t tag,int * busp,int * devp,int * fncp)2755375f030Spatrick pciecam_decompose_tag(void *sc, pcitag_t tag, int *busp, int *devp, int *fncp)
2765375f030Spatrick {
2775375f030Spatrick if (busp != NULL)
2785375f030Spatrick *busp = (tag >> BUS_SHIFT) & 0xff;
2795375f030Spatrick if (devp != NULL)
2805375f030Spatrick *devp = (tag >> DEVICE_SHIFT) & 0x1f;
2815375f030Spatrick if (fncp != NULL)
2825375f030Spatrick *fncp = (tag >> FNC_SHIFT) & 0x7;
2835375f030Spatrick }
2845375f030Spatrick
2855375f030Spatrick int
pciecam_conf_size(void * sc,pcitag_t tag)2865375f030Spatrick pciecam_conf_size(void *sc, pcitag_t tag)
2875375f030Spatrick {
2885375f030Spatrick return PCIE_CONFIG_SPACE_SIZE;
2895375f030Spatrick }
2905375f030Spatrick
2915375f030Spatrick pcireg_t
pciecam_conf_read(void * v,pcitag_t tag,int reg)2925375f030Spatrick pciecam_conf_read(void *v, pcitag_t tag, int reg)
2935375f030Spatrick {
2945375f030Spatrick struct pciecam_softc *sc = (struct pciecam_softc *)v;
2955375f030Spatrick int bus, dev, fn;
2965375f030Spatrick
2975375f030Spatrick pciecam_decompose_tag(sc, tag, &bus, &dev, &fn);
2985375f030Spatrick
2995375f030Spatrick return HREAD4(sc, PCIE_ADDR_OFFSET(bus, dev, fn, reg & ~0x3));
3005375f030Spatrick }
3015375f030Spatrick
3025375f030Spatrick void
pciecam_conf_write(void * v,pcitag_t tag,int reg,pcireg_t data)3035375f030Spatrick pciecam_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
3045375f030Spatrick {
3055375f030Spatrick struct pciecam_softc *sc = (struct pciecam_softc *)v;
3065375f030Spatrick int bus, dev, fn;
3075375f030Spatrick
3085375f030Spatrick pciecam_decompose_tag(sc, tag, &bus, &dev, &fn);
3095375f030Spatrick
3105375f030Spatrick HWRITE4(sc, PCIE_ADDR_OFFSET(bus, dev, fn, reg & ~0x3), data);
3115375f030Spatrick }
3125375f030Spatrick
313619b146dSpatrick int
pciecam_probe_device_hook(void * v,struct pci_attach_args * pa)314619b146dSpatrick pciecam_probe_device_hook(void *v, struct pci_attach_args *pa)
315619b146dSpatrick {
316619b146dSpatrick return 0;
317619b146dSpatrick }
318619b146dSpatrick
3195375f030Spatrick struct pciecam_intr_handle {
3205375f030Spatrick pci_chipset_tag_t ih_pc;
3215375f030Spatrick pcitag_t ih_tag;
3225375f030Spatrick int ih_intrpin;
3235375f030Spatrick int ih_msi;
3245375f030Spatrick };
3255375f030Spatrick
3265375f030Spatrick int
pciecam_intr_map(struct pci_attach_args * pa,pci_intr_handle_t * ihp)3275375f030Spatrick pciecam_intr_map(struct pci_attach_args *pa,
3285375f030Spatrick pci_intr_handle_t *ihp)
3295375f030Spatrick {
3305375f030Spatrick struct pciecam_intr_handle *ih;
3315375f030Spatrick ih = malloc(sizeof(struct pciecam_intr_handle), M_DEVBUF, M_WAITOK);
3325375f030Spatrick ih->ih_pc = pa->pa_pc;
3335375f030Spatrick ih->ih_tag = pa->pa_intrtag;
3345375f030Spatrick ih->ih_intrpin = pa->pa_intrpin;
3355375f030Spatrick ih->ih_msi = 0;
3365375f030Spatrick *ihp = (pci_intr_handle_t)ih;
3375375f030Spatrick return 0;
3385375f030Spatrick }
3395375f030Spatrick
3405375f030Spatrick int
pciecam_intr_map_msi(struct pci_attach_args * pa,pci_intr_handle_t * ihp)3415375f030Spatrick pciecam_intr_map_msi(struct pci_attach_args *pa,
3425375f030Spatrick pci_intr_handle_t *ihp)
3435375f030Spatrick {
3445375f030Spatrick pci_chipset_tag_t pc = pa->pa_pc;
3455375f030Spatrick pcitag_t tag = pa->pa_tag;
3465375f030Spatrick struct pciecam_intr_handle *ih;
3475375f030Spatrick
3485375f030Spatrick if (pci_get_capability(pc, tag, PCI_CAP_MSI, NULL, NULL) == 0)
3495375f030Spatrick return 1;
3505375f030Spatrick
3515375f030Spatrick ih = malloc(sizeof(struct pciecam_intr_handle), M_DEVBUF, M_WAITOK);
3525375f030Spatrick ih->ih_pc = pa->pa_pc;
3535375f030Spatrick ih->ih_tag = pa->pa_tag;
3545375f030Spatrick ih->ih_intrpin = pa->pa_intrpin;
3555375f030Spatrick ih->ih_msi = 1;
3565375f030Spatrick *ihp = (pci_intr_handle_t)ih;
3575375f030Spatrick
3585375f030Spatrick return 0;
3595375f030Spatrick }
3605375f030Spatrick
3615375f030Spatrick int
pciecam_intr_map_msix(struct pci_attach_args * pa,int vec,pci_intr_handle_t * ihp)3625375f030Spatrick pciecam_intr_map_msix(struct pci_attach_args *pa,
3635375f030Spatrick int vec, pci_intr_handle_t *ihp)
3645375f030Spatrick {
3655375f030Spatrick *ihp = (pci_intr_handle_t) pa->pa_pc;
3665375f030Spatrick return -1;
3675375f030Spatrick }
3685375f030Spatrick
3695375f030Spatrick const char *
pciecam_intr_string(void * sc,pci_intr_handle_t ihp)3705375f030Spatrick pciecam_intr_string(void *sc, pci_intr_handle_t ihp)
3715375f030Spatrick {
3725375f030Spatrick struct pciecam_intr_handle *ih = (struct pciecam_intr_handle *)ihp;
3735375f030Spatrick
3745375f030Spatrick if (ih->ih_msi)
3755375f030Spatrick return "msi";
3765375f030Spatrick
3775375f030Spatrick return "irq";
3785375f030Spatrick }
3795375f030Spatrick
3805375f030Spatrick void *
pciecam_intr_establish(void * self,pci_intr_handle_t ihp,int level,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)3815375f030Spatrick pciecam_intr_establish(void *self, pci_intr_handle_t ihp, int level,
382d67371fdSpatrick struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
3835375f030Spatrick {
3845375f030Spatrick struct pciecam_softc *sc = (struct pciecam_softc *)self;
3855375f030Spatrick struct pciecam_intr_handle *ih = (struct pciecam_intr_handle *)ihp;
3865375f030Spatrick void *cookie;
3875375f030Spatrick
3885375f030Spatrick if (ih->ih_msi) {
3895375f030Spatrick uint64_t addr, data;
3905375f030Spatrick pcireg_t reg;
3915375f030Spatrick int off;
3925375f030Spatrick
393d67371fdSpatrick cookie = arm_intr_establish_fdt_msi_cpu(sc->sc_node, &addr,
394d67371fdSpatrick &data, level, ci, func, arg, (void *)name);
3955375f030Spatrick if (cookie == NULL)
3965375f030Spatrick return NULL;
3975375f030Spatrick
3985375f030Spatrick /* TODO: translate address to the PCI device's view */
3995375f030Spatrick
4005375f030Spatrick if (pci_get_capability(ih->ih_pc, ih->ih_tag, PCI_CAP_MSI,
4015375f030Spatrick &off, ®) == 0)
4025375f030Spatrick panic("%s: no msi capability", __func__);
4035375f030Spatrick
4045375f030Spatrick if (reg & PCI_MSI_MC_C64) {
4055375f030Spatrick pci_conf_write(ih->ih_pc, ih->ih_tag,
4065375f030Spatrick off + PCI_MSI_MA, addr);
4075375f030Spatrick pci_conf_write(ih->ih_pc, ih->ih_tag,
4085375f030Spatrick off + PCI_MSI_MAU32, addr >> 32);
4095375f030Spatrick pci_conf_write(ih->ih_pc, ih->ih_tag,
4105375f030Spatrick off + PCI_MSI_MD64, data);
4115375f030Spatrick } else {
4125375f030Spatrick pci_conf_write(ih->ih_pc, ih->ih_tag,
4135375f030Spatrick off + PCI_MSI_MA, addr);
4145375f030Spatrick pci_conf_write(ih->ih_pc, ih->ih_tag,
4155375f030Spatrick off + PCI_MSI_MD32, data);
4165375f030Spatrick }
4175375f030Spatrick pci_conf_write(ih->ih_pc, ih->ih_tag,
4185375f030Spatrick off, reg | PCI_MSI_MC_MSIE);
4195375f030Spatrick } else {
4205375f030Spatrick int bus, dev, fn;
4215375f030Spatrick uint32_t reg[4];
4225375f030Spatrick
4235375f030Spatrick pciecam_decompose_tag(sc, ih->ih_tag, &bus, &dev, &fn);
4245375f030Spatrick
4255375f030Spatrick reg[0] = bus << 16 | dev << 11 | fn << 8;
4265375f030Spatrick reg[1] = reg[2] = 0;
4275375f030Spatrick reg[3] = ih->ih_intrpin;
4285375f030Spatrick
429d67371fdSpatrick cookie = arm_intr_establish_fdt_imap_cpu(sc->sc_node, reg,
430d67371fdSpatrick sizeof(reg), level, ci, func, arg, name);
4315375f030Spatrick }
4325375f030Spatrick
4335375f030Spatrick free(ih, M_DEVBUF, sizeof(struct pciecam_intr_handle));
4345375f030Spatrick return cookie;
4355375f030Spatrick }
4365375f030Spatrick
4375375f030Spatrick void
pciecam_intr_disestablish(void * sc,void * cookie)4385375f030Spatrick pciecam_intr_disestablish(void *sc, void *cookie)
4395375f030Spatrick {
4405375f030Spatrick /* do something */
4415375f030Spatrick }
4425375f030Spatrick
4435375f030Spatrick /*
4445375f030Spatrick * Translate memory address if needed.
4455375f030Spatrick */
4465375f030Spatrick int
pciecam_bs_map(void * t,uint64_t bpa,bus_size_t size,int flag,bus_space_handle_t * bshp)4475375f030Spatrick pciecam_bs_map(void *t, uint64_t bpa, bus_size_t size,
4485375f030Spatrick int flag, bus_space_handle_t *bshp)
4495375f030Spatrick {
4505375f030Spatrick struct pciecam_softc *sc = t;
4515375f030Spatrick uint64_t physbase, pcibase, psize;
4525375f030Spatrick int i;
4535375f030Spatrick
4545375f030Spatrick for (i = 0; i < sc->sc_pcirangeslen; i++) {
4555375f030Spatrick physbase = sc->sc_pciranges[i].phys_base;
4565375f030Spatrick pcibase = sc->sc_pciranges[i].pci_base;
4575375f030Spatrick psize = sc->sc_pciranges[i].size;
4585375f030Spatrick
4595375f030Spatrick if (bpa >= pcibase && bpa + size <= pcibase + psize)
4605375f030Spatrick return bus_space_map(sc->sc_iot,
4615375f030Spatrick bpa - pcibase + physbase, size, flag, bshp);
4625375f030Spatrick }
4635375f030Spatrick
4645375f030Spatrick return ENXIO;
4655375f030Spatrick }
466