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

1.28.2.1! skrll       1: /*     $NetBSD: ehci_pci.c,v 1.30 2007/08/04 10:36:06 tsutsui 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.2.1! skrll      40: __KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.30 2007/08/04 10:36:06 tsutsui 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 */
1.28.2.1! skrll     185:        switch (sc->sc.sc_id_vendor) {
        !           186:        case PCI_VENDOR_ATI:
        !           187:        case PCI_VENDOR_VIATECH:
1.22      xtraeme   188:                sc->sc.sc_flags |= EHCIF_DROPPED_INTR_WORKAROUND;
1.28.2.1! skrll     189:                aprint_normal("%s: dropped intr workaround enabled\n", devname);
        !           190:                break;
        !           191:        default:
        !           192:                break;
        !           193:        }
1.22      xtraeme   194:
1.5       augustss  195:        /*
                    196:         * Find companion controllers.  According to the spec they always
                    197:         * have lower function numbers so they should be enumerated already.
                    198:         */
                    199:        ncomp = 0;
                    200:        TAILQ_FOREACH(up, &ehci_pci_alldevs, next) {
                    201:                if (up->bus == pa->pa_bus && up->device == pa->pa_device) {
                    202:                        DPRINTF(("ehci_pci_attach: companion %s\n",
                    203:                                 USBDEVNAME(up->usb->bdev)));
                    204:                        sc->sc.sc_comps[ncomp++] = up->usb;
                    205:                        if (ncomp >= EHCI_COMPANION_MAX)
                    206:                                break;
                    207:                }
                    208:        }
                    209:        sc->sc.sc_ncomp = ncomp;
                    210:
1.19      augustss  211:        ehci_get_ownership(&sc->sc, pc, tag);
                    212:
1.28.2.1! skrll     213:        /*
        !           214:         * Establish our powerhook before ehci_init() does its powerhook.
        !           215:         */
1.24      jmcneill  216:        sc->sc_powerhook = powerhook_establish(
                    217:            USBDEVNAME(sc->sc.sc_bus.bdev) , ehci_pci_powerhook, sc);
1.23      jmcneill  218:        if (sc->sc_powerhook == NULL)
                    219:                aprint_error("%s: couldn't establish powerhook\n",
                    220:                    devname);
                    221:
1.28.2.1! skrll     222:        r = ehci_init(&sc->sc);
        !           223:        if (r != USBD_NORMAL_COMPLETION) {
        !           224:                aprint_error("%s: init failed, error=%d\n", devname, r);
        !           225:                return;
        !           226:        }
        !           227:
1.1       augustss  228:        /* Attach usb device. */
                    229:        sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus,
                    230:                                       usbctlprint);
                    231: }
                    232:
1.18      thorpej   233: static int
1.1       augustss  234: ehci_pci_detach(device_ptr_t self, int flags)
                    235: {
                    236:        struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self;
                    237:        int rv;
                    238:
1.23      jmcneill  239:        if (sc->sc_powerhook != NULL)
                    240:                powerhook_disestablish(sc->sc_powerhook);
                    241:
1.1       augustss  242:        rv = ehci_detach(&sc->sc, flags);
                    243:        if (rv)
                    244:                return (rv);
                    245:        if (sc->sc_ih != NULL) {
                    246:                pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
                    247:                sc->sc_ih = NULL;
                    248:        }
                    249:        if (sc->sc.sc_size) {
                    250:                bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
                    251:                sc->sc.sc_size = 0;
                    252:        }
                    253:        return (0);
                    254: }
1.18      thorpej   255:
                    256: CFATTACH_DECL(ehci_pci, sizeof(struct ehci_pci_softc),
                    257:     ehci_pci_match, ehci_pci_attach, ehci_pci_detach, ehci_activate);
1.19      augustss  258:
                    259: #ifdef EHCI_DEBUG
                    260: static void
                    261: ehci_dump_caps(ehci_softc_t *sc, pci_chipset_tag_t pc, pcitag_t tag)
                    262: {
                    263:        u_int32_t cparams, legctlsts, addr, cap, id;
                    264:        int maxdump = 10;
                    265:
                    266:        cparams = EREAD4(sc, EHCI_HCCPARAMS);
                    267:        addr = EHCI_HCC_EECP(cparams);
                    268:        while (addr != 0) {
                    269:                cap = pci_conf_read(pc, tag, addr);
                    270:                id = EHCI_CAP_GET_ID(cap);
                    271:                switch (id) {
                    272:                case EHCI_CAP_ID_LEGACY:
                    273:                        legctlsts = pci_conf_read(pc, tag,
                    274:                                                  addr + PCI_EHCI_USBLEGCTLSTS);
1.20      augustss  275:                        printf("ehci_dump_caps: legsup=0x%08x "
                    276:                               "legctlsts=0x%08x\n", cap, legctlsts);
1.19      augustss  277:                        break;
                    278:                default:
1.20      augustss  279:                        printf("ehci_dump_caps: cap=0x%08x\n", cap);
1.19      augustss  280:                        break;
                    281:                }
                    282:                if (--maxdump < 0)
                    283:                        break;
                    284:                addr = EHCI_CAP_GET_NEXT(cap);
                    285:        }
                    286: }
                    287: #endif
                    288:
                    289: static void
                    290: ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, pcitag_t tag)
                    291: {
                    292:        const char *devname = sc->sc_bus.bdev.dv_xname;
                    293:        u_int32_t cparams, addr, cap, legsup;
                    294:        int maxcap = 10;
                    295:        int ms;
                    296:
                    297: #ifdef EHCI_DEBUG
1.20      augustss  298:        if (ehcidebug)
                    299:                ehci_dump_caps(sc, pc, tag);
1.19      augustss  300: #endif
                    301:        cparams = EREAD4(sc, EHCI_HCCPARAMS);
                    302:        addr = EHCI_HCC_EECP(cparams);
                    303:        while (addr != 0) {
                    304:                cap = pci_conf_read(pc, tag, addr);
                    305:                if (EHCI_CAP_GET_ID(cap) == EHCI_CAP_ID_LEGACY)
                    306:                        break;
1.21      augustss  307:                if (--maxcap < 0) {
                    308:                        aprint_normal("%s: broken extended capabilities "
                    309:                                      "ignored\n", devname);
1.19      augustss  310:                        return;
1.21      augustss  311:                }
1.19      augustss  312:                addr = EHCI_CAP_GET_NEXT(cap);
                    313:        }
                    314:
1.28      jmcneill  315:        /* If the USB legacy capability is not specified, we are done */
                    316:        if (addr == 0)
                    317:                return;
                    318:
1.19      augustss  319:        legsup = pci_conf_read(pc, tag, addr + PCI_EHCI_USBLEGSUP);
                    320:        /* Ask BIOS to give up ownership */
                    321:        legsup |= EHCI_LEG_HC_OS_OWNED;
                    322:        pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGSUP, legsup);
                    323:        for (ms = 0; ms < EHCI_MAX_BIOS_WAIT; ms++) {
                    324:                legsup = pci_conf_read(pc, tag, addr + PCI_EHCI_USBLEGSUP);
                    325:                if (!(legsup & EHCI_LEG_HC_BIOS_OWNED))
                    326:                        break;
                    327:                delay(1000);
                    328:        }
                    329:        if (ms == EHCI_MAX_BIOS_WAIT) {
                    330:                aprint_normal("%s: BIOS refuses to give up ownership, "
                    331:                              "using force\n", devname);
                    332:                pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGSUP, 0);
                    333:                pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGCTLSTS, 0);
                    334:        } else {
1.27      ad        335:                aprint_verbose("%s: BIOS has given up ownership\n", devname);
1.19      augustss  336:        }
                    337: }
1.23      jmcneill  338:
                    339: static void
                    340: ehci_pci_powerhook(int why, void *opaque)
                    341: {
                    342:        struct ehci_pci_softc *sc;
                    343:        pci_chipset_tag_t pc;
                    344:        pcitag_t tag;
                    345:
                    346:        sc = (struct ehci_pci_softc *)opaque;
                    347:        pc = sc->sc_pc;
                    348:        tag = sc->sc_tag;
                    349:
                    350:        switch (why) {
                    351:        case PWR_STANDBY:
                    352:        case PWR_SUSPEND:
                    353:                pci_conf_capture(pc, tag, &sc->sc_pciconf);
                    354:                break;
                    355:        case PWR_RESUME:
                    356:                pci_conf_restore(pc, tag, &sc->sc_pciconf);
                    357:                ehci_get_ownership(&sc->sc, pc, tag);
                    358:                break;
                    359:        }
                    360:
                    361:        return;
                    362: }

CVSweb <webmaster@jp.NetBSD.org>