[BACK]Return to acpipchb.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / arm / acpi

Annotation of src/sys/arch/arm/acpi/acpipchb.c, Revision 1.25

1.25    ! thorpej     1: /* $NetBSD: acpipchb.c,v 1.24 2021/04/24 23:36:25 thorpej Exp $ */
1.1       jmcneill    2:
                      3: /*-
                      4:  * Copyright (c) 2018 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Jared McNeill <jmcneill@invisible.ca>.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: #include <sys/cdefs.h>
1.25    ! thorpej    33: __KERNEL_RCSID(0, "$NetBSD: acpipchb.c,v 1.24 2021/04/24 23:36:25 thorpej Exp $");
1.1       jmcneill   34:
                     35: #include <sys/param.h>
                     36: #include <sys/bus.h>
                     37: #include <sys/device.h>
                     38: #include <sys/intr.h>
                     39: #include <sys/systm.h>
                     40: #include <sys/kernel.h>
                     41: #include <sys/queue.h>
                     42: #include <sys/mutex.h>
                     43: #include <sys/kmem.h>
1.19      ad         44: #include <sys/cpu.h>
1.1       jmcneill   45:
                     46: #include <arm/cpufunc.h>
                     47:
                     48: #include <dev/pci/pcireg.h>
                     49: #include <dev/pci/pcivar.h>
                     50: #include <dev/pci/pciconf.h>
                     51:
                     52: #include <dev/acpi/acpivar.h>
1.3       jmcneill   53: #include <dev/acpi/acpi_pci.h>
1.1       jmcneill   54: #include <dev/acpi/acpi_mcfg.h>
                     55:
1.2       jmcneill   56: #include <arm/acpi/acpi_pci_machdep.h>
                     57:
1.1       jmcneill   58: #define        PCIHOST_CACHELINE_SIZE          arm_dcache_align
                     59:
1.9       jmcneill   60: #define        ACPIPCHB_MAX_RANGES     64      /* XXX arbitrary limit */
1.7       jmcneill   61:
1.9       jmcneill   62: struct acpipchb_bus_range {
1.7       jmcneill   63:        bus_addr_t              min;
                     64:        bus_addr_t              max;
                     65:        bus_addr_t              offset;
1.9       jmcneill   66: };
                     67:
                     68: struct acpipchb_bus_space {
                     69:        struct bus_space        bs;
                     70:
                     71:        struct acpipchb_bus_range range[ACPIPCHB_MAX_RANGES];
                     72:        int                     nrange;
1.7       jmcneill   73:
                     74:        int                     (*map)(void *, bus_addr_t, bus_size_t,
                     75:                                       int, bus_space_handle_t *);
1.14      jmcneill   76:
                     77:        int                     flags;
1.7       jmcneill   78: };
                     79:
1.1       jmcneill   80: struct acpipchb_softc {
                     81:        device_t                sc_dev;
                     82:
1.9       jmcneill   83:        bus_space_tag_t         sc_memt;
                     84:
1.1       jmcneill   85:        ACPI_HANDLE             sc_handle;
                     86:        ACPI_INTEGER            sc_bus;
1.6       jmcneill   87:
1.9       jmcneill   88:        struct acpipchb_bus_space sc_pcimem_bst;
1.7       jmcneill   89:        struct acpipchb_bus_space sc_pciio_bst;
1.1       jmcneill   90: };
                     91:
                     92: static int     acpipchb_match(device_t, cfdata_t, void *);
                     93: static void    acpipchb_attach(device_t, device_t, void *);
                     94:
1.22      jmcneill   95: static void    acpipchb_setup_ranges(struct acpipchb_softc *,
                     96:                                      struct pcibus_attach_args *);
                     97: static void    acpipchb_setup_quirks(struct acpipchb_softc *,
                     98:                                      struct pcibus_attach_args *);
1.6       jmcneill   99:
1.1       jmcneill  100: CFATTACH_DECL_NEW(acpipchb, sizeof(struct acpipchb_softc),
                    101:        acpipchb_match, acpipchb_attach, NULL, NULL);
                    102:
                    103: static const char * const compatible[] = {
                    104:        "PNP0A08",
                    105:        NULL
                    106: };
                    107:
                    108: static int
                    109: acpipchb_match(device_t parent, cfdata_t cf, void *aux)
                    110: {
                    111:        struct acpi_attach_args *aa = aux;
                    112:
                    113:        if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
                    114:                return 0;
                    115:
                    116:        return acpi_match_hid(aa->aa_node->ad_devinfo, compatible);
                    117: }
                    118:
                    119: static void
                    120: acpipchb_attach(device_t parent, device_t self, void *aux)
                    121: {
                    122:        struct acpipchb_softc * const sc = device_private(self);
                    123:        struct acpi_attach_args *aa = aux;
                    124:        struct pcibus_attach_args pba;
1.15      jmcneill  125:        ACPI_INTEGER seg;
1.22      jmcneill  126:        ACPI_STATUS rv;
1.18      jmcneill  127:        uint16_t bus_start;
1.1       jmcneill  128:
                    129:        sc->sc_dev = self;
1.9       jmcneill  130:        sc->sc_memt = aa->aa_memt;
1.1       jmcneill  131:        sc->sc_handle = aa->aa_node->ad_handle;
                    132:
1.18      jmcneill  133:        /*
                    134:         * First try to derive the base bus number from _CRS. If that fails,
                    135:         * try _BBN. If that fails too, assume bus 0.
                    136:         */
                    137:        if (ACPI_SUCCESS(acpi_pcidev_pciroot_bus(sc->sc_handle, &bus_start))) {
                    138:                sc->sc_bus = bus_start;
                    139:        } else {
1.22      jmcneill  140:                rv = acpi_eval_integer(sc->sc_handle, "_BBN", &sc->sc_bus);
                    141:                if (ACPI_FAILURE(rv)) {
1.18      jmcneill  142:                        sc->sc_bus = 0;
1.22      jmcneill  143:                }
1.18      jmcneill  144:        }
1.1       jmcneill  145:
1.22      jmcneill  146:        if (ACPI_FAILURE(acpi_eval_integer(sc->sc_handle, "_SEG", &seg))) {
1.2       jmcneill  147:                seg = 0;
1.22      jmcneill  148:        }
1.2       jmcneill  149:
1.1       jmcneill  150:        aprint_naive("\n");
                    151:        aprint_normal(": PCI Express Host Bridge\n");
                    152:
1.23      jmcneill  153:        acpi_claim_childdevs(self, aa->aa_node);
                    154:
1.5       jmcneill  155:        if (acpi_pci_ignore_boot_config(sc->sc_handle)) {
1.22      jmcneill  156:                if (acpimcfg_configure_bus(self, aa->aa_pc, sc->sc_handle,
                    157:                    sc->sc_bus, PCIHOST_CACHELINE_SIZE) != 0) {
1.3       jmcneill  158:                        aprint_error_dev(self, "failed to configure bus\n");
1.22      jmcneill  159:                }
1.5       jmcneill  160:        }
1.2       jmcneill  161:
1.1       jmcneill  162:        memset(&pba, 0, sizeof(pba));
1.22      jmcneill  163:        pba.pba_flags = aa->aa_pciflags &
                    164:                        ~(PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY);
1.9       jmcneill  165:        pba.pba_memt = 0;
1.6       jmcneill  166:        pba.pba_iot = 0;
1.17      jmcneill  167:        pba.pba_dmat = aa->aa_dmat;
1.1       jmcneill  168: #ifdef _PCI_HAVE_DMA64
1.17      jmcneill  169:        pba.pba_dmat64 = aa->aa_dmat64;
1.1       jmcneill  170: #endif
1.16      jmcneill  171:        pba.pba_pc = aa->aa_pc;
1.1       jmcneill  172:        pba.pba_bus = sc->sc_bus;
                    173:
1.9       jmcneill  174:        acpipchb_setup_ranges(sc, &pba);
1.16      jmcneill  175:        acpipchb_setup_quirks(sc, &pba);
1.6       jmcneill  176:
1.25    ! thorpej   177:        config_found(self, &pba, pcibusprint,
        !           178:            CFARG_DEVHANDLE, device_handle(self),
        !           179:            CFARG_EOL);
1.1       jmcneill  180: }
1.6       jmcneill  181:
1.9       jmcneill  182: struct acpipchb_setup_ranges_args {
1.6       jmcneill  183:        struct acpipchb_softc *sc;
                    184:        struct pcibus_attach_args *pba;
                    185: };
                    186:
1.7       jmcneill  187: static int
                    188: acpipchb_bus_space_map(void *t, bus_addr_t bpa, bus_size_t size, int flag,
                    189:     bus_space_handle_t *bshp)
                    190: {
                    191:        struct acpipchb_bus_space * const abs = t;
1.9       jmcneill  192:        int i;
1.7       jmcneill  193:
1.9       jmcneill  194:        if (size == 0)
1.7       jmcneill  195:                return ERANGE;
                    196:
1.14      jmcneill  197:        if ((abs->flags & PCI_FLAGS_IO_OKAY) != 0) {
                    198:                /* Force strongly ordered mapping for all I/O space */
                    199:                flag = _ARM_BUS_SPACE_MAP_STRONGLY_ORDERED;
                    200:        }
                    201:
1.9       jmcneill  202:        for (i = 0; i < abs->nrange; i++) {
                    203:                struct acpipchb_bus_range * const range = &abs->range[i];
1.22      jmcneill  204:                if (bpa >= range->min && bpa + size - 1 <= range->max) {
                    205:                        return abs->map(t, bpa + range->offset, size,
                    206:                                        flag, bshp);
                    207:                }
1.9       jmcneill  208:        }
                    209:
                    210:        return ERANGE;
1.7       jmcneill  211: }
                    212:
1.6       jmcneill  213: static ACPI_STATUS
1.9       jmcneill  214: acpipchb_setup_ranges_cb(ACPI_RESOURCE *res, void *ctx)
1.6       jmcneill  215: {
1.9       jmcneill  216:        struct acpipchb_setup_ranges_args * const args = ctx;
1.6       jmcneill  217:        struct acpipchb_softc * const sc = args->sc;
                    218:        struct pcibus_attach_args *pba = args->pba;
1.9       jmcneill  219:        struct acpipchb_bus_space *abs;
                    220:        struct acpipchb_bus_range *range;
                    221:        const char *range_type;
                    222:        u_int pci_flags;
1.6       jmcneill  223:
                    224:        if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
1.22      jmcneill  225:            res->Type != ACPI_RESOURCE_TYPE_ADDRESS64) {
1.6       jmcneill  226:                return AE_OK;
1.22      jmcneill  227:        }
1.6       jmcneill  228:
1.9       jmcneill  229:        switch (res->Data.Address.ResourceType) {
                    230:        case ACPI_IO_RANGE:
                    231:                abs = &sc->sc_pciio_bst;
                    232:                range_type = "I/O";
                    233:                pci_flags = PCI_FLAGS_IO_OKAY;
                    234:                break;
                    235:        case ACPI_MEMORY_RANGE:
                    236:                abs = &sc->sc_pcimem_bst;
                    237:                range_type = "MEM";
                    238:                pci_flags = PCI_FLAGS_MEM_OKAY;
                    239:                break;
                    240:        default:
1.6       jmcneill  241:                return AE_OK;
1.9       jmcneill  242:        }
1.6       jmcneill  243:
1.9       jmcneill  244:        if (abs->nrange == ACPIPCHB_MAX_RANGES) {
                    245:                aprint_error_dev(sc->sc_dev,
1.22      jmcneill  246:                    "maximum number of ranges reached (ACPIPCHB_MAX_RANGES)\n");
1.9       jmcneill  247:                return AE_LIMIT;
                    248:        }
1.6       jmcneill  249:
1.9       jmcneill  250:        range = &abs->range[abs->nrange];
1.6       jmcneill  251:        switch (res->Type) {
                    252:        case ACPI_RESOURCE_TYPE_ADDRESS32:
1.9       jmcneill  253:                range->min = res->Data.Address32.Address.Minimum;
                    254:                range->max = res->Data.Address32.Address.Maximum;
                    255:                range->offset = res->Data.Address32.Address.TranslationOffset;
1.6       jmcneill  256:                break;
                    257:        case ACPI_RESOURCE_TYPE_ADDRESS64:
1.9       jmcneill  258:                range->min = res->Data.Address64.Address.Minimum;
                    259:                range->max = res->Data.Address64.Address.Maximum;
                    260:                range->offset = res->Data.Address64.Address.TranslationOffset;
1.6       jmcneill  261:                break;
1.9       jmcneill  262:        default:
                    263:                return AE_OK;
1.6       jmcneill  264:        }
1.9       jmcneill  265:        abs->nrange++;
1.6       jmcneill  266:
1.22      jmcneill  267:        aprint_debug_dev(sc->sc_dev, "PCI %s [%#lx-%#lx] -> %#lx\n",
                    268:            range_type, range->min, range->max, range->offset);
1.6       jmcneill  269:
1.9       jmcneill  270:        if ((pba->pba_flags & pci_flags) == 0) {
                    271:                abs->bs = *sc->sc_memt;
                    272:                abs->bs.bs_cookie = abs;
                    273:                abs->map = abs->bs.bs_map;
1.14      jmcneill  274:                abs->flags = pci_flags;
1.9       jmcneill  275:                abs->bs.bs_map = acpipchb_bus_space_map;
1.22      jmcneill  276:                if ((pci_flags & PCI_FLAGS_IO_OKAY) != 0) {
1.9       jmcneill  277:                        pba->pba_iot = &abs->bs;
1.22      jmcneill  278:                } else if ((pci_flags & PCI_FLAGS_MEM_OKAY) != 0) {
1.9       jmcneill  279:                        pba->pba_memt = &abs->bs;
1.22      jmcneill  280:                }
1.9       jmcneill  281:                pba->pba_flags |= pci_flags;
                    282:        }
1.6       jmcneill  283:
1.9       jmcneill  284:        return AE_OK;
1.6       jmcneill  285: }
                    286:
                    287: static void
1.9       jmcneill  288: acpipchb_setup_ranges(struct acpipchb_softc *sc, struct pcibus_attach_args *pba)
1.6       jmcneill  289: {
1.9       jmcneill  290:        struct acpipchb_setup_ranges_args args;
1.6       jmcneill  291:
                    292:        args.sc = sc;
                    293:        args.pba = pba;
                    294:
1.22      jmcneill  295:        AcpiWalkResources(sc->sc_handle, "_CRS", acpipchb_setup_ranges_cb,
                    296:            &args);
1.6       jmcneill  297: }
1.16      jmcneill  298:
                    299: static void
                    300: acpipchb_setup_quirks(struct acpipchb_softc *sc, struct pcibus_attach_args *pba)
                    301: {
1.22      jmcneill  302:        struct arm32_pci_chipset *md_pc =
                    303:            (struct arm32_pci_chipset *)pba->pba_pc;
1.16      jmcneill  304:        struct acpi_pci_context *ap = md_pc->pc_conf_v;
                    305:
                    306:        pba->pba_flags &= ~ap->ap_pciflags_clear;
                    307: }

CVSweb <webmaster@jp.NetBSD.org>