[BACK]Return to ehci_pci.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / pci

Annotation of src/sys/dev/pci/ehci_pci.c, Revision 1.28

1.28    ! jmcneill    1: /*     $NetBSD: ehci_pci.c,v 1.27 2007/02/09 21:55:27 ad Exp $ */
1.1       augustss    2:
                      3: /*
1.8       augustss    4:  * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
1.1       augustss    5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Lennart Augustsson (lennart@augustsson.net).
                      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:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *        This product includes software developed by the NetBSD
                     21:  *        Foundation, Inc. and its contributors.
                     22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     23:  *    contributors may be used to endorse or promote products derived
                     24:  *    from this software without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     36:  * POSSIBILITY OF SUCH DAMAGE.
                     37:  */
1.6       lukem      38:
                     39: #include <sys/cdefs.h>
1.28    ! jmcneill   40: __KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.27 2007/02/09 21:55:27 ad Exp $");
1.1       augustss   41:
                     42: #include <sys/param.h>
                     43: #include <sys/systm.h>
                     44: #include <sys/kernel.h>
                     45: #include <sys/device.h>
                     46: #include <sys/proc.h>
                     47: #include <sys/queue.h>
                     48:
                     49: #include <machine/bus.h>
                     50:
1.22      xtraeme    51: #include <dev/pci/pcidevs.h>
1.1       augustss   52: #include <dev/pci/pcivar.h>
1.4       augustss   53: #include <dev/pci/usb_pci.h>
1.1       augustss   54:
                     55: #include <dev/usb/usb.h>
                     56: #include <dev/usb/usbdi.h>
                     57: #include <dev/usb/usbdivar.h>
                     58: #include <dev/usb/usb_mem.h>
                     59:
                     60: #include <dev/usb/ehcireg.h>
                     61: #include <dev/usb/ehcivar.h>
                     62:
1.5       augustss   63: #ifdef EHCI_DEBUG
                     64: #define DPRINTF(x)     if (ehcidebug) printf x
                     65: extern int ehcidebug;
                     66: #else
                     67: #define DPRINTF(x)
                     68: #endif
                     69:
1.19      augustss   70: static void ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc,
                     71:                               pcitag_t tag);
1.23      jmcneill   72: static void ehci_pci_powerhook(int, void *);
1.19      augustss   73:
1.1       augustss   74: struct ehci_pci_softc {
                     75:        ehci_softc_t            sc;
                     76:        pci_chipset_tag_t       sc_pc;
                     77:        pcitag_t                sc_tag;
                     78:        void                    *sc_ih;         /* interrupt vectoring */
1.23      jmcneill   79:
                     80:        void                    *sc_powerhook;
                     81:        struct pci_conf_state   sc_pciconf;
1.1       augustss   82: };
                     83:
1.19      augustss   84: #define EHCI_MAX_BIOS_WAIT             1000 /* ms */
                     85:
1.18      thorpej    86: static int
1.26      christos   87: ehci_pci_match(struct device *parent, struct cfdata *match,
1.25      christos   88:     void *aux)
1.1       augustss   89: {
                     90:        struct pci_attach_args *pa = (struct pci_attach_args *) aux;
                     91:
                     92:        if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS &&
                     93:            PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB &&
                     94:            PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI)
                     95:                return (1);
1.17      perry      96:
1.1       augustss   97:        return (0);
                     98: }
                     99:
1.18      thorpej   100: static void
1.26      christos  101: ehci_pci_attach(struct device *parent, struct device *self, void *aux)
1.1       augustss  102: {
                    103:        struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self;
                    104:        struct pci_attach_args *pa = (struct pci_attach_args *)aux;
                    105:        pci_chipset_tag_t pc = pa->pa_pc;
                    106:        pcitag_t tag = pa->pa_tag;
                    107:        char const *intrstr;
                    108:        pci_intr_handle_t ih;
                    109:        pcireg_t csr;
1.16      mycroft   110:        const char *vendor;
                    111:        const char *devname = sc->sc.sc_bus.bdev.dv_xname;
1.1       augustss  112:        char devinfo[256];
                    113:        usbd_status r;
1.5       augustss  114:        int ncomp;
                    115:        struct usb_pci *up;
1.1       augustss  116:
1.13      thorpej   117:        aprint_naive(": USB controller\n");
                    118:
1.15      itojun    119:        pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
1.13      thorpej   120:        aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
                    121:            PCI_REVISION(pa->pa_class));
1.1       augustss  122:
                    123:        /* Map I/O registers */
                    124:        if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
                    125:                           &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) {
1.13      thorpej   126:                aprint_error("%s: can't map memory space\n", devname);
1.1       augustss  127:                return;
                    128:        }
                    129:
                    130:        sc->sc_pc = pc;
                    131:        sc->sc_tag = tag;
                    132:        sc->sc.sc_bus.dmatag = pa->pa_dmat;
                    133:
                    134:        /* Enable the device. */
                    135:        csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
                    136:        pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
                    137:                       csr | PCI_COMMAND_MASTER_ENABLE);
                    138:
1.4       augustss  139:        /* Disable interrupts, so we don't get any spurious ones. */
1.5       augustss  140:        sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
                    141:        DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs));
1.4       augustss  142:        EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
                    143:
1.1       augustss  144:        /* Map and establish the interrupt. */
1.3       sommerfe  145:        if (pci_intr_map(pa, &ih)) {
1.13      thorpej   146:                aprint_error("%s: couldn't map interrupt\n", devname);
1.1       augustss  147:                return;
                    148:        }
                    149:        intrstr = pci_intr_string(pc, ih);
                    150:        sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB, ehci_intr, sc);
                    151:        if (sc->sc_ih == NULL) {
1.13      thorpej   152:                aprint_error("%s: couldn't establish interrupt", devname);
1.1       augustss  153:                if (intrstr != NULL)
1.13      thorpej   154:                        aprint_normal(" at %s", intrstr);
                    155:                aprint_normal("\n");
1.1       augustss  156:                return;
                    157:        }
1.13      thorpej   158:        aprint_normal("%s: interrupting at %s\n", devname, intrstr);
1.1       augustss  159:
                    160:        switch(pci_conf_read(pc, tag, PCI_USBREV) & PCI_USBREV_MASK) {
                    161:        case PCI_USBREV_PRE_1_0:
                    162:        case PCI_USBREV_1_0:
                    163:        case PCI_USBREV_1_1:
1.4       augustss  164:                sc->sc.sc_bus.usbrev = USBREV_UNKNOWN;
1.27      ad        165:                aprint_verbose("%s: pre-2.0 USB rev\n", devname);
1.4       augustss  166:                return;
1.1       augustss  167:        case PCI_USBREV_2_0:
                    168:                sc->sc.sc_bus.usbrev = USBREV_2_0;
                    169:                break;
                    170:        default:
                    171:                sc->sc.sc_bus.usbrev = USBREV_UNKNOWN;
                    172:                break;
                    173:        }
                    174:
                    175:        /* Figure out vendor for root hub descriptor. */
                    176:        vendor = pci_findvendor(pa->pa_id);
                    177:        sc->sc.sc_id_vendor = PCI_VENDOR(pa->pa_id);
                    178:        if (vendor)
1.14      itojun    179:                strlcpy(sc->sc.sc_vendor, vendor, sizeof(sc->sc.sc_vendor));
1.1       augustss  180:        else
1.14      itojun    181:                snprintf(sc->sc.sc_vendor, sizeof(sc->sc.sc_vendor),
                    182:                    "vendor 0x%04x", PCI_VENDOR(pa->pa_id));
1.17      perry     183:
1.22      xtraeme   184:        /* Enable workaround for dropped interrupts as required */
                    185:        if (sc->sc.sc_id_vendor == PCI_VENDOR_VIATECH)
                    186:                sc->sc.sc_flags |= EHCIF_DROPPED_INTR_WORKAROUND;
                    187:
1.5       augustss  188:        /*
                    189:         * Find companion controllers.  According to the spec they always
                    190:         * have lower function numbers so they should be enumerated already.
                    191:         */
                    192:        ncomp = 0;
                    193:        TAILQ_FOREACH(up, &ehci_pci_alldevs, next) {
                    194:                if (up->bus == pa->pa_bus && up->device == pa->pa_device) {
                    195:                        DPRINTF(("ehci_pci_attach: companion %s\n",
                    196:                                 USBDEVNAME(up->usb->bdev)));
                    197:                        sc->sc.sc_comps[ncomp++] = up->usb;
                    198:                        if (ncomp >= EHCI_COMPANION_MAX)
                    199:                                break;
                    200:                }
                    201:        }
                    202:        sc->sc.sc_ncomp = ncomp;
                    203:
1.19      augustss  204:        ehci_get_ownership(&sc->sc, pc, tag);
                    205:
1.1       augustss  206:        r = ehci_init(&sc->sc);
                    207:        if (r != USBD_NORMAL_COMPLETION) {
1.13      thorpej   208:                aprint_error("%s: init failed, error=%d\n", devname, r);
1.1       augustss  209:                return;
                    210:        }
                    211:
1.24      jmcneill  212:        sc->sc_powerhook = powerhook_establish(
                    213:            USBDEVNAME(sc->sc.sc_bus.bdev) , ehci_pci_powerhook, sc);
1.23      jmcneill  214:        if (sc->sc_powerhook == NULL)
                    215:                aprint_error("%s: couldn't establish powerhook\n",
                    216:                    devname);
                    217:
1.1       augustss  218:        /* Attach usb device. */
                    219:        sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus,
                    220:                                       usbctlprint);
                    221: }
                    222:
1.18      thorpej   223: static int
1.1       augustss  224: ehci_pci_detach(device_ptr_t self, int flags)
                    225: {
                    226:        struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self;
                    227:        int rv;
                    228:
1.23      jmcneill  229:        if (sc->sc_powerhook != NULL)
                    230:                powerhook_disestablish(sc->sc_powerhook);
                    231:
1.1       augustss  232:        rv = ehci_detach(&sc->sc, flags);
                    233:        if (rv)
                    234:                return (rv);
                    235:        if (sc->sc_ih != NULL) {
                    236:                pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
                    237:                sc->sc_ih = NULL;
                    238:        }
                    239:        if (sc->sc.sc_size) {
                    240:                bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
                    241:                sc->sc.sc_size = 0;
                    242:        }
                    243:        return (0);
                    244: }
1.18      thorpej   245:
                    246: CFATTACH_DECL(ehci_pci, sizeof(struct ehci_pci_softc),
                    247:     ehci_pci_match, ehci_pci_attach, ehci_pci_detach, ehci_activate);
1.19      augustss  248:
                    249: #ifdef EHCI_DEBUG
                    250: static void
                    251: ehci_dump_caps(ehci_softc_t *sc, pci_chipset_tag_t pc, pcitag_t tag)
                    252: {
                    253:        u_int32_t cparams, legctlsts, addr, cap, id;
                    254:        int maxdump = 10;
                    255:
                    256:        cparams = EREAD4(sc, EHCI_HCCPARAMS);
                    257:        addr = EHCI_HCC_EECP(cparams);
                    258:        while (addr != 0) {
                    259:                cap = pci_conf_read(pc, tag, addr);
                    260:                id = EHCI_CAP_GET_ID(cap);
                    261:                switch (id) {
                    262:                case EHCI_CAP_ID_LEGACY:
                    263:                        legctlsts = pci_conf_read(pc, tag,
                    264:                                                  addr + PCI_EHCI_USBLEGCTLSTS);
1.20      augustss  265:                        printf("ehci_dump_caps: legsup=0x%08x "
                    266:                               "legctlsts=0x%08x\n", cap, legctlsts);
1.19      augustss  267:                        break;
                    268:                default:
1.20      augustss  269:                        printf("ehci_dump_caps: cap=0x%08x\n", cap);
1.19      augustss  270:                        break;
                    271:                }
                    272:                if (--maxdump < 0)
                    273:                        break;
                    274:                addr = EHCI_CAP_GET_NEXT(cap);
                    275:        }
                    276: }
                    277: #endif
                    278:
                    279: static void
                    280: ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, pcitag_t tag)
                    281: {
                    282:        const char *devname = sc->sc_bus.bdev.dv_xname;
                    283:        u_int32_t cparams, addr, cap, legsup;
                    284:        int maxcap = 10;
                    285:        int ms;
                    286:
                    287: #ifdef EHCI_DEBUG
1.20      augustss  288:        if (ehcidebug)
                    289:                ehci_dump_caps(sc, pc, tag);
1.19      augustss  290: #endif
                    291:        cparams = EREAD4(sc, EHCI_HCCPARAMS);
                    292:        addr = EHCI_HCC_EECP(cparams);
                    293:        while (addr != 0) {
                    294:                cap = pci_conf_read(pc, tag, addr);
                    295:                if (EHCI_CAP_GET_ID(cap) == EHCI_CAP_ID_LEGACY)
                    296:                        break;
1.21      augustss  297:                if (--maxcap < 0) {
                    298:                        aprint_normal("%s: broken extended capabilities "
                    299:                                      "ignored\n", devname);
1.19      augustss  300:                        return;
1.21      augustss  301:                }
1.19      augustss  302:                addr = EHCI_CAP_GET_NEXT(cap);
                    303:        }
                    304:
1.28    ! jmcneill  305:        /* If the USB legacy capability is not specified, we are done */
        !           306:        if (addr == 0)
        !           307:                return;
        !           308:
1.19      augustss  309:        legsup = pci_conf_read(pc, tag, addr + PCI_EHCI_USBLEGSUP);
                    310:        /* Ask BIOS to give up ownership */
                    311:        legsup |= EHCI_LEG_HC_OS_OWNED;
                    312:        pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGSUP, legsup);
                    313:        for (ms = 0; ms < EHCI_MAX_BIOS_WAIT; ms++) {
                    314:                legsup = pci_conf_read(pc, tag, addr + PCI_EHCI_USBLEGSUP);
                    315:                if (!(legsup & EHCI_LEG_HC_BIOS_OWNED))
                    316:                        break;
                    317:                delay(1000);
                    318:        }
                    319:        if (ms == EHCI_MAX_BIOS_WAIT) {
                    320:                aprint_normal("%s: BIOS refuses to give up ownership, "
                    321:                              "using force\n", devname);
                    322:                pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGSUP, 0);
                    323:                pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGCTLSTS, 0);
                    324:        } else {
1.27      ad        325:                aprint_verbose("%s: BIOS has given up ownership\n", devname);
1.19      augustss  326:        }
                    327: }
1.23      jmcneill  328:
                    329: static void
                    330: ehci_pci_powerhook(int why, void *opaque)
                    331: {
                    332:        struct ehci_pci_softc *sc;
                    333:        pci_chipset_tag_t pc;
                    334:        pcitag_t tag;
                    335:
                    336:        sc = (struct ehci_pci_softc *)opaque;
                    337:        pc = sc->sc_pc;
                    338:        tag = sc->sc_tag;
                    339:
                    340:        switch (why) {
                    341:        case PWR_STANDBY:
                    342:        case PWR_SUSPEND:
                    343:                pci_conf_capture(pc, tag, &sc->sc_pciconf);
                    344:                break;
                    345:        case PWR_RESUME:
                    346:                pci_conf_restore(pc, tag, &sc->sc_pciconf);
                    347:                ehci_get_ownership(&sc->sc, pc, tag);
                    348:                break;
                    349:        }
                    350:
                    351:        return;
                    352: }

CVSweb <webmaster@jp.NetBSD.org>