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