From owner-p4-projects@FreeBSD.ORG Sat Jul 31 15:40:51 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 1114F1065678; Sat, 31 Jul 2010 15:40:51 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B0CB7106566B for ; Sat, 31 Jul 2010 15:40:50 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 7B1788FC12 for ; Sat, 31 Jul 2010 15:40:50 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.4/8.14.4) with ESMTP id o6VFeoVj083895 for ; Sat, 31 Jul 2010 15:40:50 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.4/8.14.4/Submit) id o6VFeoQt083892 for perforce@freebsd.org; Sat, 31 Jul 2010 15:40:50 GMT (envelope-from hselasky@FreeBSD.org) Date: Sat, 31 Jul 2010 15:40:50 GMT Message-Id: <201007311540.o6VFeoQt083892@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 181650 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 31 Jul 2010 15:40:51 -0000 http://p4web.freebsd.org/@@181650?ac=10 Change 181650 by hselasky@hselasky_laptop001 on 2010/07/31 15:40:35 USB controller (XHCI): - commit the XHCI PCI interface file and update some header file definitions. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#6 edit .. //depot/projects/usb/src/sys/dev/usb/controller/xhci_pci.c#2 edit .. //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#7 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#6 (text+ko) ==== @@ -357,7 +357,7 @@ struct usb_page_cache ctx_pc; struct usb_page root_pg; - sturct usb_page ctx_pg; + struct usb_page ctx_pg; struct xhci_hw_dev devs[XHCI_MAX_DEVICES]; }; @@ -417,4 +417,15 @@ }; +/* prototypes */ + +void xhci_suspend(struct xhci_softc *); +void xhci_resume(struct xhci_softc *); +void xhci_shutdown(struct xhci_softc *); +usb_error_t xhci_init(struct xhci_softc *); +usb_error_t xhci_start_controller(struct xhci_softc *); +void xhci_iterate_hw_softc(struct usb_bus *, usb_bus_mem_sub_cb_t *); +usb_error_t xhci_halt_controller(struct xhci_softc *); +void xhci_interrupt(struct xhci_softc *); + #endif /* _XHCI_H_ */ ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci_pci.c#2 (text+ko) ==== @@ -22,3 +22,296 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/controller/xhci_pci.c $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static device_probe_t xhci_pci_probe; +static device_attach_t xhci_pci_attach; +static device_detach_t xhci_pci_detach; +static device_suspend_t xhci_pci_suspend; +static device_resume_t xhci_pci_resume; +static device_shutdown_t xhci_pci_shutdown; +static void xhci_pci_takecontroller(device_t); + +static device_method_t xhci_device_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, xhci_pci_probe), + DEVMETHOD(device_attach, xhci_pci_attach), + DEVMETHOD(device_detach, xhci_pci_detach), + DEVMETHOD(device_suspend, xhci_pci_suspend), + DEVMETHOD(device_resume, xhci_pci_resume), + DEVMETHOD(device_shutdown, xhci_pci_shutdown), + /* bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + + {0, 0} +}; + +static driver_t xhci_driver = { + .name = "xhci", + .methods = xhci_device_methods, + .size = sizeof(struct xhci_softc), +}; + +static devclass_t xhci_devclass; + +DRIVER_MODULE(xhci, pci, xhci_driver, xhci_devclass, 0, 0); +MODULE_DEPEND(xhci, usb, 1, 1, 1); + +static int +xhci_pci_suspend(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + int err; + + err = bus_generic_suspend(self); + if (err) + return (err); + xhci_suspend(sc); + return (0); +} + +static int +xhci_pci_resume(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + + xhci_pci_takecontroller(self); + xhci_resume(sc); + + bus_generic_resume(self); + + return (0); +} + +static int +xhci_pci_shutdown(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + int err; + + err = bus_generic_shutdown(self); + if (err) + return (err); + xhci_shutdown(sc); + + return (0); +} + +static const char * +xhci_pci_match(device_t self) +{ + if ((pci_get_class(self) == PCIC_SERIALBUS) + && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) + && (pci_get_progif(self) == PCI_INTERFACE_XHCI)) { + return ("XHCI (generic) USB 3.0 controller"); + } + return (NULL); /* dunno */ +} + +static int +xhci_pci_probe(device_t self) +{ + const char *desc = xhci_pci_match(self); + + if (desc) { + device_set_desc(self, desc); + return (0); + } else { + return (ENXIO); + } +} + +static int +xhci_pci_attach(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + int err; + int rid; + + /* initialise some bus fields */ + sc->sc_bus.parent = self; + + /* XXX check for 64-bit capability */ + + if (xhci_init(sc)) { + device_printf(self, "Could not initialize softc\n"); + goto error; + } + + pci_enable_busmaster(self); + + rid = PCI_XHCI_CBMEM; + sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (!sc->sc_io_res) { + device_printf(self, "Could not map memory\n"); + goto error; + } + sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); + sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); + sc->sc_io_size = rman_get_size(sc->sc_io_res); + + rid = 0; + sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + if (sc->sc_irq_res == NULL) { + device_printf(self, "Could not allocate IRQ\n"); + goto error; + } + sc->sc_bus.bdev = device_add_child(self, "usbus", -1); + if (!sc->sc_bus.bdev) { + device_printf(self, "Could not add USB device\n"); + goto error; + } + device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); + + sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self)); + +#if (__FreeBSD_version >= 700031) + err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, + NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); +#else + err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, + (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); +#endif + if (err) { + device_printf(self, "Could not setup IRQ, err=%d\n", err); + sc->sc_intr_hdl = NULL; + goto error; + } + xhci_pci_takecontroller(self); + + err = xhci_halt_controller(sc); + + if (!err) + err = xhci_start_controller(sc); + + if (!err) { + err = device_probe_and_attach(sc->sc_bus.bdev); + } + if (err) { + device_printf(self, "XHCI start failed err=%d\n", err); + goto error; + } + return (0); + +error: + xhci_pci_detach(self); + return (ENXIO); +} + +static int +xhci_pci_detach(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + device_t bdev; + + if (sc->sc_bus.bdev != NULL) { + bdev = sc->sc_bus.bdev; + device_detach(bdev); + device_delete_child(self, bdev); + } + /* during module unload there are lots of children leftover */ + device_delete_all_children(self); + + pci_disable_busmaster(self); + + if (sc->sc_irq_res && sc->sc_intr_hdl) { + + xhci_halt_controller(sc); + + bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); + sc->sc_intr_hdl = NULL; + } + if (sc->sc_irq_res) { + bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); + sc->sc_irq_res = NULL; + } + if (sc->sc_io_res) { + bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, + sc->sc_io_res); + sc->sc_io_res = NULL; + } + usb_bus_mem_free_all(&sc->sc_bus, &xhci_iterate_hw_softc); + + return (0); +} + +static void +xhci_pci_takecontroller(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + uint32_t cparams; + uint32_t eec; + uint16_t to; + uint8_t eecp; + uint8_t bios_sem; + + cparams = XREAD4(sc, capa, XHCI_HCSPARAMS0); + + /* Synchronise with the BIOS if it owns the controller. */ + for (eecp = XHCI_HCS0_XECP(cparams); eecp != 0; + eecp = XHCI_XECP_NEXT(eec)) { + eec = pci_read_config(self, eecp, 4); + if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) + continue; + bios_sem = pci_read_config(self, eecp + + XHCI_XECP_BIOS_SEM, 1); + if (bios_sem == 0) + continue; + device_printf(sc->sc_bus.bdev, "waiting for BIOS " + "to give up control\n"); + pci_write_config(self, eecp + + XHCI_XECP_OS_SEM, 1, 1); + to = 500; + while (1) { + bios_sem = pci_read_config(self, eecp + + XHCI_XECP_BIOS_SEM, 1); + if (bios_sem == 0) + break; + + if (--to == 0) { + device_printf(sc->sc_bus.bdev, + "timed out waiting for BIOS\n"); + break; + } + usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ + } + } +} ==== //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#7 (text+ko) ==== @@ -33,6 +33,7 @@ #define PCI_XHCI_USBREV 0x60 /* RO USB protocol revision */ #define PCI_USB_REV_3_0 0x30 /* USB 3.0 */ #define PCI_XHCI_FLADJ 0x61 /* RW frame length adjust */ +#define PCI_INTERFACE_XHCI 0x30 /* USB 3.0 - XHCI */ /* XHCI capability registers */ #define XHCI_CAPLENGTH 0x00 /* RO capability */ @@ -163,6 +164,7 @@ #define XHCI_IMOD_IVAL_SET(x) (((x) & 0xFFFF) << 0) /* 250ns unit */ #define XHCI_IMOD_ICNT_GET(x) (((x) >> 16) & 0xFFFF) /* 250ns unit */ #define XHCI_IMOD_ICNT_SET(x) (((x) & 0xFFFF) << 16) /* 250ns unit */ +#define XHCI_IMOD_DEFAULT 0x000001F4U /* 8000 IRQ/second */ #define XHCI_ERSTSZ(n) (0x0028 + (0x20 * (n)) /* XHCI event ring segment table size */ #define XHCI_ERSTS_GET(x) ((x) & 0xFFFF) #define XHCI_ERSTS_SET(x) ((x) & 0xFFFF) @@ -180,17 +182,19 @@ #define XHCI_DB_SID_GET(x) (((x) >> 16) & 0xFFFF) /* RW - doorbell stream ID */ #define XHCI_DB_SID_SET(x) (((x) & 0xFFFF) << 16) /* RW - doorbell stream ID */ -/* XHCI interrupter registers. Offset given by XHCI_CAPLENGTH + XHCI_RTSOFF registers */ -#define XHCI_IMAN(i) (0x0020 + (0x20 * (i))) /* RW - interrupt management */ -#define XHCI_IMAN_IP_BIT (1U << 0) /* interrupt pending */ -#define XHCI_IMAN_IE_BIT (1U << 1) /* interrupt enable */ -#define XHCI_IMOD(i) (0x0024 + (0x20 * (i))) /* RW - interrupt moderation */ -#define XHCI_IMOD_DEFAULT 0x000001F4U /* 8000 IRQ/second */ -#define XHCI_ERSTSZ(i) (0x0028 + (0x20 * (i))) /* RW - segment table size */ -#define XHCI_ERSTBA_LO(i) (0x0030 + (0x20 * (i))) /* RW - segment base address */ -#define XHCI_ERSTBA_HI(i) (0x0034 + (0x20 * (i))) /* RW - segment base address */ -#define XHCI_ERDP_LO(i) (0x0038 + (0x20 * (i))) /* RW - dequeue pointer */ -#define XHCI_ERDP_HI(i) (0x003C + (0x20 * (i))) /* RW - dequeue pointer */ +/* XHCI legacy support */ +#define XHCI_XECP_ID(x) ((x) & 0xFF) +#define XHCI_XECP_NEXT(x) (((x) >> 8) & 0xFF) +#define XHCI_XECP_BIOS_SEM 0x0002 +#define XHCI_XECP_OS_SEM 0x0003 + +/* XHCI capability ID's */ +#define XHCI_ID_USB_LEGACY 0x0001 +#define XHCI_ID_PROTOCOLS 0x0002 +#define XHCI_ID_POWER_MGMT 0x0003 +#define XHCI_ID_VIRTUALIZATION 0x0004 +#define XHCI_ID_MSG_IRQ 0x0005 +#define XHCI_ID_USB_LOCAL_MEM 0x0006 /* XHCI register R/W wrappers */ #define XREAD1(sc, what, a) \