[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.21.2.1

1.21.2.1! thorpej     1: /* $NetBSD: acpipchb.c,v 1.22 2020/12/06 12:40:58 jmcneill 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.21.2.1! thorpej    33: __KERNEL_RCSID(0, "$NetBSD: acpipchb.c,v 1.22 2020/12/06 12:40:58 jmcneill 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.21.2.1! thorpej    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.21.2.1! thorpej   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.21.2.1! thorpej   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.21.2.1! thorpej   143:                }
1.18      jmcneill  144:        }
1.1       jmcneill  145:
1.21.2.1! thorpej   146:        if (ACPI_FAILURE(acpi_eval_integer(sc->sc_handle, "_SEG", &seg))) {
1.2       jmcneill  147:                seg = 0;
1.21.2.1! thorpej   148:        }
1.2       jmcneill  149:
1.1       jmcneill  150:        aprint_naive("\n");
                    151:        aprint_normal(": PCI Express Host Bridge\n");
                    152:
1.5       jmcneill  153:        if (acpi_pci_ignore_boot_config(sc->sc_handle)) {
1.21.2.1! thorpej   154:                if (acpimcfg_configure_bus(self, aa->aa_pc, sc->sc_handle,
        !           155:                    sc->sc_bus, PCIHOST_CACHELINE_SIZE) != 0) {
1.3       jmcneill  156:                        aprint_error_dev(self, "failed to configure bus\n");
1.21.2.1! thorpej   157:                }
1.5       jmcneill  158:        }
1.2       jmcneill  159:
1.1       jmcneill  160:        memset(&pba, 0, sizeof(pba));
1.21.2.1! thorpej   161:        pba.pba_flags = aa->aa_pciflags &
        !           162:                        ~(PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY);
1.9       jmcneill  163:        pba.pba_memt = 0;
1.6       jmcneill  164:        pba.pba_iot = 0;
1.17      jmcneill  165:        pba.pba_dmat = aa->aa_dmat;
1.1       jmcneill  166: #ifdef _PCI_HAVE_DMA64
1.17      jmcneill  167:        pba.pba_dmat64 = aa->aa_dmat64;
1.1       jmcneill  168: #endif
1.16      jmcneill  169:        pba.pba_pc = aa->aa_pc;
1.1       jmcneill  170:        pba.pba_bus = sc->sc_bus;
                    171:
1.9       jmcneill  172:        acpipchb_setup_ranges(sc, &pba);
1.16      jmcneill  173:        acpipchb_setup_quirks(sc, &pba);
1.6       jmcneill  174:
1.1       jmcneill  175:        config_found_ia(self, "pcibus", &pba, pcibusprint);
                    176: }
1.6       jmcneill  177:
1.9       jmcneill  178: struct acpipchb_setup_ranges_args {
1.6       jmcneill  179:        struct acpipchb_softc *sc;
                    180:        struct pcibus_attach_args *pba;
                    181: };
                    182:
1.7       jmcneill  183: static int
                    184: acpipchb_bus_space_map(void *t, bus_addr_t bpa, bus_size_t size, int flag,
                    185:     bus_space_handle_t *bshp)
                    186: {
                    187:        struct acpipchb_bus_space * const abs = t;
1.9       jmcneill  188:        int i;
1.7       jmcneill  189:
1.9       jmcneill  190:        if (size == 0)
1.7       jmcneill  191:                return ERANGE;
                    192:
1.14      jmcneill  193:        if ((abs->flags & PCI_FLAGS_IO_OKAY) != 0) {
                    194:                /* Force strongly ordered mapping for all I/O space */
                    195:                flag = _ARM_BUS_SPACE_MAP_STRONGLY_ORDERED;
                    196:        }
                    197:
1.9       jmcneill  198:        for (i = 0; i < abs->nrange; i++) {
                    199:                struct acpipchb_bus_range * const range = &abs->range[i];
1.21.2.1! thorpej   200:                if (bpa >= range->min && bpa + size - 1 <= range->max) {
        !           201:                        return abs->map(t, bpa + range->offset, size,
        !           202:                                        flag, bshp);
        !           203:                }
1.9       jmcneill  204:        }
                    205:
                    206:        return ERANGE;
1.7       jmcneill  207: }
                    208:
1.6       jmcneill  209: static ACPI_STATUS
1.9       jmcneill  210: acpipchb_setup_ranges_cb(ACPI_RESOURCE *res, void *ctx)
1.6       jmcneill  211: {
1.9       jmcneill  212:        struct acpipchb_setup_ranges_args * const args = ctx;
1.6       jmcneill  213:        struct acpipchb_softc * const sc = args->sc;
                    214:        struct pcibus_attach_args *pba = args->pba;
1.9       jmcneill  215:        struct acpipchb_bus_space *abs;
                    216:        struct acpipchb_bus_range *range;
                    217:        const char *range_type;
                    218:        u_int pci_flags;
1.6       jmcneill  219:
                    220:        if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
1.21.2.1! thorpej   221:            res->Type != ACPI_RESOURCE_TYPE_ADDRESS64) {
1.6       jmcneill  222:                return AE_OK;
1.21.2.1! thorpej   223:        }
1.6       jmcneill  224:
1.9       jmcneill  225:        switch (res->Data.Address.ResourceType) {
                    226:        case ACPI_IO_RANGE:
                    227:                abs = &sc->sc_pciio_bst;
                    228:                range_type = "I/O";
                    229:                pci_flags = PCI_FLAGS_IO_OKAY;
                    230:                break;
                    231:        case ACPI_MEMORY_RANGE:
                    232:                abs = &sc->sc_pcimem_bst;
                    233:                range_type = "MEM";
                    234:                pci_flags = PCI_FLAGS_MEM_OKAY;
                    235:                break;
                    236:        default:
1.6       jmcneill  237:                return AE_OK;
1.9       jmcneill  238:        }
1.6       jmcneill  239:
1.9       jmcneill  240:        if (abs->nrange == ACPIPCHB_MAX_RANGES) {
                    241:                aprint_error_dev(sc->sc_dev,
1.21.2.1! thorpej   242:                    "maximum number of ranges reached (ACPIPCHB_MAX_RANGES)\n");
1.9       jmcneill  243:                return AE_LIMIT;
                    244:        }
1.6       jmcneill  245:
1.9       jmcneill  246:        range = &abs->range[abs->nrange];
1.6       jmcneill  247:        switch (res->Type) {
                    248:        case ACPI_RESOURCE_TYPE_ADDRESS32:
1.9       jmcneill  249:                range->min = res->Data.Address32.Address.Minimum;
                    250:                range->max = res->Data.Address32.Address.Maximum;
                    251:                range->offset = res->Data.Address32.Address.TranslationOffset;
1.6       jmcneill  252:                break;
                    253:        case ACPI_RESOURCE_TYPE_ADDRESS64:
1.9       jmcneill  254:                range->min = res->Data.Address64.Address.Minimum;
                    255:                range->max = res->Data.Address64.Address.Maximum;
                    256:                range->offset = res->Data.Address64.Address.TranslationOffset;
1.6       jmcneill  257:                break;
1.9       jmcneill  258:        default:
                    259:                return AE_OK;
1.6       jmcneill  260:        }
1.9       jmcneill  261:        abs->nrange++;
1.6       jmcneill  262:
1.21.2.1! thorpej   263:        aprint_debug_dev(sc->sc_dev, "PCI %s [%#lx-%#lx] -> %#lx\n",
        !           264:            range_type, range->min, range->max, range->offset);
1.6       jmcneill  265:
1.9       jmcneill  266:        if ((pba->pba_flags & pci_flags) == 0) {
                    267:                abs->bs = *sc->sc_memt;
                    268:                abs->bs.bs_cookie = abs;
                    269:                abs->map = abs->bs.bs_map;
1.14      jmcneill  270:                abs->flags = pci_flags;
1.9       jmcneill  271:                abs->bs.bs_map = acpipchb_bus_space_map;
1.21.2.1! thorpej   272:                if ((pci_flags & PCI_FLAGS_IO_OKAY) != 0) {
1.9       jmcneill  273:                        pba->pba_iot = &abs->bs;
1.21.2.1! thorpej   274:                } else if ((pci_flags & PCI_FLAGS_MEM_OKAY) != 0) {
1.9       jmcneill  275:                        pba->pba_memt = &abs->bs;
1.21.2.1! thorpej   276:                }
1.9       jmcneill  277:                pba->pba_flags |= pci_flags;
                    278:        }
1.6       jmcneill  279:
1.9       jmcneill  280:        return AE_OK;
1.6       jmcneill  281: }
                    282:
                    283: static void
1.9       jmcneill  284: acpipchb_setup_ranges(struct acpipchb_softc *sc, struct pcibus_attach_args *pba)
1.6       jmcneill  285: {
1.9       jmcneill  286:        struct acpipchb_setup_ranges_args args;
1.6       jmcneill  287:
                    288:        args.sc = sc;
                    289:        args.pba = pba;
                    290:
1.21.2.1! thorpej   291:        AcpiWalkResources(sc->sc_handle, "_CRS", acpipchb_setup_ranges_cb,
        !           292:            &args);
1.6       jmcneill  293: }
1.16      jmcneill  294:
                    295: static void
                    296: acpipchb_setup_quirks(struct acpipchb_softc *sc, struct pcibus_attach_args *pba)
                    297: {
1.21.2.1! thorpej   298:        struct arm32_pci_chipset *md_pc =
        !           299:            (struct arm32_pci_chipset *)pba->pba_pc;
1.16      jmcneill  300:        struct acpi_pci_context *ap = md_pc->pc_conf_v;
                    301:
                    302:        pba->pba_flags &= ~ap->ap_pciflags_clear;
                    303: }

CVSweb <webmaster@jp.NetBSD.org>