LCOV - code coverage report
Current view: top level - dev/pci - ehci_pci.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 128 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: ehci_pci.c,v 1.30 2016/07/20 09:48:06 mpi Exp $ */
       2             : /*      $NetBSD: ehci_pci.c,v 1.15 2004/04/23 21:13:06 itojun Exp $     */
       3             : 
       4             : /*
       5             :  * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
       6             :  * All rights reserved.
       7             :  *
       8             :  * This code is derived from software contributed to The NetBSD Foundation
       9             :  * by Lennart Augustsson (lennart@augustsson.net).
      10             :  *
      11             :  * Redistribution and use in source and binary forms, with or without
      12             :  * modification, are permitted provided that the following conditions
      13             :  * are met:
      14             :  * 1. Redistributions of source code must retain the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer.
      16             :  * 2. Redistributions in binary form must reproduce the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer in the
      18             :  *    documentation and/or other materials provided with the distribution.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      21             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      22             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      23             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      24             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      25             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      26             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      27             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      28             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      29             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      30             :  * POSSIBILITY OF SUCH DAMAGE.
      31             :  */
      32             : 
      33             : #include <sys/param.h>
      34             : #include <sys/systm.h>
      35             : #include <sys/kernel.h>
      36             : #include <sys/rwlock.h>
      37             : #include <sys/device.h>
      38             : #include <sys/timeout.h>
      39             : #include <sys/queue.h>
      40             : 
      41             : #include <machine/bus.h>
      42             : 
      43             : #include <dev/pci/pcidevs.h>
      44             : #include <dev/pci/pcivar.h>
      45             : 
      46             : #include <dev/usb/usb.h>
      47             : #include <dev/usb/usbdi.h>
      48             : #include <dev/usb/usbdivar.h>
      49             : #include <dev/usb/usb_mem.h>
      50             : 
      51             : #include <dev/usb/ehcireg.h>
      52             : #include <dev/usb/ehcivar.h>
      53             : 
      54             : #ifdef EHCI_DEBUG
      55             : #define DPRINTF(x)      if (ehcidebug) printf x
      56             : extern int ehcidebug;
      57             : #else
      58             : #define DPRINTF(x)
      59             : #endif
      60             : 
      61             : struct ehci_pci_softc {
      62             :         struct ehci_softc       sc;
      63             :         pci_chipset_tag_t       sc_pc;
      64             :         pcitag_t                sc_tag;
      65             :         void                    *sc_ih;         /* interrupt vectoring */
      66             : };
      67             : 
      68             : int ehci_sb700_match(struct pci_attach_args *pa);
      69             : 
      70             : #define EHCI_SBx00_WORKAROUND_REG       0x50
      71             : #define EHCI_SBx00_WORKAROUND_ENABLE    (1 << 3)
      72             : #define EHCI_VT6202_WORKAROUND_REG      0x48
      73             : 
      74             : int     ehci_pci_match(struct device *, void *, void *);
      75             : void    ehci_pci_attach(struct device *, struct device *, void *);
      76             : int     ehci_pci_detach(struct device *, int);
      77             : int     ehci_pci_activate(struct device *, int);
      78             : #if 0
      79             : void    ehci_pci_givecontroller(struct ehci_pci_softc *);
      80             : #endif
      81             : void    ehci_pci_takecontroller(struct ehci_pci_softc *, int);
      82             : 
      83             : struct cfattach ehci_pci_ca = {
      84             :         sizeof(struct ehci_pci_softc), ehci_pci_match, ehci_pci_attach,
      85             :         ehci_pci_detach, ehci_pci_activate
      86             : };
      87             : 
      88             : int
      89           0 : ehci_pci_match(struct device *parent, void *match, void *aux)
      90             : {
      91           0 :         struct pci_attach_args *pa = (struct pci_attach_args *) aux;
      92             : 
      93           0 :         if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS &&
      94           0 :             PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB &&
      95           0 :             PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI)
      96           0 :                 return (1);
      97             :  
      98           0 :         return (0);
      99           0 : }
     100             : 
     101             : void
     102           0 : ehci_pci_attach(struct device *parent, struct device *self, void *aux)
     103             : {
     104           0 :         struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self;
     105           0 :         struct pci_attach_args *pa = (struct pci_attach_args *)aux;
     106           0 :         pci_chipset_tag_t pc = pa->pa_pc;
     107           0 :         pcitag_t tag = pa->pa_tag;
     108             :         char const *intrstr;
     109           0 :         pci_intr_handle_t ih;
     110             :         const char *vendor;
     111           0 :         char *devname = sc->sc.sc_bus.bdev.dv_xname;
     112             :         usbd_status r;
     113             :         int s;
     114             : 
     115             :         /* Map I/O registers */
     116           0 :         if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
     117           0 :                            &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size, 0)) {
     118           0 :                 printf(": can't map mem space\n");
     119           0 :                 return;
     120             :         }
     121             : 
     122           0 :         sc->sc_pc = pc;
     123           0 :         sc->sc_tag = tag;
     124           0 :         sc->sc.sc_bus.dmatag = pa->pa_dmat;
     125             : 
     126             :         /* Disable interrupts, so we don't get any spurious ones. */
     127           0 :         s = splhardusb();
     128           0 :         sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
     129             :         DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs));
     130           0 :         EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
     131             : 
     132             :         /* Handle quirks */
     133           0 :         switch (PCI_VENDOR(pa->pa_id)) {
     134             :         case PCI_VENDOR_ATI:
     135           0 :                 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB600_EHCI ||
     136           0 :                     (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB700_EHCI &&
     137           0 :                      pci_find_device(NULL, ehci_sb700_match))) {
     138             :                         pcireg_t value;
     139             : 
     140             :                         /* apply the ATI SB600/SB700 workaround */
     141           0 :                         value = pci_conf_read(sc->sc_pc, sc->sc_tag,
     142             :                             EHCI_SBx00_WORKAROUND_REG);
     143           0 :                         pci_conf_write(sc->sc_pc, sc->sc_tag,
     144           0 :                             EHCI_SBx00_WORKAROUND_REG, value |
     145             :                             EHCI_SBx00_WORKAROUND_ENABLE);
     146           0 :                 }
     147             :                 break;
     148             : 
     149             :         case PCI_VENDOR_VIATECH:
     150           0 :                 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT6202 &&
     151           0 :                     (PCI_REVISION(pa->pa_class) & 0xf0) == 0x60) {
     152             :                         pcireg_t value;
     153             : 
     154             :                         /*
     155             :                          * The VT6202 defaults to a 1 usec EHCI sleep time
     156             :                          * which hogs the PCI bus *badly*. Setting bit 5 of
     157             :                          * the register makes that sleep time use the conventional
     158             :                          * 10 usec.
     159             :                          */
     160           0 :                         value = pci_conf_read(sc->sc_pc, sc->sc_tag,
     161             :                             EHCI_VT6202_WORKAROUND_REG);
     162           0 :                         pci_conf_write(sc->sc_pc, sc->sc_tag,
     163           0 :                             EHCI_VT6202_WORKAROUND_REG, value | 0x20000000);
     164           0 :                 }
     165             :                 break;
     166             :         }
     167             : 
     168             :         /* Map and establish the interrupt. */
     169           0 :         if (pci_intr_map(pa, &ih)) {
     170           0 :                 printf(": couldn't map interrupt\n");
     171           0 :                 goto unmap_ret;
     172             :         }
     173           0 :         intrstr = pci_intr_string(pc, ih);
     174           0 :         sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB | IPL_MPSAFE,
     175           0 :             ehci_intr, sc, devname);
     176           0 :         if (sc->sc_ih == NULL) {
     177           0 :                 printf(": couldn't establish interrupt");
     178           0 :                 if (intrstr != NULL)
     179           0 :                         printf(" at %s", intrstr);
     180           0 :                 printf("\n");
     181           0 :                 goto unmap_ret;
     182             :         }
     183           0 :         printf(": %s\n", intrstr);
     184             : 
     185           0 :         switch(pci_conf_read(pc, tag, PCI_USBREV) & PCI_USBREV_MASK) {
     186             :         case PCI_USBREV_PRE_1_0:
     187             :         case PCI_USBREV_1_0:
     188             :         case PCI_USBREV_1_1:
     189           0 :                 sc->sc.sc_bus.usbrev = USBREV_UNKNOWN;
     190           0 :                 printf("%s: pre-2.0 USB rev\n", devname);
     191           0 :                 goto disestablish_ret;
     192             :         case PCI_USBREV_2_0:
     193           0 :                 sc->sc.sc_bus.usbrev = USBREV_2_0;
     194           0 :                 break;
     195             :         default:
     196           0 :                 sc->sc.sc_bus.usbrev = USBREV_UNKNOWN;
     197           0 :                 break;
     198             :         }
     199             : 
     200             :         /* Figure out vendor for root hub descriptor. */
     201           0 :         vendor = pci_findvendor(pa->pa_id);
     202           0 :         sc->sc.sc_id_vendor = PCI_VENDOR(pa->pa_id);
     203           0 :         if (vendor)
     204           0 :                 strlcpy(sc->sc.sc_vendor, vendor, sizeof(sc->sc.sc_vendor));
     205             :         else
     206           0 :                 snprintf(sc->sc.sc_vendor, sizeof(sc->sc.sc_vendor),
     207           0 :                     "vendor 0x%04x", PCI_VENDOR(pa->pa_id));
     208             : 
     209             :         /* Enable workaround for dropped interrupts as required */
     210           0 :         switch (sc->sc.sc_id_vendor) {
     211             :         case PCI_VENDOR_ATI:
     212             :         case PCI_VENDOR_VIATECH:
     213           0 :                 sc->sc.sc_flags |= EHCIF_DROPPED_INTR_WORKAROUND;
     214           0 :                 break;
     215             :         default:
     216             :                 break;
     217             :         }
     218             : 
     219           0 :         ehci_pci_takecontroller(sc, 0);
     220           0 :         r = ehci_init(&sc->sc);
     221           0 :         if (r != USBD_NORMAL_COMPLETION) {
     222           0 :                 printf("%s: init failed, error=%d\n", devname, r);
     223           0 :                 goto disestablish_ret;
     224             :         }
     225             : 
     226             :         /* Attach usb device. */
     227           0 :         config_found(self, &sc->sc.sc_bus, usbctlprint);
     228           0 :         splx(s);
     229           0 :         return;
     230             : 
     231             : disestablish_ret:
     232           0 :         pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
     233             : unmap_ret:
     234           0 :         bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
     235           0 :         splx(s);
     236           0 : }
     237             : 
     238             : int
     239           0 : ehci_pci_activate(struct device *self, int act)
     240             : {
     241           0 :         struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self;
     242             :         int rv;
     243             : 
     244           0 :         switch (act) {
     245             :         case DVACT_RESUME:
     246           0 :                 ehci_pci_takecontroller(sc, 1);
     247           0 :                 break;
     248             :         }
     249             : 
     250           0 :         rv = ehci_activate(self, act);
     251             : 
     252             : #if 0
     253             :         switch (act) {
     254             :         case DVACT_POWERDOWN:
     255             :                 ehci_pci_givecontroller(sc);
     256             :                 break;
     257             :         }
     258             : #endif
     259           0 :         return (rv);
     260             : }
     261             : 
     262             : int
     263           0 : ehci_pci_detach(struct device *self, int flags)
     264             : {
     265           0 :         struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self;
     266             :         int rv;
     267             : 
     268           0 :         rv = ehci_detach(self, flags);
     269           0 :         if (rv)
     270           0 :                 return (rv);
     271           0 :         if (sc->sc_ih != NULL) {
     272           0 :                 pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
     273           0 :                 sc->sc_ih = NULL;
     274           0 :         }
     275           0 :         if (sc->sc.sc_size) {
     276           0 :                 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
     277           0 :                 sc->sc.sc_size = 0;
     278           0 :         }
     279           0 :         return (0);
     280           0 : }
     281             : 
     282             : #if 0
     283             : void
     284             : ehci_pci_givecontroller(struct ehci_pci_softc *sc)
     285             : {
     286             :         u_int32_t cparams, eec, legsup;
     287             :         int eecp;
     288             : 
     289             :         cparams = EREAD4(&sc->sc, EHCI_HCCPARAMS);
     290             :         for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
     291             :             eecp = EHCI_EECP_NEXT(eec)) {
     292             :                 eec = pci_conf_read(sc->sc_pc, sc->sc_tag, eecp);
     293             :                 if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
     294             :                         continue;
     295             :                 legsup = eec;
     296             :                 pci_conf_write(sc->sc_pc, sc->sc_tag, eecp,
     297             :                     legsup & ~EHCI_LEGSUP_OSOWNED);
     298             :         }
     299             : }
     300             : #endif
     301             : 
     302             : void
     303           0 : ehci_pci_takecontroller(struct ehci_pci_softc *sc, int silent)
     304             : {
     305             :         u_int32_t cparams, eec, legsup;
     306             :         int eecp, i;
     307             : 
     308           0 :         cparams = EREAD4(&sc->sc, EHCI_HCCPARAMS);
     309             :         /* Synchronise with the BIOS if it owns the controller. */
     310           0 :         for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
     311           0 :             eecp = EHCI_EECP_NEXT(eec)) {
     312           0 :                 eec = pci_conf_read(sc->sc_pc, sc->sc_tag, eecp);
     313           0 :                 if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
     314             :                         continue;
     315             :                 legsup = eec;
     316           0 :                 if (legsup & EHCI_LEGSUP_BIOSOWNED) {
     317           0 :                         pci_conf_write(sc->sc_pc, sc->sc_tag, eecp,
     318           0 :                             legsup | EHCI_LEGSUP_OSOWNED);
     319             :                         DPRINTF(("%s: waiting for BIOS to give up control\n",
     320             :                             sc->sc.sc_bus.bdev.dv_xname));
     321           0 :                         for (i = 0; i < 5000; i++) {
     322           0 :                                 legsup = pci_conf_read(sc->sc_pc, sc->sc_tag,
     323             :                                     eecp);
     324           0 :                                 if ((legsup & EHCI_LEGSUP_BIOSOWNED) == 0)
     325             :                                         break;
     326           0 :                                 DELAY(1000);
     327             :                         }
     328           0 :                         if (silent == 0 && (legsup & EHCI_LEGSUP_BIOSOWNED))
     329           0 :                                 printf("%s: timed out waiting for BIOS\n",
     330           0 :                                     sc->sc.sc_bus.bdev.dv_xname);
     331             :                 }
     332             :         }
     333           0 : }
     334             : 
     335             : int
     336           0 : ehci_sb700_match(struct pci_attach_args *pa)
     337             : {
     338           0 :         if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI &&
     339           0 :             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SBX00_SMB &&
     340           0 :             (PCI_REVISION(pa->pa_class) == 0x3a ||
     341           0 :              PCI_REVISION(pa->pa_class) == 0x3b))
     342           0 :                 return (1);
     343             : 
     344           0 :         return (0);
     345           0 : }

Generated by: LCOV version 1.13