PERFORCE change 181650 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sat Jul 31 15:40:51 UTC 2010
http://p4web.freebsd.org/@@181650?ac=10
Change 181650 by hselasky at 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/usb/controller/xhci_pci.c $");
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/linker_set.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/usb_pci.h>
+#include <dev/usb/controller/xhci.h>
+#include <dev/usb/controller/xhcireg.h>
+
+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) \
More information about the p4-projects
mailing list