From b68f2fb9e73f46037fbeca5fbd4ae8a7ddd8ef6b Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 27 Jul 2009 10:58:08 +0100 Subject: tty: Fix a USB serial crash/scribble The port lock is used to protect the port state. However the port structure is freed on a hangup, then the lock taken on a close. The right fix is to drop the port on tty->shutdown() but we can't yet do that due to sleep v non-sleeping rules. Instead do the next best thing and fix it up when we are not in -rc season. Reported-by: Daniel Mack Signed-off-by: Alan Cox Tested-by: Daniel Mack Signed-off-by: Linus Torvalds --- drivers/usb/serial/usb-serial.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index bd7581b3a48..3c8923f62ed 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -340,6 +340,22 @@ static void serial_close(struct tty_struct *tty, struct file *filp) dbg("%s - port %d", __func__, port->number); + /* FIXME: + This leaves a very narrow race. Really we should do the + serial_do_free() on tty->shutdown(), but tty->shutdown can + be called from IRQ context and serial_do_free can sleep. + + The right fix is probably to make the tty free (which is rare) + and thus tty->shutdown() occur via a work queue and simplify all + the drivers that use it. + */ + if (tty_hung_up_p(filp)) { + /* serial_hangup already called serial_down at this point. + Another user may have already reopened the port but + serial_do_free is refcounted */ + serial_do_free(port); + return; + } if (tty_port_close_start(&port->port, tty, filp) == 0) return; @@ -355,7 +371,8 @@ static void serial_hangup(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; serial_do_down(port); tty_port_hangup(&port->port); - serial_do_free(port); + /* We must not free port yet - the USB serial layer depends on it's + continued existence */ } static int serial_write(struct tty_struct *tty, const unsigned char *buf, -- cgit v1.2.3 From c56d300086140c93dc3390e5300fd17df802ec0e Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 28 Jul 2009 00:34:58 +0100 Subject: usb_serial: Fix remaining ref count/lock bugs This fixes - locking bug that was hidden by ecc2e05e739c30870c8e4f252b63a0c4041f2724 - Regression #13821 - Spurious warning when closing and blocking for data write out With these changes my PL2303 always ends up as ttyUSB0 when it should and the module refcounts stay correct. I'll do a more wholesale split & tidy of _open in the next release or two as we get a standard tty_port_open and port->ops->init port->ops->shutdown call backs. Copy sent to Alan Stern and Carlos Mafra just to confirm it fixes all the reports but it passes local testing with the same hardware as Alan Stern. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/usb/serial/usb-serial.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 3c8923f62ed..99188c92068 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include "pl2303.h" @@ -184,6 +185,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp) struct usb_serial_port *port; unsigned int portNumber; int retval = 0; + int first = 0; dbg("%s", __func__); @@ -223,7 +225,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp) /* If the console is attached, the device is already open */ if (port->port.count == 1 && !port->console) { - + first = 1; /* lock this module before we call it * this may fail, which means we must bail out, * safe because we are called with BKL held */ @@ -246,13 +248,21 @@ static int serial_open (struct tty_struct *tty, struct file *filp) if (retval) goto bailout_interface_put; mutex_unlock(&serial->disc_mutex); + set_bit(ASYNCB_INITIALIZED, &port->port.flags); } mutex_unlock(&port->mutex); /* Now do the correct tty layer semantics */ retval = tty_port_block_til_ready(&port->port, tty, filp); - if (retval == 0) + if (retval == 0) { + if (!first) + usb_serial_put(serial); return 0; - + } + mutex_lock(&port->mutex); + if (first == 0) + goto bailout_mutex_unlock; + /* Undo the initial port actions */ + mutex_lock(&serial->disc_mutex); bailout_interface_put: usb_autopm_put_interface(serial->interface); bailout_module_put: @@ -411,7 +421,6 @@ static int serial_chars_in_buffer(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; dbg("%s = port %d", __func__, port->number); - WARN_ON(!port->port.count); /* if the device was unplugged then any remaining characters fell out of the connector ;) */ if (port->serial->disconnected) -- cgit v1.2.3 From f99aa3f9b67ca8c29dc29ef3fc453f0343206c46 Mon Sep 17 00:00:00 2001 From: "Carlos R. Mafra" Date: Mon, 13 Jul 2009 21:45:03 +0200 Subject: USB: option: Remove unused variable After commit f092c240494f2d807401d93f95f683909b90af96 ("USB: option: remove unnecessary and erroneous code") the variable 'serial' becomes unused, as gcc-4.3.2 points out: drivers/usb/serial/option.c: In function 'option_instat_callback': drivers/usb/serial/option.c:834: warning: unused variable 'serial' drivers/usb/serial/option.c: In function 'option_open': drivers/usb/serial/option.c:930: warning: unused variable 'serial' So I removed it. Signed-off-by: Carlos R. Mafra Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 98262dd552b..77b9563ec43 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -831,7 +831,6 @@ static void option_instat_callback(struct urb *urb) int status = urb->status; struct usb_serial_port *port = urb->context; struct option_port_private *portdata = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; dbg("%s", __func__); dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata); @@ -927,7 +926,6 @@ static int option_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp) { struct option_port_private *portdata; - struct usb_serial *serial = port->serial; int i, err; struct urb *urb; -- cgit v1.2.3 From 5f4fab91f2b12c12f0506b4da49ed199db8c64ed Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 13 Jul 2009 23:24:10 +0200 Subject: USB: let the option driver compile without CONFIG_PM This is needed for compilation without CONFIG_PM. Signed-off-by: Oliver Neukum Acked-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 77b9563ec43..7638d2632ff 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -66,8 +66,10 @@ static int option_tiocmget(struct tty_struct *tty, struct file *file); static int option_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static int option_send_setup(struct usb_serial_port *port); +#ifdef CONFIG_PM static int option_suspend(struct usb_serial *serial, pm_message_t message); static int option_resume(struct usb_serial *serial); +#endif /* Vendor and product IDs */ #define OPTION_VENDOR_ID 0x0AF0 @@ -555,8 +557,10 @@ static struct usb_driver option_driver = { .name = "option", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, +#ifdef CONFIG_PM .suspend = usb_serial_suspend, .resume = usb_serial_resume, +#endif .id_table = option_ids, .no_dynamic_id = 1, }; @@ -588,8 +592,10 @@ static struct usb_serial_driver option_1port_device = { .disconnect = option_disconnect, .release = option_release, .read_int_callback = option_instat_callback, +#ifdef CONFIG_PM .suspend = option_suspend, .resume = option_resume, +#endif }; static int debug; @@ -1185,6 +1191,7 @@ static void option_release(struct usb_serial *serial) } } +#ifdef CONFIG_PM static int option_suspend(struct usb_serial *serial, pm_message_t message) { dbg("%s entered", __func__); @@ -1243,6 +1250,7 @@ static int option_resume(struct usb_serial *serial) } return 0; } +#endif MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -- cgit v1.2.3 From 7a777919bbeec3eac1d7904a728a60e9c2bb9c67 Mon Sep 17 00:00:00 2001 From: Giacomo Lozito Date: Mon, 13 Jul 2009 23:23:33 +0200 Subject: USB: storage: raise timeout in usb_stor_Bulk_max_lun Requests to get max LUN, for certain USB storage devices, require a longer timeout before a correct reply is returned. This happens for a Realtek USB Card Reader (0bda:0152), which has a max LUN of 3 but is set to 0, thus losing functionality, because of the timeout occurring too quickly. Raising the timeout value fixes the issue and might help other devices to return a correct max LUN value as well. Signed-off-by: Giacomo Lozito Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index fcb32021721..e20dc525d17 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -961,7 +961,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us) US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, us->iobuf, 1, HZ); + 0, us->ifnum, us->iobuf, 1, 10*HZ); US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", result, us->iobuf[0]); -- cgit v1.2.3 From 715bfc22ce952a14fac0b9200fd70d81c1951091 Mon Sep 17 00:00:00 2001 From: Anand Gadiyar Date: Tue, 14 Jul 2009 16:41:00 +0530 Subject: USB: OMAP: OHCI: hc_driver's stop method should call ohci_stop OMAP: OHCI: hc_driver's stop method should call ohci_stop Without this, the ohci-omap driver will not cleanup the debugfs nodes when the driver is unloaded. So the next insmod will fail, if CONFIG_DEBUG_FS and CONFIG_USB_DEBUG are both selected. Reported-by: vikram pandita Cc: David Brownell Signed-off-by: Anand Gadiyar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-omap.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index f3aaba35e91..83cbecd2a1e 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -282,6 +282,7 @@ static int ohci_omap_init(struct usb_hcd *hcd) static void ohci_omap_stop(struct usb_hcd *hcd) { dev_dbg(hcd->self.controller, "stopping USB Controller\n"); + ohci_stop(hcd); omap_ohci_clock_power(0); } -- cgit v1.2.3 From fca4404c55ab44c7413769f1d9c66451103711a5 Mon Sep 17 00:00:00 2001 From: Ville Sundberg Date: Wed, 15 Jul 2009 00:27:28 +0300 Subject: USB: ftdi_sio: Add support for GN Otometrics Aurical USB Audiometer The patch adds support for the GN Otometrics Aurical USB Audiometer (FT232BM-based). A new VID and a new PID is added. Signed-off-by: Ville Sundberg Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 60c64cc5be2..b574878c78b 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -698,6 +698,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, + { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index c9fbd741509..24dbd99e87d 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -946,6 +946,13 @@ #define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */ +/* + * GN Otometrics (http://www.otometrics.com) + * Submitted by Ville Sundberg. + */ +#define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */ +#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */ + /* * BmRequestType: 1100 0000b * bRequest: FTDI_E2_READ -- cgit v1.2.3 From 8bf16ba7c8ea9d067914e270764c14020a26232f Mon Sep 17 00:00:00 2001 From: Craig Shelley Date: Sun, 12 Jul 2009 21:52:33 +0100 Subject: USB: CP210x Add new device IDs Signed-off-by: Craig Shelley Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index e9a40b820fd..985cbcf48bd 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -80,6 +80,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */ { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ + { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */ { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ @@ -96,7 +97,9 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */ { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ + { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */ { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ + { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ -- cgit v1.2.3 From bcfa4e68d8d0ea617bde4203b2b3848f5a49a423 Mon Sep 17 00:00:00 2001 From: Simon Kagstrom Date: Mon, 13 Jul 2009 08:25:09 +0200 Subject: USB: ehci-orion: Call ehci_reset before ehci_halt I noticed that USB initialization didn't setup correctly on my kirkwood based board (OpenRD base) if I hadn't initialized USB in U-boot first. The error message looks like this: ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver orion-ehci orion-ehci.0: Marvell Orion EHCI orion-ehci orion-ehci.0: new USB bus registered, assigned bus number 1 orion-ehci orion-ehci.0: can't setup orion-ehci orion-ehci.0: USB bus 1 deregistered orion-ehci orion-ehci.0: init orion-ehci.0 fail, -110 orion-ehci: probe of orion-ehci.0 failed with error -110 which is caused by ehci_halt() timing out in the handshake() call. I noticed that U-boot does a reset before calling handshake(), so this patch does the same thing for Linux. USB now works for me. Signed-off-by: Simon Kagstrom Acked-by: Nicolas Pitre Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-orion.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index dc2ac613a9d..1d283e1b2b8 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -105,6 +105,7 @@ static int ehci_orion_setup(struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; + ehci_reset(ehci); retval = ehci_halt(ehci); if (retval) return retval; @@ -118,7 +119,6 @@ static int ehci_orion_setup(struct usb_hcd *hcd) hcd->has_tt = 1; - ehci_reset(ehci); ehci_port_power(ehci, 0); return retval; -- cgit v1.2.3 From c420befde6b2747ebc2b8f015687a5dbd6e167ca Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Wed, 15 Jul 2009 17:10:26 -0300 Subject: USB: option: add ZTE device ids and remove ONDA ids Current listed Onda ids are ZTE devices. Replace them with ZTE id define and add more ZTE device ids. Also remove 19d2:2000, this is the id when device is first plugged in and is a CD-only device, before the switch using eject. These changes are based on a previous patch by Ming Zhao Signed-off-by: Herton Ronaldo Krzesinski Cc: Ming Zhao Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 113 ++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 45 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 7638d2632ff..5640f38fdb3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -261,11 +261,6 @@ static int option_resume(struct usb_serial *serial); #define AXESSTEL_VENDOR_ID 0x1726 #define AXESSTEL_PRODUCT_MV110H 0x1000 -#define ONDA_VENDOR_ID 0x19d2 -#define ONDA_PRODUCT_MSA501HS 0x0001 -#define ONDA_PRODUCT_ET502HS 0x0002 -#define ONDA_PRODUCT_MT503HS 0x2000 - #define BANDRICH_VENDOR_ID 0x1A8D #define BANDRICH_PRODUCT_C100_1 0x1002 #define BANDRICH_PRODUCT_C100_2 0x1003 @@ -476,42 +471,6 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, { USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) }, - { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MSA501HS) }, - { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_ET502HS) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0003) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0004) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0005) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0006) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0007) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0008) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0009) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x000a) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x000b) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x000c) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x000d) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x000e) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x000f) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0010) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0011) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0012) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0013) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0014) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0015) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0016) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0017) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0018) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0019) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0020) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0021) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0022) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0023) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0024) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0025) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0026) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0027) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0028) }, - { USB_DEVICE(ONDA_VENDOR_ID, 0x0029) }, - { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MT503HS) }, { USB_DEVICE(YISO_VENDOR_ID, YISO_PRODUCT_U893) }, { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) }, { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) }, @@ -536,10 +495,74 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ { USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, - { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622) }, - { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) }, - { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) }, - { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0006, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0007, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0008, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0009, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000a, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000b, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000c, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000d, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000e, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000f, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0026, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0069, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0076, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0078, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0082, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */ + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0060, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) }, -- cgit v1.2.3 From f1469fc3ef1d5a8a67146c1c72021f012a59dea6 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Fri, 17 Jul 2009 07:55:36 -0600 Subject: USB: option: Add USB ID for Novatel MC727/U727/USB727 refresh BugLink: https://bugs.launchpad.net/bugs/365291 Signed-off-by: Tim Gardner Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5640f38fdb3..ff61f89918e 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -207,6 +207,7 @@ static int option_resume(struct usb_serial *serial); #define NOVATELWIRELESS_PRODUCT_MC727 0x4100 #define NOVATELWIRELESS_PRODUCT_MC950D 0x4400 #define NOVATELWIRELESS_PRODUCT_U727 0x5010 +#define NOVATELWIRELESS_PRODUCT_MC727_NEW 0x5100 #define NOVATELWIRELESS_PRODUCT_MC760 0x6000 #define NOVATELWIRELESS_PRODUCT_OVMC760 0x6002 @@ -435,6 +436,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU870D) }, /* Novatel EU850D/EU860D/EU870D */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727_NEW) }, /* Novatel MC727/U727/USB727 refresh */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC760) }, /* Novatel MC760/U760/USB760 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_OVMC760) }, /* Novatel Ovation MC760 */ -- cgit v1.2.3 From 9d498beafc0a66ce333f0d9067af0aa5dedd4c8e Mon Sep 17 00:00:00 2001 From: Russell Lang Date: Fri, 17 Jul 2009 19:29:20 +1000 Subject: USB: aten uc2324 is really a moschip 7840 I've opened up the case, and the chips in the ATEN UC2324 are: Moschip MCS7840CV-AA 69507-6B1 0650 (USB to 4-port serial) (logo with AF kerned together) 0748 24BC02 SINGLP (unknown 8-pin chip) (logo looks like 3 or Z in circle) ZT3243LEEA 0752 B7A16420.T (4 chips, so this will be RS232 line driver) (Probably equivalent of Sipex SP3243) So the ATEN 2324 (aten2011.c driver), is definitely the Moschip 7840, and should use the mos7840.c driver. I expect you will remove the aten2011.c driver from the staging area. From the aten2011.c source code, the device ID for the UC2322 (2 port serial) is 0x7820, just like the Moschip evaluation board. This value should be added to the device id table of mos7840.c. Here's a patch that adds these devices to the driver. From: Russell Lang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c31940a307f..270009afdf7 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -124,10 +124,13 @@ #define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 #define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 -/* This driver also supports the ATEN UC2324 device since it is mos7840 based - * - if I knew the device id it would also support the ATEN UC2322 */ +/* This driver also supports + * ATEN UC2324 device using Moschip MCS7840 + * ATEN UC2322 device using Moschip MCS7820 + */ #define USB_VENDOR_ID_ATENINTL 0x0557 #define ATENINTL_DEVICE_ID_UC2324 0x2011 +#define ATENINTL_DEVICE_ID_UC2322 0x7820 /* Interrupt Routine Defines */ @@ -177,6 +180,7 @@ static struct usb_device_id moschip_port_id_table[] = { {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, + {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */ }; @@ -186,6 +190,7 @@ static __devinitdata struct usb_device_id moschip_id_table_combined[] = { {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, + {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */ }; -- cgit v1.2.3 From 183791588efd416fc35a71819683b32dee92615b Mon Sep 17 00:00:00 2001 From: Peng Huang Date: Wed, 22 Jul 2009 11:54:48 +0200 Subject: USB: serial: option: Add ZTE AC8710 usb modem device. Signed-off-by: Peng Huang Cc: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ff61f89918e..b6de085bc78 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -299,6 +299,7 @@ static int option_resume(struct usb_serial *serial); #define ZTE_PRODUCT_MF628 0x0015 #define ZTE_PRODUCT_MF626 0x0031 #define ZTE_PRODUCT_CDMA_TECH 0xfffe +#define ZTE_PRODUCT_AC8710 0xfff1 #define BENQ_VENDOR_ID 0x04a5 #define BENQ_PRODUCT_H10 0x4068 @@ -565,6 +566,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) }, -- cgit v1.2.3 From 48c348cc939aaa3a07d4938669f2f315152e895e Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Thu, 23 Jul 2009 04:03:43 +0200 Subject: USB: option.c to support Alcatel X060S/X200 broadband modems Added support for the Alcatel X060S/X200 broadband modems to the option driver. The device starts in cd-rom emulation mode (1bbb:f000) and requires the use of the usb_modeswitch tool to switch it to modem mode (1bbb:0000). Signed-off-by: Javier Martin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index b6de085bc78..c784ddbe7b6 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -321,6 +321,11 @@ static int option_resume(struct usb_serial *serial); #define ALINK_VENDOR_ID 0x1e0e #define ALINK_PRODUCT_3GU 0x9200 +/* ALCATEL PRODUCTS */ +#define ALCATEL_VENDOR_ID 0x1bbb +#define ALCATEL_PRODUCT_X060S 0x0000 + + static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -576,6 +581,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); -- cgit v1.2.3 From f01b017d198486ee3553bee6841f788263cf2c23 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 17 Jul 2009 17:30:03 +0300 Subject: USB: musb_gadget_ep0: fix typo in service_zero_data_request() This function uses wrong bit mask to prevent clearing RXCSR status bits when halting an endpoint -- which results in clearing SentStall and RxPktRdy bits (that the code actually tries to avoid); must be a result of cut-and-paste... Signed-off-by: Sergei Shtylyov Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_gadget_ep0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 40ed50ecedf..7a6778675ad 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -407,7 +407,7 @@ stall: csr |= MUSB_RXCSR_P_SENDSTALL | MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_CLRDATATOG - | MUSB_TXCSR_P_WZC_BITS; + | MUSB_RXCSR_P_WZC_BITS; musb_writew(regs, MUSB_RXCSR, csr); } -- cgit v1.2.3 From 3a9f5bd82dc986d496d8484ff54b107b4515f43f Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Mon, 27 Jul 2009 12:03:19 +0300 Subject: USB: musb: Refer to musb_otg_timer_func under correct #ifdef musb_otg_timer_func() is defined under #ifdef CONFIG_USB_MUSB_OTG. Make sure any reference to it is also under the same #ifdef. Without this fix, the driver failes to compile when USB_OTG is defined but USB_MUSB_OTG isn't. Signed-off-by: Amit Kucheria Cc: Felipe Balbi Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 554a414f65d..642a4e25f7d 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1990,7 +1990,7 @@ bad_config: if (status < 0) goto fail2; -#ifdef CONFIG_USB_OTG +#ifdef CONFIG_USB_MUSB_OTG setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb); #endif -- cgit v1.2.3 From 2bbff7b742d55b094ed1467702efe146cd60c64f Mon Sep 17 00:00:00 2001 From: Ajay Kumar Gupta Date: Mon, 27 Jul 2009 14:32:15 -0700 Subject: USB: musb: fix CONFIGDATA register read issue INDEX register has to be set to '0' before reading CONFIGDATA register which is only present in TI musb platforms. Currently the default register access mode is set to FLAT_MODE thus INDEX register is not getting set properly with musb_ep_select() which is just a nop operation in FLAT_MODE.This invalid register read is causing module reinset failure. Fixing the issue by moving INDEX register write part to musb_read_configdata() function itself. Signed-off-by: Vikram Pandita Signed-off-by: Anand Gadiyar Signed-off-by: Ajay Kumar Gupta Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 1 - drivers/usb/musb/musb_regs.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 642a4e25f7d..c7c1ca0494c 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1326,7 +1326,6 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) int i; /* log core options (read using indexed model) */ - musb_ep_select(mbase, 0); reg = musb_read_configdata(mbase); strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8"); diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index de3b2f18db4..fbfd3fd9ce1 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -323,6 +323,7 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off) static inline u8 musb_read_configdata(void __iomem *mbase) { + musb_writeb(mbase, MUSB_INDEX, 0); return musb_readb(mbase, 0x10 + MUSB_CONFIGDATA); } -- cgit v1.2.3 From 0f157ef3a1284f41d9804ecb87fdcc8ea946b9fa Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 28 Jul 2009 11:56:17 -0400 Subject: USB: usbtest: no need for USB_DEVICEFS THis patch (as1270) allows the usbtest module to be built even when USB_DEVICEFS isn't configured. Tests can be performed without USB_DEVICEFS, using the /dev/bus/usb/*/* device files. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a68d91a11be..abe3aa67ed0 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -220,7 +220,7 @@ config USB_IOWARRIOR config USB_TEST tristate "USB testing driver" - depends on USB && USB_DEVICEFS + depends on USB help This driver is for testing host controller software. It is used with specialized device firmware for regression and stress testing, -- cgit v1.2.3 From d8f1a5ed52a81a953918d4aebe185ba008a7be34 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 13 Jul 2009 00:23:47 +0200 Subject: USB: xhci: fix less- and greater than confusion Without this change the loops won't start Signed-off-by: Roel Kluin Cc: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 2501c571f85..56032f2d84e 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -419,7 +419,7 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_ad &ctx->add_flags, (unsigned long long)dma, ctx->add_flags); dma += field_size; - for (i = 0; i > 6; ++i) { + for (i = 0; i < 6; ++i) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", &ctx->rsvd[i], (unsigned long long)dma, ctx->rsvd[i], i); @@ -443,7 +443,7 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_ad &ctx->slot.dev_state, (unsigned long long)dma, ctx->slot.dev_state); dma += field_size; - for (i = 0; i > 4; ++i) { + for (i = 0; i < 4; ++i) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", &ctx->slot.reserved[i], (unsigned long long)dma, ctx->slot.reserved[i], i); -- cgit v1.2.3 From f9dc68fe7ad390428c6bc5d7ff582cdb5d92fcb8 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:07 -0700 Subject: USB: xhci: Set TD size in transfer TRB. The 0.95 xHCI specification requires software to set the "TD size" field in each transaction request block (TRB). This field gives the host controller an indication of how much data is remaining in the TD (including the buffer in the current TRB). Set this field in bulk TRBs and data stage TRBs for control transfers. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 02d81985c45..d5b95299742 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1285,6 +1285,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Queue the first TRB, even if it's zero-length */ do { u32 field = 0; + u32 length_field = 0; /* Don't change the cycle bit of the first TRB until later */ if (first_trb) @@ -1314,10 +1315,13 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), (unsigned int) addr + trb_buff_len); } + length_field = TRB_LEN(trb_buff_len) | + TD_REMAINDER(urb->transfer_buffer_length - running_total) | + TRB_INTR_TARGET(0); queue_trb(xhci, ep_ring, false, (u32) addr, (u32) ((u64) addr >> 32), - TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0), + length_field, /* We always want to know if the TRB was short, * or we won't get an event when it completes. * (Unless we use event data TRBs, which are a @@ -1365,7 +1369,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct xhci_generic_trb *start_trb; bool first_trb; int start_cycle; - u32 field; + u32 field, length_field; int running_total, trb_buff_len, ret; u64 addr; @@ -1443,10 +1447,13 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, td->last_trb = ep_ring->enqueue; field |= TRB_IOC; } + length_field = TRB_LEN(trb_buff_len) | + TD_REMAINDER(urb->transfer_buffer_length - running_total) | + TRB_INTR_TARGET(0); queue_trb(xhci, ep_ring, false, (u32) addr, (u32) ((u64) addr >> 32), - TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0), + length_field, /* We always want to know if the TRB was short, * or we won't get an event when it completes. * (Unless we use event data TRBs, which are a @@ -1478,7 +1485,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct usb_ctrlrequest *setup; struct xhci_generic_trb *start_trb; int start_cycle; - u32 field; + u32 field, length_field; struct xhci_td *td; ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; @@ -1528,13 +1535,16 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* If there's data, queue data TRBs */ field = 0; + length_field = TRB_LEN(urb->transfer_buffer_length) | + TD_REMAINDER(urb->transfer_buffer_length) | + TRB_INTR_TARGET(0); if (urb->transfer_buffer_length > 0) { if (setup->bRequestType & USB_DIR_IN) field |= TRB_DIR_IN; queue_trb(xhci, ep_ring, false, lower_32_bits(urb->transfer_dma), upper_32_bits(urb->transfer_dma), - TRB_LEN(urb->transfer_buffer_length) | TRB_INTR_TARGET(0), + length_field, /* Event on short tx */ field | TRB_ISP | TRB_TYPE(TRB_DATA) | ep_ring->cycle_state); } -- cgit v1.2.3 From a1587d97ce3e53816c88b513a2038f6c5e5babd7 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:15 -0700 Subject: USB: xhci: Deal with stalled endpoints. When an endpoint on a device under an xHCI host controller stalls, the host controller driver must let the hardware know that the USB core has successfully cleared the halt condition. The HCD submits a Reset Endpoint Command, which will clear the toggle bit for USB 2.0 devices, and set the sequence number to zero for USB 3.0 devices. The xHCI urb_enqueue will accept new URBs while the endpoint is halted, and will queue them to the hardware rings. However, the endpoint doorbell will not be rung until the Reset Endpoint Command completes. Don't queue a reset endpoint command for root hubs. khubd clears halt conditions on the roothub during the initialization process, but the roothub isn't a real device, so the xHCI host controller doesn't need to know about the cleared halt. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 44 +++++++++++++++++++++++++++++++++++++++++++- drivers/usb/host/xhci-pci.c | 1 + drivers/usb/host/xhci-ring.c | 36 +++++++++++++++++++++++++++++++++++- drivers/usb/host/xhci.h | 8 ++++++-- 4 files changed, 85 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index dba3e07ccd0..1c5901ad6eb 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -787,8 +787,11 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, int ret = 0; ret = xhci_check_args(hcd, udev, ep, 1, __func__); - if (ret <= 0) + if (ret <= 0) { + /* So we won't queue a reset ep command for a root hub */ + ep->hcpriv = NULL; return ret; + } xhci = hcd_to_xhci(hcd); added_ctxs = xhci_get_endpoint_flag(&ep->desc); @@ -851,6 +854,9 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, } new_slot_info = in_ctx->slot.dev_info; + /* Store the usb_device pointer for later use */ + ep->hcpriv = udev; + xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", (unsigned int) ep->desc.bEndpointAddress, udev->slot_id, @@ -1026,6 +1032,42 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) xhci_zero_in_ctx(virt_dev); } +/* Deal with stalled endpoints. The core should have sent the control message + * to clear the halt condition. However, we need to make the xHCI hardware + * reset its sequence number, since a device will expect a sequence number of + * zero after the halt condition is cleared. + * Context: in_interrupt + */ +void xhci_endpoint_reset(struct usb_hcd *hcd, + struct usb_host_endpoint *ep) +{ + struct xhci_hcd *xhci; + struct usb_device *udev; + unsigned int ep_index; + unsigned long flags; + int ret; + + xhci = hcd_to_xhci(hcd); + udev = (struct usb_device *) ep->hcpriv; + /* Called with a root hub endpoint (or an endpoint that wasn't added + * with xhci_add_endpoint() + */ + if (!ep->hcpriv) + return; + ep_index = xhci_get_endpoint_index(&ep->desc); + + xhci_dbg(xhci, "Queueing reset endpoint command\n"); + spin_lock_irqsave(&xhci->lock, flags); + ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index); + if (!ret) { + xhci_ring_cmd_db(xhci); + } + spin_unlock_irqrestore(&xhci->lock, flags); + + if (ret) + xhci_warn(xhci, "FIXME allocate a new ring segment\n"); +} + /* * At this point, the struct usb_device is about to go away, the device has * disconnected, and all traffic has been stopped and the endpoints have been diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 1462709e26c..592fe7e623f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -117,6 +117,7 @@ static const struct hc_driver xhci_pci_hc_driver = { .free_dev = xhci_free_dev, .add_endpoint = xhci_add_endpoint, .drop_endpoint = xhci_drop_endpoint, + .endpoint_reset = xhci_endpoint_reset, .check_bandwidth = xhci_check_bandwidth, .reset_bandwidth = xhci_reset_bandwidth, .address_device = xhci_address_device, diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index d5b95299742..d672ba14ff8 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -279,7 +279,8 @@ static void ring_ep_doorbell(struct xhci_hcd *xhci, /* Don't ring the doorbell for this endpoint if there are pending * cancellations because the we don't want to interrupt processing. */ - if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING)) { + if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING) + && !(ep_ring->state & EP_HALTED)) { field = xhci_readl(xhci, db_addr) & DB_MASK; xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr); /* Flush PCI posted writes - FIXME Matthew Wilcox says this @@ -603,6 +604,25 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, ring_ep_doorbell(xhci, slot_id, ep_index); } +static void handle_reset_ep_completion(struct xhci_hcd *xhci, + struct xhci_event_cmd *event, + union xhci_trb *trb) +{ + int slot_id; + unsigned int ep_index; + + slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); + ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); + /* This command will only fail if the endpoint wasn't halted, + * but we don't care. + */ + xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n", + (unsigned int) GET_COMP_CODE(event->status)); + + /* Clear our internal halted state and restart the ring */ + xhci->devs[slot_id]->ep_rings[ep_index]->state &= ~EP_HALTED; + ring_ep_doorbell(xhci, slot_id, ep_index); +} static void handle_cmd_completion(struct xhci_hcd *xhci, struct xhci_event_cmd *event) @@ -653,6 +673,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, case TRB_TYPE(TRB_CMD_NOOP): ++xhci->noops_handled; break; + case TRB_TYPE(TRB_RESET_EP): + handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue); + break; default: /* Skip over unknown commands on the event ring */ xhci->error_bitmask |= 1 << 6; @@ -823,6 +846,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, break; case COMP_STALL: xhci_warn(xhci, "WARN: Stalled endpoint\n"); + ep_ring->state |= EP_HALTED; status = -EPIPE; break; case COMP_TRB_ERR: @@ -1656,3 +1680,13 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, return queue_command(xhci, (u32) addr | cycle_state, 0, 0, trb_slot_id | trb_ep_index | type); } + +int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, + unsigned int ep_index) +{ + u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); + u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); + u32 type = TRB_TYPE(TRB_RESET_EP); + + return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type); +} diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8936eeb5588..cde648a524f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -848,8 +848,8 @@ union xhci_trb { #define TRB_CONFIG_EP 12 /* Evaluate Context Command */ #define TRB_EVAL_CONTEXT 13 -/* Reset Transfer Ring Command */ -#define TRB_RESET_RING 14 +/* Reset Endpoint Command */ +#define TRB_RESET_EP 14 /* Stop Transfer Ring Command */ #define TRB_STOP_RING 15 /* Set Transfer Ring Dequeue Pointer Command */ @@ -929,6 +929,7 @@ struct xhci_ring { unsigned int cancels_pending; unsigned int state; #define SET_DEQ_PENDING (1 << 0) +#define EP_HALTED (1 << 1) /* The TRB that was last reported in a stopped endpoint ring */ union xhci_trb *stopped_trb; struct xhci_td *stopped_td; @@ -1128,6 +1129,7 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); +void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep); int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); @@ -1148,6 +1150,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index); int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id); +int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, + unsigned int ep_index); /* xHCI roothub code */ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, -- cgit v1.2.3 From b11069f5f6ce6e359f853e908b0917303fcdec8f Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:23 -0700 Subject: USB: xhci: Use GFP_ATOMIC while holding spinlocks. The xHCI functions to queue an URB onto the hardware rings must be called with the xhci spinlock held. Those functions will allocate memory, and take a gfp_t memory flags argument. We must pass them the GFP_ATOMIC flag, since we don't want the memory allocation to attempt to sleep while waiting for more memory to become available. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 1c5901ad6eb..ff99365cae4 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -601,10 +601,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) goto exit; } if (usb_endpoint_xfer_control(&urb->ep->desc)) - ret = xhci_queue_ctrl_tx(xhci, mem_flags, urb, + /* We have a spinlock and interrupts disabled, so we must pass + * atomic context to this function, which may allocate memory. + */ + ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) - ret = xhci_queue_bulk_tx(xhci, mem_flags, urb, + ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); else ret = -EINVAL; -- cgit v1.2.3 From 8e595a5d30a5ee4bb745d4da6439d73ed7d91054 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:31 -0700 Subject: USB: xhci: Represent 64-bit addresses with one u64. There are several xHCI data structures that use two 32-bit fields to represent a 64-bit address. Since some architectures don't support 64-bit PCI writes, the fields need to be written in two 32-bit writes. The xHCI specification says that if a platform is incapable of generating 64-bit writes, software must write the low 32-bits first, then the high 32-bits. Hardware that supports 64-bit addressing will wait for the high 32-bit write before reading the revised value, and hardware that only supports 32-bit writes will ignore the high 32-bit write. Previous xHCI code represented 64-bit addresses with two u32 values. This lead to buggy code that would write the 32-bits in the wrong order, or forget to write the upper 32-bits. Change the two u32s to one u64 and create a function call to write all 64-bit addresses in the proper order. This new function could be modified in the future if all platforms support 64-bit writes. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbg.c | 67 +++++++++++++++++--------------------------- drivers/usb/host/xhci-hcd.c | 43 +++++++++++++--------------- drivers/usb/host/xhci-mem.c | 61 ++++++++++++++++------------------------ drivers/usb/host/xhci-ring.c | 49 +++++++++++++++----------------- drivers/usb/host/xhci.h | 65 +++++++++++++++++++++++++++++------------- 5 files changed, 137 insertions(+), 148 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 56032f2d84e..6d62e4abe3c 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -173,6 +173,7 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int { void *addr; u32 temp; + u64 temp_64; addr = &ir_set->irq_pending; temp = xhci_readl(xhci, addr); @@ -200,25 +201,15 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int xhci_dbg(xhci, " WARN: %p: ir_set.rsvd = 0x%x\n", addr, (unsigned int)temp); - addr = &ir_set->erst_base[0]; - temp = xhci_readl(xhci, addr); - xhci_dbg(xhci, " %p: ir_set.erst_base[0] = 0x%x\n", - addr, (unsigned int) temp); - - addr = &ir_set->erst_base[1]; - temp = xhci_readl(xhci, addr); - xhci_dbg(xhci, " %p: ir_set.erst_base[1] = 0x%x\n", - addr, (unsigned int) temp); - - addr = &ir_set->erst_dequeue[0]; - temp = xhci_readl(xhci, addr); - xhci_dbg(xhci, " %p: ir_set.erst_dequeue[0] = 0x%x\n", - addr, (unsigned int) temp); + addr = &ir_set->erst_base; + temp_64 = xhci_read_64(xhci, addr); + xhci_dbg(xhci, " %p: ir_set.erst_base = @%08llx\n", + addr, temp_64); - addr = &ir_set->erst_dequeue[1]; - temp = xhci_readl(xhci, addr); - xhci_dbg(xhci, " %p: ir_set.erst_dequeue[1] = 0x%x\n", - addr, (unsigned int) temp); + addr = &ir_set->erst_dequeue; + temp_64 = xhci_read_64(xhci, addr); + xhci_dbg(xhci, " %p: ir_set.erst_dequeue = @%08llx\n", + addr, temp_64); } void xhci_print_run_regs(struct xhci_hcd *xhci) @@ -268,8 +259,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb) xhci_dbg(xhci, "Link TRB:\n"); xhci_print_trb_offsets(xhci, trb); - address = trb->link.segment_ptr[0] + - (((u64) trb->link.segment_ptr[1]) << 32); + address = trb->link.segment_ptr; xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address); xhci_dbg(xhci, "Interrupter target = 0x%x\n", @@ -282,8 +272,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb) (unsigned int) (trb->link.control & TRB_NO_SNOOP)); break; case TRB_TYPE(TRB_TRANSFER): - address = trb->trans_event.buffer[0] + - (((u64) trb->trans_event.buffer[1]) << 32); + address = trb->trans_event.buffer; /* * FIXME: look at flags to figure out if it's an address or if * the data is directly in the buffer field. @@ -291,8 +280,7 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb) xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address); break; case TRB_TYPE(TRB_COMPLETION): - address = trb->event_cmd.cmd_trb[0] + - (((u64) trb->event_cmd.cmd_trb[1]) << 32); + address = trb->event_cmd.cmd_trb; xhci_dbg(xhci, "Command TRB pointer = %llu\n", address); xhci_dbg(xhci, "Completion status = %u\n", (unsigned int) GET_COMP_CODE(trb->event_cmd.status)); @@ -328,8 +316,8 @@ void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg) for (i = 0; i < TRBS_PER_SEGMENT; ++i) { trb = &seg->trbs[i]; xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr, - (unsigned int) trb->link.segment_ptr[0], - (unsigned int) trb->link.segment_ptr[1], + lower_32_bits(trb->link.segment_ptr), + upper_32_bits(trb->link.segment_ptr), (unsigned int) trb->link.intr_target, (unsigned int) trb->link.control); addr += sizeof(*trb); @@ -386,8 +374,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) entry = &erst->entries[i]; xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", (unsigned int) addr, - (unsigned int) entry->seg_addr[0], - (unsigned int) entry->seg_addr[1], + lower_32_bits(entry->seg_addr), + upper_32_bits(entry->seg_addr), (unsigned int) entry->seg_size, (unsigned int) entry->rsvd); addr += sizeof(*entry); @@ -396,12 +384,13 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) { - u32 val; + u64 val; - val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]); - xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = 0x%x\n", val); - val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]); - xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val); + val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); + xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = @%08x\n", + lower_32_bits(val)); + xhci_dbg(xhci, "// xHC command ring deq ptr high bits = @%08x\n", + upper_32_bits(val)); } void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) @@ -462,14 +451,10 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_ad &ctx->ep[i].ep_info2, (unsigned long long)dma, ctx->ep[i].ep_info2); dma += field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[0]\n", - &ctx->ep[i].deq[0], - (unsigned long long)dma, ctx->ep[i].deq[0]); - dma += field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[1]\n", - &ctx->ep[i].deq[1], - (unsigned long long)dma, ctx->ep[i].deq[1]); - dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", + &ctx->ep[i].deq, + (unsigned long long)dma, ctx->ep[i].deq); + dma += 2*field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", &ctx->ep[i].tx_info, (unsigned long long)dma, ctx->ep[i].tx_info); diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index ff99365cae4..e15773598e4 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -226,6 +226,7 @@ int xhci_init(struct usb_hcd *hcd) static void xhci_work(struct xhci_hcd *xhci) { u32 temp; + u64 temp_64; /* * Clear the op reg interrupt status first, @@ -249,8 +250,8 @@ static void xhci_work(struct xhci_hcd *xhci) xhci_handle_event(xhci); /* Clear the event handler busy flag; the event ring should be empty. */ - temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); - xhci_writel(xhci, temp & ~ERST_EHB, &xhci->ir_set->erst_dequeue[0]); + temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); + xhci_write_64(xhci, temp_64 & ~ERST_EHB, &xhci->ir_set->erst_dequeue); /* Flush posted writes -- FIXME is this necessary? */ xhci_readl(xhci, &xhci->ir_set->irq_pending); } @@ -295,6 +296,7 @@ void xhci_event_ring_work(unsigned long arg) { unsigned long flags; int temp; + u64 temp_64; struct xhci_hcd *xhci = (struct xhci_hcd *) arg; int i, j; @@ -311,9 +313,9 @@ void xhci_event_ring_work(unsigned long arg) xhci_dbg(xhci, "Event ring:\n"); xhci_debug_segment(xhci, xhci->event_ring->deq_seg); xhci_dbg_ring_ptrs(xhci, xhci->event_ring); - temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); - temp &= ERST_PTR_MASK; - xhci_dbg(xhci, "ERST deq = 0x%x\n", temp); + temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); + temp_64 &= ~ERST_PTR_MASK; + xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); xhci_dbg(xhci, "Command ring:\n"); xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg); xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); @@ -356,6 +358,7 @@ void xhci_event_ring_work(unsigned long arg) int xhci_run(struct usb_hcd *hcd) { u32 temp; + u64 temp_64; struct xhci_hcd *xhci = hcd_to_xhci(hcd); void (*doorbell)(struct xhci_hcd *) = NULL; @@ -416,11 +419,9 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg(xhci, "Event ring:\n"); xhci_debug_ring(xhci, xhci->event_ring); xhci_dbg_ring_ptrs(xhci, xhci->event_ring); - temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); - temp &= ERST_PTR_MASK; - xhci_dbg(xhci, "ERST deq = 0x%x\n", temp); - temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[1]); - xhci_dbg(xhci, "ERST deq upper = 0x%x\n", temp); + temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); + temp_64 &= ~ERST_PTR_MASK; + xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); temp = xhci_readl(xhci, &xhci->op_regs->command); temp |= (CMD_RUN); @@ -888,8 +889,7 @@ static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev) ep_ctx = &virt_dev->in_ctx->ep[i]; ep_ctx->ep_info = 0; ep_ctx->ep_info2 = 0; - ep_ctx->deq[0] = 0; - ep_ctx->deq[1] = 0; + ep_ctx->deq = 0; ep_ctx->tx_info = 0; } } @@ -1165,7 +1165,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_virt_device *virt_dev; int ret = 0; struct xhci_hcd *xhci = hcd_to_xhci(hcd); - u32 temp; + u64 temp_64; if (!udev->slot_id) { xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id); @@ -1227,18 +1227,13 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) if (ret) { return ret; } - temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[0]); - xhci_dbg(xhci, "Op regs DCBAA ptr[0] = %#08x\n", temp); - temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[1]); - xhci_dbg(xhci, "Op regs DCBAA ptr[1] = %#08x\n", temp); - xhci_dbg(xhci, "Slot ID %d dcbaa entry[0] @%p = %#08x\n", - udev->slot_id, - &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id], - xhci->dcbaa->dev_context_ptrs[2*udev->slot_id]); - xhci_dbg(xhci, "Slot ID %d dcbaa entry[1] @%p = %#08x\n", + temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); + xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64); + xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n", udev->slot_id, - &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1], - xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1]); + &xhci->dcbaa->dev_context_ptrs[udev->slot_id], + (unsigned long long) + xhci->dcbaa->dev_context_ptrs[udev->slot_id]); xhci_dbg(xhci, "Output Context DMA address = %#08llx\n", (unsigned long long)virt_dev->out_ctx_dma); xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index c8a72de1c50..ec825f16dce 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -88,7 +88,7 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, return; prev->next = next; if (link_trbs) { - prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr[0] = next->dma; + prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = next->dma; /* Set the last TRB in the segment to have a TRB type ID of Link TRB */ val = prev->trbs[TRBS_PER_SEGMENT-1].link.control; @@ -200,8 +200,7 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) return; dev = xhci->devs[slot_id]; - xhci->dcbaa->dev_context_ptrs[2*slot_id] = 0; - xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0; + xhci->dcbaa->dev_context_ptrs[slot_id] = 0; if (!dev) return; @@ -265,13 +264,12 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, * Point to output device context in dcbaa; skip the output control * context, which is eight 32 bit fields (or 32 bytes long) */ - xhci->dcbaa->dev_context_ptrs[2*slot_id] = + xhci->dcbaa->dev_context_ptrs[slot_id] = (u32) dev->out_ctx_dma + (32); xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", slot_id, - &xhci->dcbaa->dev_context_ptrs[2*slot_id], + &xhci->dcbaa->dev_context_ptrs[slot_id], (unsigned long long)dev->out_ctx_dma); - xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0; return 1; fail: @@ -360,10 +358,9 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud ep0_ctx->ep_info2 |= MAX_BURST(0); ep0_ctx->ep_info2 |= ERROR_COUNT(3); - ep0_ctx->deq[0] = + ep0_ctx->deq = dev->ep_rings[0]->first_seg->dma; - ep0_ctx->deq[0] |= dev->ep_rings[0]->cycle_state; - ep0_ctx->deq[1] = 0; + ep0_ctx->deq |= dev->ep_rings[0]->cycle_state; /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ @@ -477,8 +474,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, if (!virt_dev->new_ep_rings[ep_index]) return -ENOMEM; ep_ring = virt_dev->new_ep_rings[ep_index]; - ep_ctx->deq[0] = ep_ring->first_seg->dma | ep_ring->cycle_state; - ep_ctx->deq[1] = 0; + ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state; ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep); @@ -535,8 +531,7 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci, ep_ctx->ep_info = 0; ep_ctx->ep_info2 = 0; - ep_ctx->deq[0] = 0; - ep_ctx->deq[1] = 0; + ep_ctx->deq = 0; ep_ctx->tx_info = 0; /* Don't free the endpoint ring until the set interface or configuration * request succeeds. @@ -551,10 +546,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) /* Free the Event Ring Segment Table and the actual Event Ring */ xhci_writel(xhci, 0, &xhci->ir_set->erst_size); - xhci_writel(xhci, 0, &xhci->ir_set->erst_base[0]); - xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]); - xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[0]); - xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]); + xhci_write_64(xhci, 0, &xhci->ir_set->erst_base); + xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue); size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); if (xhci->erst.entries) pci_free_consistent(pdev, size, @@ -566,8 +559,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->event_ring = NULL; xhci_dbg(xhci, "Freed event ring\n"); - xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[0]); - xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[1]); + xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring); if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; @@ -586,8 +578,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->device_pool = NULL; xhci_dbg(xhci, "Freed device context pool\n"); - xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[0]); - xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[1]); + xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr); if (xhci->dcbaa) pci_free_consistent(pdev, sizeof(*xhci->dcbaa), xhci->dcbaa, xhci->dcbaa->dma); @@ -602,6 +593,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) dma_addr_t dma; struct device *dev = xhci_to_hcd(xhci)->self.controller; unsigned int val, val2; + u64 val_64; struct xhci_segment *seg; u32 page_size; int i; @@ -647,8 +639,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci->dcbaa->dma = dma; xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n", (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); - xhci_writel(xhci, dma, &xhci->op_regs->dcbaa_ptr[0]); - xhci_writel(xhci, (u32) 0, &xhci->op_regs->dcbaa_ptr[1]); + xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); /* * Initialize the ring segment pool. The ring must be a contiguous @@ -675,14 +666,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) (unsigned long long)xhci->cmd_ring->first_seg->dma); /* Set the address in the Command Ring Control register */ - val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]); - val = (val & ~CMD_RING_ADDR_MASK) | - (xhci->cmd_ring->first_seg->dma & CMD_RING_ADDR_MASK) | + val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); + val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | + (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) | xhci->cmd_ring->cycle_state; - xhci_dbg(xhci, "// Setting command ring address low bits to 0x%x\n", val); - xhci_writel(xhci, val, &xhci->op_regs->cmd_ring[0]); - xhci_dbg(xhci, "// Setting command ring address high bits to 0x0\n"); - xhci_writel(xhci, (u32) 0, &xhci->op_regs->cmd_ring[1]); + xhci_dbg(xhci, "// Setting command ring address to 0x%x\n", val); + xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); xhci_dbg_cmd_ptrs(xhci); val = xhci_readl(xhci, &xhci->cap_regs->db_off); @@ -722,8 +711,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) /* set ring base address and size for each segment table entry */ for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) { struct xhci_erst_entry *entry = &xhci->erst.entries[val]; - entry->seg_addr[0] = seg->dma; - entry->seg_addr[1] = 0; + entry->seg_addr = seg->dma; entry->seg_size = TRBS_PER_SEGMENT; entry->rsvd = 0; seg = seg->next; @@ -741,11 +729,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) /* set the segment table base address */ xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n", (unsigned long long)xhci->erst.erst_dma_addr); - val = xhci_readl(xhci, &xhci->ir_set->erst_base[0]); - val &= ERST_PTR_MASK; - val |= (xhci->erst.erst_dma_addr & ~ERST_PTR_MASK); - xhci_writel(xhci, val, &xhci->ir_set->erst_base[0]); - xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]); + val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base); + val_64 &= ERST_PTR_MASK; + val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK); + xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base); /* Set the event ring dequeue address */ xhci_set_hc_event_deq(xhci); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index d672ba14ff8..588686fca47 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -237,7 +237,7 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, void xhci_set_hc_event_deq(struct xhci_hcd *xhci) { - u32 temp; + u64 temp; dma_addr_t deq; deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, @@ -246,13 +246,12 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci) xhci_warn(xhci, "WARN something wrong with SW event ring " "dequeue ptr.\n"); /* Update HC event ring dequeue pointer */ - temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); + temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); temp &= ERST_PTR_MASK; if (!in_interrupt()) xhci_dbg(xhci, "// Write event ring dequeue pointer\n"); - xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]); - xhci_writel(xhci, (deq & ~ERST_PTR_MASK) | temp, - &xhci->ir_set->erst_dequeue[0]); + xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, + &xhci->ir_set->erst_dequeue); } /* Ring the host controller doorbell after placing a command on the ring */ @@ -352,7 +351,7 @@ static void find_new_dequeue_state(struct xhci_hcd *xhci, if (!state->new_deq_seg) BUG(); /* Dig out the cycle state saved by the xHC during the stop ep cmd */ - state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq[0]; + state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq; state->new_deq_ptr = cur_td->last_trb; state->new_deq_seg = find_trb_seg(state->new_deq_seg, @@ -594,10 +593,8 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, * cancelling URBs, which might not be an error... */ } else { - xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq[0] = 0x%x, " - "deq[1] = 0x%x.\n", - dev->out_ctx->ep[ep_index].deq[0], - dev->out_ctx->ep[ep_index].deq[1]); + xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n", + dev->out_ctx->ep[ep_index].deq); } ep_ring->state &= ~SET_DEQ_PENDING; @@ -631,7 +628,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, u64 cmd_dma; dma_addr_t cmd_dequeue_dma; - cmd_dma = (((u64) event->cmd_trb[1]) << 32) + event->cmd_trb[0]; + cmd_dma = event->cmd_trb; cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, xhci->cmd_ring->dequeue); /* Is the command ring deq ptr out of sync with the deq seg ptr? */ @@ -794,10 +791,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, return -ENODEV; } - event_dma = event->buffer[0]; - if (event->buffer[1] != 0) - xhci_warn(xhci, "WARN ignoring upper 32-bits of 64-bit TRB dma address\n"); - + event_dma = event->buffer; /* This TRB should be in the TD at the head of this ring's TD list */ if (list_empty(&ep_ring->td_list)) { xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", @@ -821,10 +815,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / sizeof(*event_trb)]; xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10); - xhci_dbg(xhci, "Offset 0x00 (buffer[0]) = 0x%x\n", - (unsigned int) event->buffer[0]); - xhci_dbg(xhci, "Offset 0x04 (buffer[0]) = 0x%x\n", - (unsigned int) event->buffer[1]); + xhci_dbg(xhci, "Offset 0x00 (buffer lo) = 0x%x\n", + lower_32_bits(event->buffer)); + xhci_dbg(xhci, "Offset 0x04 (buffer hi) = 0x%x\n", + upper_32_bits(event->buffer)); xhci_dbg(xhci, "Offset 0x08 (transfer length) = 0x%x\n", (unsigned int) event->transfer_len); xhci_dbg(xhci, "Offset 0x0C (flags) = 0x%x\n", @@ -1343,8 +1337,8 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, TD_REMAINDER(urb->transfer_buffer_length - running_total) | TRB_INTR_TARGET(0); queue_trb(xhci, ep_ring, false, - (u32) addr, - (u32) ((u64) addr >> 32), + lower_32_bits(addr), + upper_32_bits(addr), length_field, /* We always want to know if the TRB was short, * or we won't get an event when it completes. @@ -1475,8 +1469,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, TD_REMAINDER(urb->transfer_buffer_length - running_total) | TRB_INTR_TARGET(0); queue_trb(xhci, ep_ring, false, - (u32) addr, - (u32) ((u64) addr >> 32), + lower_32_bits(addr), + upper_32_bits(addr), length_field, /* We always want to know if the TRB was short, * or we won't get an event when it completes. @@ -1637,7 +1631,8 @@ int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id) int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id) { - return queue_command(xhci, in_ctx_ptr, 0, 0, + return queue_command(xhci, lower_32_bits(in_ctx_ptr), + upper_32_bits(in_ctx_ptr), 0, TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id)); } @@ -1645,7 +1640,8 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id) { - return queue_command(xhci, in_ctx_ptr, 0, 0, + return queue_command(xhci, lower_32_bits(in_ctx_ptr), + upper_32_bits(in_ctx_ptr), 0, TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id)); } @@ -1677,7 +1673,8 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n"); xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n", deq_seg, deq_ptr); - return queue_command(xhci, (u32) addr | cycle_state, 0, 0, + return queue_command(xhci, lower_32_bits(addr) | cycle_state, + upper_32_bits(addr), 0, trb_slot_id | trb_ep_index | type); } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index cde648a524f..60770c89132 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -25,6 +25,7 @@ #include #include +#include #include "../core/hcd.h" /* Code sharing between pci-quirks and xhci hcd */ @@ -42,14 +43,6 @@ * xHCI register interface. * This corresponds to the eXtensible Host Controller Interface (xHCI) * Revision 0.95 specification - * - * Registers should always be accessed with double word or quad word accesses. - * - * Some xHCI implementations may support 64-bit address pointers. Registers - * with 64-bit address pointers should be written to with dword accesses by - * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. - * xHCI implementations that do not support 64-bit address pointers will ignore - * the high dword, and write order is irrelevant. */ /** @@ -166,10 +159,10 @@ struct xhci_op_regs { u32 reserved1; u32 reserved2; u32 dev_notification; - u32 cmd_ring[2]; + u64 cmd_ring; /* rsvd: offset 0x20-2F */ u32 reserved3[4]; - u32 dcbaa_ptr[2]; + u64 dcbaa_ptr; u32 config_reg; /* rsvd: offset 0x3C-3FF */ u32 reserved4[241]; @@ -254,7 +247,7 @@ struct xhci_op_regs { #define CMD_RING_RUNNING (1 << 3) /* bits 4:5 reserved and should be preserved */ /* Command Ring pointer - bit mask for the lower 32 bits. */ -#define CMD_RING_ADDR_MASK (0xffffffc0) +#define CMD_RING_RSVD_BITS (0x3f) /* CONFIG - Configure Register - config_reg bitmasks */ /* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */ @@ -382,8 +375,8 @@ struct xhci_intr_reg { u32 irq_control; u32 erst_size; u32 rsvd; - u32 erst_base[2]; - u32 erst_dequeue[2]; + u64 erst_base; + u64 erst_dequeue; }; /* irq_pending bitmasks */ @@ -538,7 +531,7 @@ struct xhci_slot_ctx { struct xhci_ep_ctx { u32 ep_info; u32 ep_info2; - u32 deq[2]; + u64 deq; u32 tx_info; /* offset 0x14 - 0x1f reserved for HC internal use */ u32 reserved[3]; @@ -641,7 +634,7 @@ struct xhci_virt_device { */ struct xhci_device_context_array { /* 64-bit device addresses; we only write 32-bit addresses */ - u32 dev_context_ptrs[2*MAX_HC_SLOTS]; + u64 dev_context_ptrs[MAX_HC_SLOTS]; /* private xHCD pointers */ dma_addr_t dma; }; @@ -654,7 +647,7 @@ struct xhci_device_context_array { struct xhci_stream_ctx { /* 64-bit stream ring address, cycle state, and stream type */ - u32 stream_ring[2]; + u64 stream_ring; /* offset 0x14 - 0x1f reserved for HC internal use */ u32 reserved[2]; }; @@ -662,7 +655,7 @@ struct xhci_stream_ctx { struct xhci_transfer_event { /* 64-bit buffer address, or immediate data */ - u32 buffer[2]; + u64 buffer; u32 transfer_len; /* This field is interpreted differently based on the type of TRB */ u32 flags; @@ -744,7 +737,7 @@ struct xhci_transfer_event { struct xhci_link_trb { /* 64-bit segment pointer*/ - u32 segment_ptr[2]; + u64 segment_ptr; u32 intr_target; u32 control; }; @@ -755,7 +748,7 @@ struct xhci_link_trb { /* Command completion event TRB */ struct xhci_event_cmd { /* Pointer to command TRB, or the value passed by the event data trb */ - u32 cmd_trb[2]; + u64 cmd_trb; u32 status; u32 flags; }; @@ -943,7 +936,7 @@ struct xhci_ring { struct xhci_erst_entry { /* 64-bit event ring segment address */ - u32 seg_addr[2]; + u64 seg_addr; u32 seg_size; /* Set to zero */ u32 rsvd; @@ -1079,6 +1072,38 @@ static inline void xhci_writel(struct xhci_hcd *xhci, writel(val, regs); } +/* + * Registers should always be accessed with double word or quad word accesses. + * + * Some xHCI implementations may support 64-bit address pointers. Registers + * with 64-bit address pointers should be written to with dword accesses by + * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. + * xHCI implementations that do not support 64-bit address pointers will ignore + * the high dword, and write order is irrelevant. + */ +static inline u64 xhci_read_64(const struct xhci_hcd *xhci, + __u64 __iomem *regs) +{ + __u32 __iomem *ptr = (__u32 __iomem *) regs; + u64 val_lo = readl(ptr); + u64 val_hi = readl(ptr + 1); + return val_lo + (val_hi << 32); +} +static inline void xhci_write_64(struct xhci_hcd *xhci, + const u64 val, __u64 __iomem *regs) +{ + __u32 __iomem *ptr = (__u32 __iomem *) regs; + u32 val_lo = lower_32_bits(val); + u32 val_hi = upper_32_bits(val); + + if (!in_interrupt()) + xhci_dbg(xhci, + "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n", + regs, (long unsigned int) val); + writel(val_lo, ptr); + writel(val_hi, ptr + 1); +} + /* xHCI debugging */ void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num); void xhci_print_registers(struct xhci_hcd *xhci); -- cgit v1.2.3 From 62889610f5591005bed9517360e17531684f72d0 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:36 -0700 Subject: USB: xhci: Handle short control packets correctly. When there is a short packet on a control transfer, the xHCI host controller hardware will generate two events. The first event will be for the data stage TD with a completion code for a short packet. The second event will be for the status stage with a successful completion code. Before this patch, the xHCI driver would giveback the short control URB when it received the event for the data stage TD. Then it would become confused when it saw a status stage event for the endpoint for an URB it had already finished processing. Change the xHCI host controller driver to wait for the status stage event when it receives a short transfer completion code for a data stage TD. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 588686fca47..5dd3b1fd71c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -892,15 +892,23 @@ static int handle_tx_event(struct xhci_hcd *xhci, if (event_trb != ep_ring->dequeue) { /* The event was for the status stage */ if (event_trb == td->last_trb) { - td->urb->actual_length = - td->urb->transfer_buffer_length; + /* Did we already see a short data stage? */ + if (td->urb->actual_length != 0) + status = -EREMOTEIO; + else + td->urb->actual_length = + td->urb->transfer_buffer_length; } else { /* Maybe the event was for the data stage? */ - if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) + if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) { /* We didn't stop on a link TRB in the middle */ td->urb->actual_length = td->urb->transfer_buffer_length - TRB_LEN(event->transfer_len); + xhci_dbg(xhci, "Waiting for status stage event\n"); + urb = NULL; + goto cleanup; + } } } } else { -- cgit v1.2.3 From 2d83109be62edd9647c45d7ed2b916b03974a7ec Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:40 -0700 Subject: USB: xhci: Correct Event Handler Busy flag usage. The Event Handler Busy bit in the event ring dequeue pointer is write 1 to clear. Fix the interrupt service routine to clear that bit after the event handler has run. xhci_set_hc_event_deq() is designed to update the event ring dequeue pointer without changing any of the four reserved bits in the lower nibble. The event handler busy (EHB) bit is write one to clear, so the new value must always contain a zero in that bit in order to preserve the EHB value. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 4 ++-- drivers/usb/host/xhci-ring.c | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index e15773598e4..2e8e5bf6b6c 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -249,9 +249,9 @@ static void xhci_work(struct xhci_hcd *xhci) /* FIXME this should be a delayed service routine that clears the EHB */ xhci_handle_event(xhci); - /* Clear the event handler busy flag; the event ring should be empty. */ + /* Clear the event handler busy flag (RW1C); the event ring should be empty. */ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - xhci_write_64(xhci, temp_64 & ~ERST_EHB, &xhci->ir_set->erst_dequeue); + xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue); /* Flush posted writes -- FIXME is this necessary? */ xhci_readl(xhci, &xhci->ir_set->irq_pending); } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 5dd3b1fd71c..fe9541a89a3 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -248,8 +248,12 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci) /* Update HC event ring dequeue pointer */ temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); temp &= ERST_PTR_MASK; + /* Don't clear the EHB bit (which is RW1C) because + * there might be more events to service. + */ + temp &= ~ERST_EHB; if (!in_interrupt()) - xhci_dbg(xhci, "// Write event ring dequeue pointer\n"); + xhci_dbg(xhci, "// Write event ring dequeue pointer, preserving EHB bit\n"); xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, &xhci->ir_set->erst_dequeue); } -- cgit v1.2.3 From 66e49d8774fa03539713e8f91169c37c05df1e94 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:46 -0700 Subject: USB: xhci: Make debugging more verbose. Add more debugging to the irq handler, slot context initialization, ring operations, URB cancellation, and MMIO writes. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 47 +++++++++++++++++++++++++++++++------------- drivers/usb/host/xhci-ring.c | 35 +++++++++++++++++++++++++++++++-- drivers/usb/host/xhci.h | 14 ++++++------- 3 files changed, 72 insertions(+), 24 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 2e8e5bf6b6c..764995fd59e 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -267,8 +267,10 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); u32 temp, temp2; + union xhci_trb *trb; spin_lock(&xhci->lock); + trb = xhci->event_ring->dequeue; /* Check if the xHC generated the interrupt, or the irq is shared */ temp = xhci_readl(xhci, &xhci->op_regs->status); temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending); @@ -276,6 +278,15 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) spin_unlock(&xhci->lock); return IRQ_NONE; } + xhci_dbg(xhci, "op reg status = %08x\n", temp); + xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2); + xhci_dbg(xhci, "Event ring dequeue ptr:\n"); + xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n", + (unsigned long long)xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb), + lower_32_bits(trb->link.segment_ptr), + upper_32_bits(trb->link.segment_ptr), + (unsigned int) trb->link.intr_target, + (unsigned int) trb->link.control); if (temp & STS_FATAL) { xhci_warn(xhci, "WARNING: Host System Error\n"); @@ -385,6 +396,20 @@ int xhci_run(struct usb_hcd *hcd) add_timer(&xhci->event_ring_timer); #endif + xhci_dbg(xhci, "Command ring memory map follows:\n"); + xhci_debug_ring(xhci, xhci->cmd_ring); + xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); + xhci_dbg_cmd_ptrs(xhci); + + xhci_dbg(xhci, "ERST memory map follows:\n"); + xhci_dbg_erst(xhci, &xhci->erst); + xhci_dbg(xhci, "Event ring:\n"); + xhci_debug_ring(xhci, xhci->event_ring); + xhci_dbg_ring_ptrs(xhci, xhci->event_ring); + temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); + temp_64 &= ~ERST_PTR_MASK; + xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); + xhci_dbg(xhci, "// Set the interrupt modulation register\n"); temp = xhci_readl(xhci, &xhci->ir_set->irq_control); temp &= ~ER_IRQ_INTERVAL_MASK; @@ -409,20 +434,6 @@ int xhci_run(struct usb_hcd *hcd) if (NUM_TEST_NOOPS > 0) doorbell = xhci_setup_one_noop(xhci); - xhci_dbg(xhci, "Command ring memory map follows:\n"); - xhci_debug_ring(xhci, xhci->cmd_ring); - xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); - xhci_dbg_cmd_ptrs(xhci); - - xhci_dbg(xhci, "ERST memory map follows:\n"); - xhci_dbg_erst(xhci, &xhci->erst); - xhci_dbg(xhci, "Event ring:\n"); - xhci_debug_ring(xhci, xhci->event_ring); - xhci_dbg_ring_ptrs(xhci, xhci->event_ring); - temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - temp_64 &= ~ERST_PTR_MASK; - xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); - temp = xhci_readl(xhci, &xhci->op_regs->command); temp |= (CMD_RUN); xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", @@ -665,8 +676,12 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) goto done; xhci_dbg(xhci, "Cancel URB %p\n", urb); + xhci_dbg(xhci, "Event ring:\n"); + xhci_debug_ring(xhci, xhci->event_ring); ep_index = xhci_get_endpoint_index(&urb->ep->desc); ep_ring = xhci->devs[urb->dev->slot_id]->ep_rings[ep_index]; + xhci_dbg(xhci, "Endpoint ring:\n"); + xhci_debug_ring(xhci, ep_ring); td = (struct xhci_td *) urb->hcpriv; ep_ring->cancels_pending++; @@ -1178,6 +1193,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) if (!udev->config) xhci_setup_addressable_virt_dev(xhci, udev); /* Otherwise, assume the core has the device configured how it wants */ + xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2); spin_lock_irqsave(&xhci->lock, flags); ret = xhci_queue_address_device(xhci, virt_dev->in_ctx_dma, @@ -1221,6 +1238,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) default: xhci_err(xhci, "ERROR: unexpected command completion " "code 0x%x.\n", virt_dev->cmd_status); + xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); ret = -EINVAL; break; } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index fe9541a89a3..1fc0decfa0a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -135,6 +135,7 @@ static void next_trb(struct xhci_hcd *xhci, static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer) { union xhci_trb *next = ++(ring->dequeue); + unsigned long long addr; ring->deq_updates++; /* Update the dequeue pointer further if that was a link TRB or we're at @@ -152,6 +153,13 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer ring->dequeue = ring->deq_seg->trbs; next = ring->dequeue; } + addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue); + if (ring == xhci->event_ring) + xhci_dbg(xhci, "Event ring deq = 0x%llx (DMA)\n", addr); + else if (ring == xhci->cmd_ring) + xhci_dbg(xhci, "Command ring deq = 0x%llx (DMA)\n", addr); + else + xhci_dbg(xhci, "Ring deq = 0x%llx (DMA)\n", addr); } /* @@ -171,6 +179,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer { u32 chain; union xhci_trb *next; + unsigned long long addr; chain = ring->enqueue->generic.field[3] & TRB_CHAIN; next = ++(ring->enqueue); @@ -204,6 +213,13 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer ring->enqueue = ring->enq_seg->trbs; next = ring->enqueue; } + addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue); + if (ring == xhci->event_ring) + xhci_dbg(xhci, "Event ring enq = 0x%llx (DMA)\n", addr); + else if (ring == xhci->cmd_ring) + xhci_dbg(xhci, "Command ring enq = 0x%llx (DMA)\n", addr); + else + xhci_dbg(xhci, "Ring enq = 0x%llx (DMA)\n", addr); } /* @@ -252,8 +268,7 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci) * there might be more events to service. */ temp &= ~ERST_EHB; - if (!in_interrupt()) - xhci_dbg(xhci, "// Write event ring dequeue pointer, preserving EHB bit\n"); + xhci_dbg(xhci, "// Write event ring dequeue pointer, preserving EHB bit\n"); xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, &xhci->ir_set->erst_dequeue); } @@ -781,6 +796,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, struct urb *urb = 0; int status = -EINPROGRESS; + xhci_dbg(xhci, "In %s\n", __func__); xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)]; if (!xdev) { xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n"); @@ -789,6 +805,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, /* Endpoint ID is 1 based, our index is zero based */ ep_index = TRB_TO_EP_ID(event->flags) - 1; + xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index); ep_ring = xdev->ep_rings[ep_index]; if (!ep_ring || (xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) { xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n"); @@ -797,6 +814,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, event_dma = event->buffer; /* This TRB should be in the TD at the head of this ring's TD list */ + xhci_dbg(xhci, "%s - checking for list empty\n", __func__); if (list_empty(&ep_ring->td_list)) { xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", TRB_TO_SLOT_ID(event->flags), ep_index); @@ -806,11 +824,14 @@ static int handle_tx_event(struct xhci_hcd *xhci, urb = NULL; goto cleanup; } + xhci_dbg(xhci, "%s - getting list entry\n", __func__); td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); /* Is this a TRB in the currently executing TD? */ + xhci_dbg(xhci, "%s - looking for TD\n", __func__); event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, td->last_trb, event_dma); + xhci_dbg(xhci, "%s - found event_seg = %p\n", __func__, event_seg); if (!event_seg) { /* HC is busted, give up! */ xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not part of current TD\n"); @@ -1027,6 +1048,8 @@ cleanup: /* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */ if (urb) { usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb); + xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n", + urb, td->urb->actual_length, status); spin_unlock(&xhci->lock); usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status); spin_lock(&xhci->lock); @@ -1044,6 +1067,7 @@ void xhci_handle_event(struct xhci_hcd *xhci) int update_ptrs = 1; int ret; + xhci_dbg(xhci, "In %s\n", __func__); if (!xhci->event_ring || !xhci->event_ring->dequeue) { xhci->error_bitmask |= 1 << 1; return; @@ -1056,18 +1080,25 @@ void xhci_handle_event(struct xhci_hcd *xhci) xhci->error_bitmask |= 1 << 2; return; } + xhci_dbg(xhci, "%s - OS owns TRB\n", __func__); /* FIXME: Handle more event types. */ switch ((event->event_cmd.flags & TRB_TYPE_BITMASK)) { case TRB_TYPE(TRB_COMPLETION): + xhci_dbg(xhci, "%s - calling handle_cmd_completion\n", __func__); handle_cmd_completion(xhci, &event->event_cmd); + xhci_dbg(xhci, "%s - returned from handle_cmd_completion\n", __func__); break; case TRB_TYPE(TRB_PORT_STATUS): + xhci_dbg(xhci, "%s - calling handle_port_status\n", __func__); handle_port_status(xhci, event); + xhci_dbg(xhci, "%s - returned from handle_port_status\n", __func__); update_ptrs = 0; break; case TRB_TYPE(TRB_TRANSFER): + xhci_dbg(xhci, "%s - calling handle_tx_event\n", __func__); ret = handle_tx_event(xhci, &event->trans_event); + xhci_dbg(xhci, "%s - returned from handle_tx_event\n", __func__); if (ret < 0) xhci->error_bitmask |= 1 << 9; else diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 60770c89132..074728e1022 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1065,10 +1065,9 @@ static inline unsigned int xhci_readl(const struct xhci_hcd *xhci, static inline void xhci_writel(struct xhci_hcd *xhci, const unsigned int val, __u32 __iomem *regs) { - if (!in_interrupt()) - xhci_dbg(xhci, - "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n", - regs, val); + xhci_dbg(xhci, + "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n", + regs, val); writel(val, regs); } @@ -1096,10 +1095,9 @@ static inline void xhci_write_64(struct xhci_hcd *xhci, u32 val_lo = lower_32_bits(val); u32 val_hi = upper_32_bits(val); - if (!in_interrupt()) - xhci_dbg(xhci, - "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n", - regs, (long unsigned int) val); + xhci_dbg(xhci, + "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n", + regs, (long unsigned int) val); writel(val_lo, ptr); writel(val_hi, ptr + 1); } -- cgit v1.2.3 From d3512f63494678dc58e44a20c56278718fd58969 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:50 -0700 Subject: USB: xhci: Don't oops if the host doesn't halt. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 764995fd59e..8c3a074a95c 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -103,7 +103,10 @@ int xhci_reset(struct xhci_hcd *xhci) u32 state; state = xhci_readl(xhci, &xhci->op_regs->status); - BUG_ON((state & STS_HALT) == 0); + if ((state & STS_HALT) == 0) { + xhci_warn(xhci, "Host controller not halted, aborting reset.\n"); + return 0; + } xhci_dbg(xhci, "// Reset the HC\n"); command = xhci_readl(xhci, &xhci->op_regs->command); -- cgit v1.2.3 From fcf8f576beafb8c5db8aee8a73eb73763fa7b0ad Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:04:01 -0700 Subject: USB: xhci: Check if the host controller died in IRQ handler. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 8c3a074a95c..008326d5bc5 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -277,6 +277,9 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) /* Check if the xHC generated the interrupt, or the irq is shared */ temp = xhci_readl(xhci, &xhci->op_regs->status); temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending); + if (temp == 0xffffffff && temp2 == 0xffffffff) + goto hw_died; + if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) { spin_unlock(&xhci->lock); return IRQ_NONE; @@ -294,6 +297,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) if (temp & STS_FATAL) { xhci_warn(xhci, "WARNING: Host System Error\n"); xhci_halt(xhci); +hw_died: xhci_to_hcd(xhci)->state = HC_STATE_HALT; spin_unlock(&xhci->lock); return -ESHUTDOWN; -- cgit v1.2.3 From 47692d179f7a88794bcd302e53ca7899d7592db9 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:04:27 -0700 Subject: USB: xhci: Setup HW retries correctly. The xHCI host controller can be programmed to retry a transfer a certain number of times per endpoint before it passes back an error condition to the host controller driver. The xHC will return an error code when the error count transitions from 1 to 0. Programming an error count of 3 means the xHC tries the transfer 3 times, programming it with a 1 means it tries to transfer once, and programming it with 0 means the HW tries the transfer infinitely. We want isochronous transfers to only be tried once, so set the error count to one. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index ec825f16dce..075e1036bcb 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -480,11 +480,13 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, /* FIXME dig Mult and streams info out of ep companion desc */ - /* Allow 3 retries for everything but isoc */ + /* Allow 3 retries for everything but isoc; + * error count = 0 means infinite retries. + */ if (!usb_endpoint_xfer_isoc(&ep->desc)) ep_ctx->ep_info2 = ERROR_COUNT(3); else - ep_ctx->ep_info2 = ERROR_COUNT(0); + ep_ctx->ep_info2 = ERROR_COUNT(1); ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep); -- cgit v1.2.3 From 4a73143ced467868e92d7914d9f8bf797640927b Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:04:32 -0700 Subject: USB: xhci: Handle babble errors on transfers. Pass back a babble error when this error code is seen in the transfer event TRB. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 1fc0decfa0a..0903e98989e 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -876,6 +876,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, xhci_warn(xhci, "WARN: transfer error on endpoint\n"); status = -EPROTO; break; + case COMP_BABBLE: + xhci_warn(xhci, "WARN: babble error on endpoint\n"); + status = -EOVERFLOW; + break; case COMP_DB_ERR: xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n"); status = -ENOSR; -- cgit v1.2.3 From b7d6d99896a6cf38dc354d673afd3fbde10b86c2 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:04:38 -0700 Subject: USB: xhci: Fail gracefully if there's no SS ep companion descriptor. This is a work around for a bug in the SuperSpeed Endpoint Companion Descriptor parsing code. It fails in some corner cases, which means ep->ss_ep_comp may be NULL. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 075e1036bcb..41aca003ee8 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -496,7 +496,12 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, max_packet = ep->desc.wMaxPacketSize; ep_ctx->ep_info2 |= MAX_PACKET(max_packet); /* dig out max burst from ep companion desc */ - max_packet = ep->ss_ep_comp->desc.bMaxBurst; + if (!ep->ss_ep_comp) { + xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n"); + max_packet = 0; + } else { + max_packet = ep->ss_ep_comp->desc.bMaxBurst; + } ep_ctx->ep_info2 |= MAX_BURST(max_packet); break; case USB_SPEED_HIGH: -- cgit v1.2.3 From 9f8e443816976edd68f415ea25c0223ea921e88c Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:04:52 -0700 Subject: USB: Fix parsing of SuperSpeed Endpoint Companion descriptor. usb_parse_ss_endpoint_companion() was supposed to allocate a structure to hold the SuperSpeed Endpoint Companion descriptor, and either copy the values the device returned, or fill in default values if the device descriptor did not include the companion descriptor. However, the previous code would miss the last endpoint in a configuration with no descriptors after it. Make usb_parse_endpoint() allocate the SS endpoint companion descriptor and fill it with default values, even if we've run out of buffer space in this configuration descriptor. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 48 ++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 24dfb33f90c..a16c538d013 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -80,38 +80,18 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, int max_tx; int i; - /* Allocate space for the SS endpoint companion descriptor */ - ep->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp), - GFP_KERNEL); - if (!ep->ss_ep_comp) - return -ENOMEM; desc = (struct usb_ss_ep_comp_descriptor *) buffer; if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) { dev_warn(ddev, "No SuperSpeed endpoint companion for config %d " " interface %d altsetting %d ep %d: " "using minimum values\n", cfgno, inum, asnum, ep->desc.bEndpointAddress); - ep->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE; - ep->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; - ep->ss_ep_comp->desc.bMaxBurst = 0; - /* - * Leave bmAttributes as zero, which will mean no streams for - * bulk, and isoc won't support multiple bursts of packets. - * With bursts of only one packet, and a Mult of 1, the max - * amount of data moved per endpoint service interval is one - * packet. - */ - if (usb_endpoint_xfer_isoc(&ep->desc) || - usb_endpoint_xfer_int(&ep->desc)) - ep->ss_ep_comp->desc.wBytesPerInterval = - ep->desc.wMaxPacketSize; /* * The next descriptor is for an Endpoint or Interface, * no extra descriptors to copy into the companion structure, * and we didn't eat up any of the buffer. */ - retval = 0; - goto valid; + return 0; } memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE); desc = &ep->ss_ep_comp->desc; @@ -320,6 +300,28 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, buffer += i; size -= i; + /* Allocate space for the SS endpoint companion descriptor */ + endpoint->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp), + GFP_KERNEL); + if (!endpoint->ss_ep_comp) + return -ENOMEM; + + /* Fill in some default values (may be overwritten later) */ + endpoint->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE; + endpoint->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; + endpoint->ss_ep_comp->desc.bMaxBurst = 0; + /* + * Leave bmAttributes as zero, which will mean no streams for + * bulk, and isoc won't support multiple bursts of packets. + * With bursts of only one packet, and a Mult of 1, the max + * amount of data moved per endpoint service interval is one + * packet. + */ + if (usb_endpoint_xfer_isoc(&endpoint->desc) || + usb_endpoint_xfer_int(&endpoint->desc)) + endpoint->ss_ep_comp->desc.wBytesPerInterval = + endpoint->desc.wMaxPacketSize; + if (size > 0) { retval = usb_parse_ss_endpoint_companion(ddev, cfgno, inum, asnum, endpoint, num_ep, buffer, @@ -329,6 +331,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, retval = buffer - buffer0; } } else { + dev_warn(ddev, "config %d interface %d altsetting %d " + "endpoint 0x%X has no " + "SuperSpeed companion descriptor\n", + cfgno, inum, asnum, d->bEndpointAddress); retval = buffer - buffer0; } } else { -- cgit v1.2.3 From 254c80a3a0eb811489f7410c3291f01a60e8e42f Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 27 Jul 2009 12:05:03 -0700 Subject: USB: xhci: Scratchpad buffer allocation Allocates and initializes the scratchpad buffer array (XHCI 4.20). This is an array of 64-bit DMA addresses to scratch pages that the controller may use during operation. The number of pages is specified in the "Max Scratchpad Buffers" field of HCSPARAMS2. The DMA address of this array is written into slot 0 of the DCBAA. Signed-off-by: John Youn Acked-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 102 ++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 11 +++++ 2 files changed, 113 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 41aca003ee8..71121d99235 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -545,6 +545,103 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci, */ } +/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */ +static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) +{ + int i; + struct device *dev = xhci_to_hcd(xhci)->self.controller; + int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); + + xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp); + + if (!num_sp) + return 0; + + xhci->scratchpad = kzalloc(sizeof(*xhci->scratchpad), flags); + if (!xhci->scratchpad) + goto fail_sp; + + xhci->scratchpad->sp_array = + pci_alloc_consistent(to_pci_dev(dev), + num_sp * sizeof(u64), + &xhci->scratchpad->sp_dma); + if (!xhci->scratchpad->sp_array) + goto fail_sp2; + + xhci->scratchpad->sp_buffers = kzalloc(sizeof(void *) * num_sp, flags); + if (!xhci->scratchpad->sp_buffers) + goto fail_sp3; + + xhci->scratchpad->sp_dma_buffers = + kzalloc(sizeof(dma_addr_t) * num_sp, flags); + + if (!xhci->scratchpad->sp_dma_buffers) + goto fail_sp4; + + xhci->dcbaa->dev_context_ptrs[0] = xhci->scratchpad->sp_dma; + for (i = 0; i < num_sp; i++) { + dma_addr_t dma; + void *buf = pci_alloc_consistent(to_pci_dev(dev), + xhci->page_size, &dma); + if (!buf) + goto fail_sp5; + + xhci->scratchpad->sp_array[i] = dma; + xhci->scratchpad->sp_buffers[i] = buf; + xhci->scratchpad->sp_dma_buffers[i] = dma; + } + + return 0; + + fail_sp5: + for (i = i - 1; i >= 0; i--) { + pci_free_consistent(to_pci_dev(dev), xhci->page_size, + xhci->scratchpad->sp_buffers[i], + xhci->scratchpad->sp_dma_buffers[i]); + } + kfree(xhci->scratchpad->sp_dma_buffers); + + fail_sp4: + kfree(xhci->scratchpad->sp_buffers); + + fail_sp3: + pci_free_consistent(to_pci_dev(dev), num_sp * sizeof(u64), + xhci->scratchpad->sp_array, + xhci->scratchpad->sp_dma); + + fail_sp2: + kfree(xhci->scratchpad); + xhci->scratchpad = NULL; + + fail_sp: + return -ENOMEM; +} + +static void scratchpad_free(struct xhci_hcd *xhci) +{ + int num_sp; + int i; + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + + if (!xhci->scratchpad) + return; + + num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); + + for (i = 0; i < num_sp; i++) { + pci_free_consistent(pdev, xhci->page_size, + xhci->scratchpad->sp_buffers[i], + xhci->scratchpad->sp_dma_buffers[i]); + } + kfree(xhci->scratchpad->sp_dma_buffers); + kfree(xhci->scratchpad->sp_buffers); + pci_free_consistent(pdev, num_sp * sizeof(u64), + xhci->scratchpad->sp_array, + xhci->scratchpad->sp_dma); + kfree(xhci->scratchpad); + xhci->scratchpad = NULL; +} + void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); @@ -593,6 +690,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->page_size = 0; xhci->page_shift = 0; + scratchpad_free(xhci); } int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) @@ -755,7 +853,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) for (i = 0; i < MAX_HC_SLOTS; ++i) xhci->devs[i] = 0; + if (scratchpad_alloc(xhci, flags)) + goto fail; + return 0; + fail: xhci_warn(xhci, "Couldn't initialize memory\n"); xhci_mem_cleanup(xhci); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 074728e1022..5a09b9a26e0 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -89,6 +89,7 @@ struct xhci_cap_regs { #define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ /* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ +#define HCS_MAX_SCRATCHPAD(p) (((p) >> 27) & 0x1f) /* HCSPARAMS3 - hcs_params3 - bitmasks */ /* bits 0:7, Max U1 to U0 latency for the roothub ports */ @@ -951,6 +952,13 @@ struct xhci_erst { unsigned int erst_size; }; +struct xhci_scratchpad { + u64 *sp_array; + dma_addr_t sp_dma; + void **sp_buffers; + dma_addr_t *sp_dma_buffers; +}; + /* * Each segment table entry is 4*32bits long. 1K seems like an ok size: * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, @@ -1005,6 +1013,9 @@ struct xhci_hcd { struct xhci_ring *cmd_ring; struct xhci_ring *event_ring; struct xhci_erst erst; + /* Scratchpad */ + struct xhci_scratchpad *scratchpad; + /* slot enabling and address device helpers */ struct completion addr_dev; int slot_id; -- cgit v1.2.3 From 28c2d2efb48dec2f0b050affae6d5787d6449e47 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:05:08 -0700 Subject: USB: xhci: Always align output device contexts to 64 bytes. Make sure the xHCI output device context is 64-byte aligned. Previous code was using the same structure for both the output device context and the input control context. Since the structure had 32 bytes of flags before the device context, the output device context wouldn't be 64-byte aligned. Define a new structure to use for the output device context and clean up the debugging for these two structures. The copy of the device context in the input control context does *not* need to be 64-byte aligned. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbg.c | 101 +++++++++++++++++++++++++++----------------- drivers/usb/host/xhci-hcd.c | 7 +-- drivers/usb/host/xhci-mem.c | 15 +++---- drivers/usb/host/xhci.h | 19 ++++++++- 4 files changed, 89 insertions(+), 53 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 6d62e4abe3c..d77f8de1125 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -393,78 +393,103 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) upper_32_bits(val)); } -void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) +dma_addr_t xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_slot_ctx *slot, dma_addr_t dma) { - int i, j; - int last_ep_ctx = 31; /* Fields are 32 bits wide, DMA addresses are in bytes */ int field_size = 32 / 8; - - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", - &ctx->drop_flags, (unsigned long long)dma, - ctx->drop_flags); - dma += field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", - &ctx->add_flags, (unsigned long long)dma, - ctx->add_flags); - dma += field_size; - for (i = 0; i < 6; ++i) { - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", - &ctx->rsvd[i], (unsigned long long)dma, - ctx->rsvd[i], i); - dma += field_size; - } + int i; xhci_dbg(xhci, "Slot Context:\n"); xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n", - &ctx->slot.dev_info, - (unsigned long long)dma, ctx->slot.dev_info); + &slot->dev_info, + (unsigned long long)dma, slot->dev_info); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n", - &ctx->slot.dev_info2, - (unsigned long long)dma, ctx->slot.dev_info2); + &slot->dev_info2, + (unsigned long long)dma, slot->dev_info2); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n", - &ctx->slot.tt_info, - (unsigned long long)dma, ctx->slot.tt_info); + &slot->tt_info, + (unsigned long long)dma, slot->tt_info); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n", - &ctx->slot.dev_state, - (unsigned long long)dma, ctx->slot.dev_state); + &slot->dev_state, + (unsigned long long)dma, slot->dev_state); dma += field_size; for (i = 0; i < 4; ++i) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", - &ctx->slot.reserved[i], (unsigned long long)dma, - ctx->slot.reserved[i], i); + &slot->reserved[i], (unsigned long long)dma, + slot->reserved[i], i); dma += field_size; } + return dma; +} + +dma_addr_t xhci_dbg_ep_ctx(struct xhci_hcd *xhci, struct xhci_ep_ctx *ep, dma_addr_t dma, unsigned int last_ep) +{ + int i, j; + int last_ep_ctx = 31; + /* Fields are 32 bits wide, DMA addresses are in bytes */ + int field_size = 32 / 8; + if (last_ep < 31) last_ep_ctx = last_ep + 1; for (i = 0; i < last_ep_ctx; ++i) { xhci_dbg(xhci, "Endpoint %02d Context:\n", i); xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", - &ctx->ep[i].ep_info, - (unsigned long long)dma, ctx->ep[i].ep_info); + &ep[i].ep_info, + (unsigned long long)dma, ep[i].ep_info); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n", - &ctx->ep[i].ep_info2, - (unsigned long long)dma, ctx->ep[i].ep_info2); + &ep[i].ep_info2, + (unsigned long long)dma, ep[i].ep_info2); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", - &ctx->ep[i].deq, - (unsigned long long)dma, ctx->ep[i].deq); + &ep[i].deq, + (unsigned long long)dma, ep[i].deq); dma += 2*field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", - &ctx->ep[i].tx_info, - (unsigned long long)dma, ctx->ep[i].tx_info); + &ep[i].tx_info, + (unsigned long long)dma, ep[i].tx_info); dma += field_size; for (j = 0; j < 3; ++j) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", - &ctx->ep[i].reserved[j], + &ep[i].reserved[j], (unsigned long long)dma, - ctx->ep[i].reserved[j], j); + ep[i].reserved[j], j); dma += field_size; } } + return dma; +} + +void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) +{ + int i; + /* Fields are 32 bits wide, DMA addresses are in bytes */ + int field_size = 32 / 8; + + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", + &ctx->drop_flags, (unsigned long long)dma, + ctx->drop_flags); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", + &ctx->add_flags, (unsigned long long)dma, + ctx->add_flags); + dma += field_size; + for (i = 0; i < 6; ++i) { + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", + &ctx->rsvd[i], (unsigned long long)dma, + ctx->rsvd[i], i); + dma += field_size; + } + dma = xhci_dbg_slot_ctx(xhci, &ctx->slot, dma); + dma = xhci_dbg_ep_ctx(xhci, ctx->ep, dma, last_ep); +} + +void xhci_dbg_device_ctx(struct xhci_hcd *xhci, struct xhci_device_ctx *ctx, dma_addr_t dma, unsigned int last_ep) +{ + dma = xhci_dbg_slot_ctx(xhci, &ctx->slot, dma); + dma = xhci_dbg_ep_ctx(xhci, ctx->ep, dma, last_ep); } diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 008326d5bc5..921dd173d79 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -1013,7 +1013,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) } xhci_dbg(xhci, "Output context after successful config ep cmd:\n"); - xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, + xhci_dbg_device_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); xhci_zero_in_ctx(virt_dev); @@ -1265,7 +1265,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2); xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); - xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); + xhci_dbg_device_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); /* * USB core uses address 1 for the roothubs, so we add one to the * address given back to us by the HC. @@ -1274,9 +1274,6 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) /* Zero the input context control for later use */ virt_dev->in_ctx->add_flags = 0; virt_dev->in_ctx->drop_flags = 0; - /* Mirror flags in the output context for future ep enable/disable */ - virt_dev->out_ctx->add_flags = SLOT_FLAG | EP0_FLAG; - virt_dev->out_ctx->drop_flags = 0; xhci_dbg(xhci, "Device address = %d\n", udev->devnum); /* XXX Meh, not sure if anyone else but choose_address uses this. */ diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 71121d99235..8d6bdf2f801 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -235,7 +235,10 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, return 0; dev = xhci->devs[slot_id]; - /* Allocate the (output) device context that will be used in the HC */ + /* Allocate the (output) device context that will be used in the HC. + * The structure is 32 bytes smaller than the input context, but that's + * fine. + */ dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); if (!dev->out_ctx) goto fail; @@ -260,16 +263,12 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, init_completion(&dev->cmd_completion); - /* - * Point to output device context in dcbaa; skip the output control - * context, which is eight 32 bit fields (or 32 bytes long) - */ - xhci->dcbaa->dev_context_ptrs[slot_id] = - (u32) dev->out_ctx_dma + (32); + /* Point to output device context in dcbaa. */ + xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx_dma; xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", slot_id, &xhci->dcbaa->dev_context_ptrs[slot_id], - (unsigned long long)dev->out_ctx_dma); + (unsigned long long) xhci->dcbaa->dev_context_ptrs[slot_id]); return 1; fail: diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 5a09b9a26e0..d4d3c7777fb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -584,15 +584,29 @@ struct xhci_ep_ctx { /** * struct xhci_device_control - * Input/Output context; see section 6.2.5. + * Input context; see section 6.2.5. * * @drop_context: set the bit of the endpoint context you want to disable * @add_context: set the bit of the endpoint context you want to enable */ struct xhci_device_control { + /* Input control context */ u32 drop_flags; u32 add_flags; u32 rsvd[6]; + /* Copy of device context */ + struct xhci_slot_ctx slot; + struct xhci_ep_ctx ep[31]; +}; + +/** + * struct xhci_device_ctx + * Device context; see section 6.2.1. + * + * @slot: slot context for the device. + * @ep: array of endpoint contexts for the device. + */ +struct xhci_device_ctx { struct xhci_slot_ctx slot; struct xhci_ep_ctx ep[31]; }; @@ -612,7 +626,7 @@ struct xhci_virt_device { * track of input and output contexts separately because * these commands might fail and we don't trust the hardware. */ - struct xhci_device_control *out_ctx; + struct xhci_device_ctx *out_ctx; dma_addr_t out_ctx_dma; /* Used for addressing devices and configuration changes */ struct xhci_device_control *in_ctx; @@ -1126,6 +1140,7 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci); void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep); +void xhci_dbg_device_ctx(struct xhci_hcd *xhci, struct xhci_device_ctx *ctx, dma_addr_t dma, unsigned int last_ep); /* xHCI memory managment */ void xhci_mem_cleanup(struct xhci_hcd *xhci); -- cgit v1.2.3 From d115b04818e57bdbc7ccde4d0660b15e33013dc8 Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 27 Jul 2009 12:05:15 -0700 Subject: USB: xhci: Support for 64-byte contexts Adds support for controllers that use 64-byte contexts. The following context data structures are affected by this: Device, Input, Input Control, Endpoint, and Slot. To accommodate the use of either 32 or 64-byte contexts, a Device or Input context can only be accessed through functions which look-up and return pointers to their contained contexts. Signed-off-by: John Youn Acked-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbg.c | 125 +++++++++++++++++++++++++++---------------- drivers/usb/host/xhci-hcd.c | 121 ++++++++++++++++++++++++----------------- drivers/usb/host/xhci-mem.c | 121 +++++++++++++++++++++++++++++------------ drivers/usb/host/xhci-ring.c | 22 +++++--- drivers/usb/host/xhci.h | 61 +++++++++++---------- 5 files changed, 287 insertions(+), 163 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index d77f8de1125..705e3432415 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -393,103 +393,138 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) upper_32_bits(val)); } -dma_addr_t xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_slot_ctx *slot, dma_addr_t dma) +/* Print the last 32 bytes for 64-byte contexts */ +static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma) +{ + int i; + for (i = 0; i < 4; ++i) { + xhci_dbg(xhci, "@%p (virt) @%08llx " + "(dma) %#08llx - rsvd64[%d]\n", + &ctx[4 + i], (unsigned long long)dma, + ctx[4 + i], i); + dma += 8; + } +} + +void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx) { /* Fields are 32 bits wide, DMA addresses are in bytes */ int field_size = 32 / 8; int i; + struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx); + dma_addr_t dma = ctx->dma + ((unsigned long)slot_ctx - (unsigned long)ctx); + int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); + xhci_dbg(xhci, "Slot Context:\n"); xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n", - &slot->dev_info, - (unsigned long long)dma, slot->dev_info); + &slot_ctx->dev_info, + (unsigned long long)dma, slot_ctx->dev_info); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n", - &slot->dev_info2, - (unsigned long long)dma, slot->dev_info2); + &slot_ctx->dev_info2, + (unsigned long long)dma, slot_ctx->dev_info2); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n", - &slot->tt_info, - (unsigned long long)dma, slot->tt_info); + &slot_ctx->tt_info, + (unsigned long long)dma, slot_ctx->tt_info); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n", - &slot->dev_state, - (unsigned long long)dma, slot->dev_state); + &slot_ctx->dev_state, + (unsigned long long)dma, slot_ctx->dev_state); dma += field_size; for (i = 0; i < 4; ++i) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", - &slot->reserved[i], (unsigned long long)dma, - slot->reserved[i], i); + &slot_ctx->reserved[i], (unsigned long long)dma, + slot_ctx->reserved[i], i); dma += field_size; } - return dma; + if (csz) + dbg_rsvd64(xhci, (u64 *)slot_ctx, dma); } -dma_addr_t xhci_dbg_ep_ctx(struct xhci_hcd *xhci, struct xhci_ep_ctx *ep, dma_addr_t dma, unsigned int last_ep) +void xhci_dbg_ep_ctx(struct xhci_hcd *xhci, + struct xhci_container_ctx *ctx, + unsigned int last_ep) { int i, j; int last_ep_ctx = 31; /* Fields are 32 bits wide, DMA addresses are in bytes */ int field_size = 32 / 8; + int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); if (last_ep < 31) last_ep_ctx = last_ep + 1; for (i = 0; i < last_ep_ctx; ++i) { + struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i); + dma_addr_t dma = ctx->dma + + ((unsigned long)ep_ctx - (unsigned long)ctx); + xhci_dbg(xhci, "Endpoint %02d Context:\n", i); xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", - &ep[i].ep_info, - (unsigned long long)dma, ep[i].ep_info); + &ep_ctx->ep_info, + (unsigned long long)dma, ep_ctx->ep_info); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n", - &ep[i].ep_info2, - (unsigned long long)dma, ep[i].ep_info2); + &ep_ctx->ep_info2, + (unsigned long long)dma, ep_ctx->ep_info2); dma += field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", - &ep[i].deq, - (unsigned long long)dma, ep[i].deq); + &ep_ctx->deq, + (unsigned long long)dma, ep_ctx->deq); dma += 2*field_size; xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", - &ep[i].tx_info, - (unsigned long long)dma, ep[i].tx_info); + &ep_ctx->tx_info, + (unsigned long long)dma, ep_ctx->tx_info); dma += field_size; for (j = 0; j < 3; ++j) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", - &ep[i].reserved[j], + &ep_ctx->reserved[j], (unsigned long long)dma, - ep[i].reserved[j], j); + ep_ctx->reserved[j], j); dma += field_size; } + + if (csz) + dbg_rsvd64(xhci, (u64 *)ep_ctx, dma); } - return dma; } -void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) +void xhci_dbg_ctx(struct xhci_hcd *xhci, + struct xhci_container_ctx *ctx, + unsigned int last_ep) { int i; /* Fields are 32 bits wide, DMA addresses are in bytes */ int field_size = 32 / 8; - - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", - &ctx->drop_flags, (unsigned long long)dma, - ctx->drop_flags); - dma += field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", - &ctx->add_flags, (unsigned long long)dma, - ctx->add_flags); - dma += field_size; - for (i = 0; i < 6; ++i) { - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", - &ctx->rsvd[i], (unsigned long long)dma, - ctx->rsvd[i], i); + struct xhci_slot_ctx *slot_ctx; + dma_addr_t dma = ctx->dma; + int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); + + if (ctx->type == XHCI_CTX_TYPE_INPUT) { + struct xhci_input_control_ctx *ctrl_ctx = + xhci_get_input_control_ctx(xhci, ctx); + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", + &ctrl_ctx->drop_flags, (unsigned long long)dma, + ctrl_ctx->drop_flags); dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", + &ctrl_ctx->add_flags, (unsigned long long)dma, + ctrl_ctx->add_flags); + dma += field_size; + for (i = 0; i < 6; ++i) { + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd2[%d]\n", + &ctrl_ctx->rsvd2[i], (unsigned long long)dma, + ctrl_ctx->rsvd2[i], i); + dma += field_size; + } + + if (csz) + dbg_rsvd64(xhci, (u64 *)ctrl_ctx, dma); } - dma = xhci_dbg_slot_ctx(xhci, &ctx->slot, dma); - dma = xhci_dbg_ep_ctx(xhci, ctx->ep, dma, last_ep); -} -void xhci_dbg_device_ctx(struct xhci_hcd *xhci, struct xhci_device_ctx *ctx, dma_addr_t dma, unsigned int last_ep) -{ - dma = xhci_dbg_slot_ctx(xhci, &ctx->slot, dma); - dma = xhci_dbg_ep_ctx(xhci, ctx->ep, dma, last_ep); + slot_ctx = xhci_get_slot_ctx(xhci, ctx); + xhci_dbg_slot_ctx(xhci, ctx); + xhci_dbg_ep_ctx(xhci, ctx, last_ep); } diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 921dd173d79..057a07e876b 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -722,7 +722,9 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep) { struct xhci_hcd *xhci; - struct xhci_device_control *in_ctx; + struct xhci_container_ctx *in_ctx, *out_ctx; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_slot_ctx *slot_ctx; unsigned int last_ctx; unsigned int ep_index; struct xhci_ep_ctx *ep_ctx; @@ -750,31 +752,34 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, } in_ctx = xhci->devs[udev->slot_id]->in_ctx; + out_ctx = xhci->devs[udev->slot_id]->out_ctx; + ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); ep_index = xhci_get_endpoint_index(&ep->desc); - ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index]; + ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); /* If the HC already knows the endpoint is disabled, * or the HCD has noted it is disabled, ignore this request */ if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED || - in_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) { + ctrl_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) { xhci_warn(xhci, "xHCI %s called with disabled ep %p\n", __func__, ep); return 0; } - in_ctx->drop_flags |= drop_flag; - new_drop_flags = in_ctx->drop_flags; + ctrl_ctx->drop_flags |= drop_flag; + new_drop_flags = ctrl_ctx->drop_flags; - in_ctx->add_flags = ~drop_flag; - new_add_flags = in_ctx->add_flags; + ctrl_ctx->add_flags = ~drop_flag; + new_add_flags = ctrl_ctx->add_flags; - last_ctx = xhci_last_valid_endpoint(in_ctx->add_flags); + last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags); + slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); /* Update the last valid endpoint context, if we deleted the last one */ - if ((in_ctx->slot.dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) { - in_ctx->slot.dev_info &= ~LAST_CTX_MASK; - in_ctx->slot.dev_info |= LAST_CTX(last_ctx); + if ((slot_ctx->dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) { + slot_ctx->dev_info &= ~LAST_CTX_MASK; + slot_ctx->dev_info |= LAST_CTX(last_ctx); } - new_slot_info = in_ctx->slot.dev_info; + new_slot_info = slot_ctx->dev_info; xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep); @@ -804,9 +809,11 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep) { struct xhci_hcd *xhci; - struct xhci_device_control *in_ctx; + struct xhci_container_ctx *in_ctx, *out_ctx; unsigned int ep_index; struct xhci_ep_ctx *ep_ctx; + struct xhci_slot_ctx *slot_ctx; + struct xhci_input_control_ctx *ctrl_ctx; u32 added_ctxs; unsigned int last_ctx; u32 new_add_flags, new_drop_flags, new_slot_info; @@ -839,12 +846,14 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, } in_ctx = xhci->devs[udev->slot_id]->in_ctx; + out_ctx = xhci->devs[udev->slot_id]->out_ctx; + ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); ep_index = xhci_get_endpoint_index(&ep->desc); - ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index]; + ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); /* If the HCD has already noted the endpoint is enabled, * ignore this request. */ - if (in_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) { + if (ctrl_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) { xhci_warn(xhci, "xHCI %s called with enabled ep %p\n", __func__, ep); return 0; @@ -862,8 +871,8 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, return -ENOMEM; } - in_ctx->add_flags |= added_ctxs; - new_add_flags = in_ctx->add_flags; + ctrl_ctx->add_flags |= added_ctxs; + new_add_flags = ctrl_ctx->add_flags; /* If xhci_endpoint_disable() was called for this endpoint, but the * xHC hasn't been notified yet through the check_bandwidth() call, @@ -871,14 +880,15 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, * descriptors. We must drop and re-add this endpoint, so we leave the * drop flags alone. */ - new_drop_flags = in_ctx->drop_flags; + new_drop_flags = ctrl_ctx->drop_flags; + slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); /* Update the last valid endpoint context, if we just added one past */ - if ((in_ctx->slot.dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) { - in_ctx->slot.dev_info &= ~LAST_CTX_MASK; - in_ctx->slot.dev_info |= LAST_CTX(last_ctx); + if ((slot_ctx->dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) { + slot_ctx->dev_info &= ~LAST_CTX_MASK; + slot_ctx->dev_info |= LAST_CTX(last_ctx); } - new_slot_info = in_ctx->slot.dev_info; + new_slot_info = slot_ctx->dev_info; /* Store the usb_device pointer for later use */ ep->hcpriv = udev; @@ -892,9 +902,11 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, return 0; } -static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev) +static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev) { + struct xhci_input_control_ctx *ctrl_ctx; struct xhci_ep_ctx *ep_ctx; + struct xhci_slot_ctx *slot_ctx; int i; /* When a device's add flag and drop flag are zero, any subsequent @@ -902,13 +914,15 @@ static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev) * untouched. Make sure we don't leave any old state in the input * endpoint contexts. */ - virt_dev->in_ctx->drop_flags = 0; - virt_dev->in_ctx->add_flags = 0; - virt_dev->in_ctx->slot.dev_info &= ~LAST_CTX_MASK; + ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); + ctrl_ctx->drop_flags = 0; + ctrl_ctx->add_flags = 0; + slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); + slot_ctx->dev_info &= ~LAST_CTX_MASK; /* Endpoint 0 is always valid */ - virt_dev->in_ctx->slot.dev_info |= LAST_CTX(1); + slot_ctx->dev_info |= LAST_CTX(1); for (i = 1; i < 31; ++i) { - ep_ctx = &virt_dev->in_ctx->ep[i]; + ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, i); ep_ctx->ep_info = 0; ep_ctx->ep_info2 = 0; ep_ctx->deq = 0; @@ -934,6 +948,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) unsigned long flags; struct xhci_hcd *xhci; struct xhci_virt_device *virt_dev; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_slot_ctx *slot_ctx; ret = xhci_check_args(hcd, udev, NULL, 0, __func__); if (ret <= 0) @@ -949,16 +965,18 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) virt_dev = xhci->devs[udev->slot_id]; /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */ - virt_dev->in_ctx->add_flags |= SLOT_FLAG; - virt_dev->in_ctx->add_flags &= ~EP0_FLAG; - virt_dev->in_ctx->drop_flags &= ~SLOT_FLAG; - virt_dev->in_ctx->drop_flags &= ~EP0_FLAG; + ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); + ctrl_ctx->add_flags |= SLOT_FLAG; + ctrl_ctx->add_flags &= ~EP0_FLAG; + ctrl_ctx->drop_flags &= ~SLOT_FLAG; + ctrl_ctx->drop_flags &= ~EP0_FLAG; xhci_dbg(xhci, "New Input Control Context:\n"); - xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, - LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); + slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); + xhci_dbg_ctx(xhci, virt_dev->in_ctx, + LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); spin_lock_irqsave(&xhci->lock, flags); - ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx_dma, + ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma, udev->slot_id); if (ret < 0) { spin_unlock_irqrestore(&xhci->lock, flags); @@ -1013,10 +1031,10 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) } xhci_dbg(xhci, "Output context after successful config ep cmd:\n"); - xhci_dbg_device_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, - LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); + xhci_dbg_ctx(xhci, virt_dev->out_ctx, + LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); - xhci_zero_in_ctx(virt_dev); + xhci_zero_in_ctx(xhci, virt_dev); /* Free any old rings */ for (i = 1; i < 31; ++i) { if (virt_dev->new_ep_rings[i]) { @@ -1054,7 +1072,7 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) virt_dev->new_ep_rings[i] = NULL; } } - xhci_zero_in_ctx(virt_dev); + xhci_zero_in_ctx(xhci, virt_dev); } /* Deal with stalled endpoints. The core should have sent the control message @@ -1187,6 +1205,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_virt_device *virt_dev; int ret = 0; struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct xhci_slot_ctx *slot_ctx; + struct xhci_input_control_ctx *ctrl_ctx; u64 temp_64; if (!udev->slot_id) { @@ -1201,11 +1221,11 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) xhci_setup_addressable_virt_dev(xhci, udev); /* Otherwise, assume the core has the device configured how it wants */ xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); - xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2); + xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); spin_lock_irqsave(&xhci->lock, flags); - ret = xhci_queue_address_device(xhci, virt_dev->in_ctx_dma, - udev->slot_id); + ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, + udev->slot_id); if (ret) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); @@ -1246,7 +1266,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) xhci_err(xhci, "ERROR: unexpected command completion " "code 0x%x.\n", virt_dev->cmd_status); xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); - xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); + xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); ret = -EINVAL; break; } @@ -1261,19 +1281,21 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) (unsigned long long) xhci->dcbaa->dev_context_ptrs[udev->slot_id]); xhci_dbg(xhci, "Output Context DMA address = %#08llx\n", - (unsigned long long)virt_dev->out_ctx_dma); + (unsigned long long)virt_dev->out_ctx->dma); xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); - xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2); + xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); - xhci_dbg_device_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); + xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); /* * USB core uses address 1 for the roothubs, so we add one to the * address given back to us by the HC. */ - udev->devnum = (virt_dev->out_ctx->slot.dev_state & DEV_ADDR_MASK) + 1; + slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); + udev->devnum = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1; /* Zero the input context control for later use */ - virt_dev->in_ctx->add_flags = 0; - virt_dev->in_ctx->drop_flags = 0; + ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); + ctrl_ctx->add_flags = 0; + ctrl_ctx->drop_flags = 0; xhci_dbg(xhci, "Device address = %d\n", udev->devnum); /* XXX Meh, not sure if anyone else but choose_address uses this. */ @@ -1315,7 +1337,6 @@ static int __init xhci_hcd_init(void) /* xhci_device_control has eight fields, and also * embeds one xhci_slot_ctx and 31 xhci_ep_ctx */ - BUILD_BUG_ON(sizeof(struct xhci_device_control) != (8+8+8*31)*32/8); BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8); BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8); BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 8d6bdf2f801..e6b9a1c6002 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -189,6 +189,63 @@ fail: return 0; } +#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32) + +struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, + int type, gfp_t flags) +{ + struct xhci_container_ctx *ctx = kzalloc(sizeof(*ctx), flags); + if (!ctx) + return NULL; + + BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT)); + ctx->type = type; + ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024; + if (type == XHCI_CTX_TYPE_INPUT) + ctx->size += CTX_SIZE(xhci->hcc_params); + + ctx->bytes = dma_pool_alloc(xhci->device_pool, flags, &ctx->dma); + memset(ctx->bytes, 0, ctx->size); + return ctx; +} + +void xhci_free_container_ctx(struct xhci_hcd *xhci, + struct xhci_container_ctx *ctx) +{ + dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma); + kfree(ctx); +} + +struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, + struct xhci_container_ctx *ctx) +{ + BUG_ON(ctx->type != XHCI_CTX_TYPE_INPUT); + return (struct xhci_input_control_ctx *)ctx->bytes; +} + +struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, + struct xhci_container_ctx *ctx) +{ + if (ctx->type == XHCI_CTX_TYPE_DEVICE) + return (struct xhci_slot_ctx *)ctx->bytes; + + return (struct xhci_slot_ctx *) + (ctx->bytes + CTX_SIZE(xhci->hcc_params)); +} + +struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, + struct xhci_container_ctx *ctx, + unsigned int ep_index) +{ + /* increment ep index by offset of start of ep ctx array */ + ep_index++; + if (ctx->type == XHCI_CTX_TYPE_INPUT) + ep_index++; + + return (struct xhci_ep_ctx *) + (ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params))); +} + /* All the xhci_tds in the ring's TD list should be freed at this point */ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) { @@ -209,11 +266,10 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) xhci_ring_free(xhci, dev->ep_rings[i]); if (dev->in_ctx) - dma_pool_free(xhci->device_pool, - dev->in_ctx, dev->in_ctx_dma); + xhci_free_container_ctx(xhci, dev->in_ctx); if (dev->out_ctx) - dma_pool_free(xhci->device_pool, - dev->out_ctx, dev->out_ctx_dma); + xhci_free_container_ctx(xhci, dev->out_ctx); + kfree(xhci->devs[slot_id]); xhci->devs[slot_id] = 0; } @@ -221,7 +277,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags) { - dma_addr_t dma; struct xhci_virt_device *dev; /* Slot ID 0 is reserved */ @@ -235,26 +290,21 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, return 0; dev = xhci->devs[slot_id]; - /* Allocate the (output) device context that will be used in the HC. - * The structure is 32 bytes smaller than the input context, but that's - * fine. - */ - dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); + /* Allocate the (output) device context that will be used in the HC. */ + dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags); if (!dev->out_ctx) goto fail; - dev->out_ctx_dma = dma; + xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dma); - memset(dev->out_ctx, 0, sizeof(*dev->out_ctx)); + (unsigned long long)dev->out_ctx->dma); /* Allocate the (input) device context for address device command */ - dev->in_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); + dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags); if (!dev->in_ctx) goto fail; - dev->in_ctx_dma = dma; + xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dma); - memset(dev->in_ctx, 0, sizeof(*dev->in_ctx)); + (unsigned long long)dev->in_ctx->dma); /* Allocate endpoint 0 ring */ dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags); @@ -264,7 +314,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, init_completion(&dev->cmd_completion); /* Point to output device context in dcbaa. */ - xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx_dma; + xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma; xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", slot_id, &xhci->dcbaa->dev_context_ptrs[slot_id], @@ -282,6 +332,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud struct xhci_virt_device *dev; struct xhci_ep_ctx *ep0_ctx; struct usb_device *top_dev; + struct xhci_slot_ctx *slot_ctx; + struct xhci_input_control_ctx *ctrl_ctx; dev = xhci->devs[udev->slot_id]; /* Slot ID 0 is reserved */ @@ -290,27 +342,29 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud udev->slot_id); return -EINVAL; } - ep0_ctx = &dev->in_ctx->ep[0]; + ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0); + ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx); + slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx); /* 2) New slot context and endpoint 0 context are valid*/ - dev->in_ctx->add_flags = SLOT_FLAG | EP0_FLAG; + ctrl_ctx->add_flags = SLOT_FLAG | EP0_FLAG; /* 3) Only the control endpoint is valid - one endpoint context */ - dev->in_ctx->slot.dev_info |= LAST_CTX(1); + slot_ctx->dev_info |= LAST_CTX(1); switch (udev->speed) { case USB_SPEED_SUPER: - dev->in_ctx->slot.dev_info |= (u32) udev->route; - dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_SS; + slot_ctx->dev_info |= (u32) udev->route; + slot_ctx->dev_info |= (u32) SLOT_SPEED_SS; break; case USB_SPEED_HIGH: - dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_HS; + slot_ctx->dev_info |= (u32) SLOT_SPEED_HS; break; case USB_SPEED_FULL: - dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_FS; + slot_ctx->dev_info |= (u32) SLOT_SPEED_FS; break; case USB_SPEED_LOW: - dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_LS; + slot_ctx->dev_info |= (u32) SLOT_SPEED_LS; break; case USB_SPEED_VARIABLE: xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); @@ -324,7 +378,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud for (top_dev = udev; top_dev->parent && top_dev->parent->parent; top_dev = top_dev->parent) /* Found device below root hub */; - dev->in_ctx->slot.dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum); + slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum); xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum); /* Is this a LS/FS device under a HS hub? */ @@ -334,8 +388,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud */ if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) && udev->tt) { - dev->in_ctx->slot.tt_info = udev->tt->hub->slot_id; - dev->in_ctx->slot.tt_info |= udev->ttport << 8; + slot_ctx->tt_info = udev->tt->hub->slot_id; + slot_ctx->tt_info |= udev->ttport << 8; } xhci_dbg(xhci, "udev->tt = %p\n", udev->tt); xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport); @@ -466,7 +520,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, unsigned int max_burst; ep_index = xhci_get_endpoint_index(&ep->desc); - ep_ctx = &virt_dev->in_ctx->ep[ep_index]; + ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); /* Set up the endpoint ring */ virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags); @@ -533,7 +587,7 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_ep_ctx *ep_ctx; ep_index = xhci_get_endpoint_index(&ep->desc); - ep_ctx = &virt_dev->in_ctx->ep[ep_index]; + ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); ep_ctx->ep_info = 0; ep_ctx->ep_info2 = 0; @@ -753,11 +807,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) */ xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, SEGMENT_SIZE, 64, xhci->page_size); + /* See Table 46 and Note on Figure 55 */ - /* FIXME support 64-byte contexts */ xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, - sizeof(struct xhci_device_control), - 64, xhci->page_size); + 2112, 64, xhci->page_size); if (!xhci->segment_pool || !xhci->device_pool) goto fail; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 0903e98989e..ea31753c313 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -362,6 +362,7 @@ static void find_new_dequeue_state(struct xhci_hcd *xhci, struct xhci_virt_device *dev = xhci->devs[slot_id]; struct xhci_ring *ep_ring = dev->ep_rings[ep_index]; struct xhci_generic_trb *trb; + struct xhci_ep_ctx *ep_ctx; state->new_cycle_state = 0; state->new_deq_seg = find_trb_seg(cur_td->start_seg, @@ -370,7 +371,8 @@ static void find_new_dequeue_state(struct xhci_hcd *xhci, if (!state->new_deq_seg) BUG(); /* Dig out the cycle state saved by the xHC during the stop ep cmd */ - state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq; + ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); + state->new_cycle_state = 0x1 & ep_ctx->deq; state->new_deq_ptr = cur_td->last_trb; state->new_deq_seg = find_trb_seg(state->new_deq_seg, @@ -570,11 +572,15 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, unsigned int ep_index; struct xhci_ring *ep_ring; struct xhci_virt_device *dev; + struct xhci_ep_ctx *ep_ctx; + struct xhci_slot_ctx *slot_ctx; slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); dev = xhci->devs[slot_id]; ep_ring = dev->ep_rings[ep_index]; + ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); + slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); if (GET_COMP_CODE(event->status) != COMP_SUCCESS) { unsigned int ep_state; @@ -588,9 +594,9 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, case COMP_CTX_STATE: xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due " "to incorrect slot or ep state.\n"); - ep_state = dev->out_ctx->ep[ep_index].ep_info; + ep_state = ep_ctx->ep_info; ep_state &= EP_STATE_MASK; - slot_state = dev->out_ctx->slot.dev_state; + slot_state = slot_ctx->dev_state; slot_state = GET_SLOT_STATE(slot_state); xhci_dbg(xhci, "Slot state = %u, EP state = %u\n", slot_state, ep_state); @@ -613,7 +619,7 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, */ } else { xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n", - dev->out_ctx->ep[ep_index].deq); + ep_ctx->deq); } ep_ring->state &= ~SET_DEQ_PENDING; @@ -795,6 +801,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, union xhci_trb *event_trb; struct urb *urb = 0; int status = -EINPROGRESS; + struct xhci_ep_ctx *ep_ctx; xhci_dbg(xhci, "In %s\n", __func__); xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)]; @@ -807,7 +814,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, ep_index = TRB_TO_EP_ID(event->flags) - 1; xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index); ep_ring = xdev->ep_rings[ep_index]; - if (!ep_ring || (xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) { + ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); + if (!ep_ring || (ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) { xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n"); return -ENODEV; } @@ -1193,9 +1201,9 @@ static int prepare_transfer(struct xhci_hcd *xhci, gfp_t mem_flags) { int ret; - + struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); ret = prepare_ring(xhci, xdev->ep_rings[ep_index], - xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK, + ep_ctx->ep_info & EP_STATE_MASK, num_trbs, mem_flags); if (ret) return ret; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index d4d3c7777fb..9c108c63270 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -446,6 +446,27 @@ struct xhci_doorbell_array { #define EPI_TO_DB(p) (((p) + 1) & 0xff) +/** + * struct xhci_container_ctx + * @type: Type of context. Used to calculated offsets to contained contexts. + * @size: Size of the context data + * @bytes: The raw context data given to HW + * @dma: dma address of the bytes + * + * Represents either a Device or Input context. Holds a pointer to the raw + * memory used for the context (bytes) and dma address of it (dma). + */ +struct xhci_container_ctx { + unsigned type; +#define XHCI_CTX_TYPE_DEVICE 0x1 +#define XHCI_CTX_TYPE_INPUT 0x2 + + int size; + + u8 *bytes; + dma_addr_t dma; +}; + /** * struct xhci_slot_ctx * @dev_info: Route string, device speed, hub info, and last valid endpoint @@ -583,32 +604,16 @@ struct xhci_ep_ctx { /** - * struct xhci_device_control - * Input context; see section 6.2.5. + * struct xhci_input_control_context + * Input control context; see section 6.2.5. * * @drop_context: set the bit of the endpoint context you want to disable * @add_context: set the bit of the endpoint context you want to enable */ -struct xhci_device_control { - /* Input control context */ +struct xhci_input_control_ctx { u32 drop_flags; u32 add_flags; - u32 rsvd[6]; - /* Copy of device context */ - struct xhci_slot_ctx slot; - struct xhci_ep_ctx ep[31]; -}; - -/** - * struct xhci_device_ctx - * Device context; see section 6.2.1. - * - * @slot: slot context for the device. - * @ep: array of endpoint contexts for the device. - */ -struct xhci_device_ctx { - struct xhci_slot_ctx slot; - struct xhci_ep_ctx ep[31]; + u32 rsvd2[6]; }; /* drop context bitmasks */ @@ -616,7 +621,6 @@ struct xhci_device_ctx { /* add context bitmasks */ #define ADD_EP(x) (0x1 << x) - struct xhci_virt_device { /* * Commands to the hardware are passed an "input context" that @@ -626,11 +630,10 @@ struct xhci_virt_device { * track of input and output contexts separately because * these commands might fail and we don't trust the hardware. */ - struct xhci_device_ctx *out_ctx; - dma_addr_t out_ctx_dma; + struct xhci_container_ctx *out_ctx; /* Used for addressing devices and configuration changes */ - struct xhci_device_control *in_ctx; - dma_addr_t in_ctx_dma; + struct xhci_container_ctx *in_ctx; + /* FIXME when stream support is added */ struct xhci_ring *ep_rings[31]; /* Temporary storage in case the configure endpoint command fails and we @@ -1139,8 +1142,7 @@ void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring); void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci); void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); -void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep); -void xhci_dbg_device_ctx(struct xhci_hcd *xhci, struct xhci_device_ctx *ctx, dma_addr_t dma, unsigned int last_ep); +void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep); /* xHCI memory managment */ void xhci_mem_cleanup(struct xhci_hcd *xhci); @@ -1207,4 +1209,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); +/* xHCI contexts */ +struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); +struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); +struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index); + #endif /* __LINUX_XHCI_HCD_H */ -- cgit v1.2.3 From c92bcfa7b4038d8ffe1f02e21269f18eb0b64144 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:05:21 -0700 Subject: USB: xhci: Stall handling bug fixes. Correct the xHCI code to handle stalls on USB endpoints. We need to move the endpoint ring's dequeue pointer past the stalled transfer, or the HW will try to restart the transfer the next time the doorbell is rung. Don't attempt to clear a halt on an endpoint if we haven't seen a stalled transfer for it. The USB core will attempt to clear a halt on all endpoints when it selects a new configuration. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 24 ++++++++ drivers/usb/host/xhci-ring.c | 133 +++++++++++++++++++++++++++---------------- drivers/usb/host/xhci.h | 12 ++++ 3 files changed, 120 insertions(+), 49 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 057a07e876b..816c39caca1 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -1089,6 +1089,8 @@ void xhci_endpoint_reset(struct usb_hcd *hcd, unsigned int ep_index; unsigned long flags; int ret; + struct xhci_dequeue_state deq_state; + struct xhci_ring *ep_ring; xhci = hcd_to_xhci(hcd); udev = (struct usb_device *) ep->hcpriv; @@ -1098,11 +1100,33 @@ void xhci_endpoint_reset(struct usb_hcd *hcd, if (!ep->hcpriv) return; ep_index = xhci_get_endpoint_index(&ep->desc); + ep_ring = xhci->devs[udev->slot_id]->ep_rings[ep_index]; + if (!ep_ring->stopped_td) { + xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n", + ep->desc.bEndpointAddress); + return; + } xhci_dbg(xhci, "Queueing reset endpoint command\n"); spin_lock_irqsave(&xhci->lock, flags); ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index); + /* + * Can't change the ring dequeue pointer until it's transitioned to the + * stopped state, which is only upon a successful reset endpoint + * command. Better hope that last command worked! + */ if (!ret) { + xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n"); + /* We need to move the HW's dequeue pointer past this TD, + * or it will attempt to resend it on the next doorbell ring. + */ + xhci_find_new_dequeue_state(xhci, udev->slot_id, + ep_index, ep_ring->stopped_td, &deq_state); + xhci_dbg(xhci, "Queueing new dequeue state\n"); + xhci_queue_new_dequeue_state(xhci, ep_ring, + udev->slot_id, + ep_index, &deq_state); + kfree(ep_ring->stopped_td); xhci_ring_cmd_db(xhci); } spin_unlock_irqrestore(&xhci->lock, flags); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ea31753c313..aa88a067148 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -335,12 +335,6 @@ static struct xhci_segment *find_trb_seg( return cur_seg; } -struct dequeue_state { - struct xhci_segment *new_deq_seg; - union xhci_trb *new_deq_ptr; - int new_cycle_state; -}; - /* * Move the xHC's endpoint ring dequeue pointer past cur_td. * Record the new state of the xHC's endpoint ring dequeue segment, @@ -355,26 +349,30 @@ struct dequeue_state { * - Finally we move the dequeue state one TRB further, toggling the cycle bit * if we've moved it past a link TRB with the toggle cycle bit set. */ -static void find_new_dequeue_state(struct xhci_hcd *xhci, +void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, - struct xhci_td *cur_td, struct dequeue_state *state) + struct xhci_td *cur_td, struct xhci_dequeue_state *state) { struct xhci_virt_device *dev = xhci->devs[slot_id]; struct xhci_ring *ep_ring = dev->ep_rings[ep_index]; struct xhci_generic_trb *trb; struct xhci_ep_ctx *ep_ctx; + dma_addr_t addr; state->new_cycle_state = 0; + xhci_dbg(xhci, "Finding segment containing stopped TRB.\n"); state->new_deq_seg = find_trb_seg(cur_td->start_seg, ep_ring->stopped_trb, &state->new_cycle_state); if (!state->new_deq_seg) BUG(); /* Dig out the cycle state saved by the xHC during the stop ep cmd */ + xhci_dbg(xhci, "Finding endpoint context\n"); ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); state->new_cycle_state = 0x1 & ep_ctx->deq; state->new_deq_ptr = cur_td->last_trb; + xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n"); state->new_deq_seg = find_trb_seg(state->new_deq_seg, state->new_deq_ptr, &state->new_cycle_state); @@ -388,6 +386,12 @@ static void find_new_dequeue_state(struct xhci_hcd *xhci, next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr); /* Don't update the ring cycle state for the producer (us). */ + xhci_dbg(xhci, "New dequeue segment = %p (virtual)\n", + state->new_deq_seg); + addr = xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr); + xhci_dbg(xhci, "New dequeue pointer = 0x%llx (DMA)\n", + (unsigned long long) addr); + xhci_dbg(xhci, "Setting dequeue pointer in internal ring state.\n"); ep_ring->dequeue = state->new_deq_ptr; ep_ring->deq_seg = state->new_deq_seg; } @@ -437,6 +441,30 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, unsigned int ep_index, struct xhci_segment *deq_seg, union xhci_trb *deq_ptr, u32 cycle_state); +void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, + struct xhci_ring *ep_ring, unsigned int slot_id, + unsigned int ep_index, struct xhci_dequeue_state *deq_state) +{ + xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " + "new deq ptr = %p (0x%llx dma), new cycle = %u\n", + deq_state->new_deq_seg, + (unsigned long long)deq_state->new_deq_seg->dma, + deq_state->new_deq_ptr, + (unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr), + deq_state->new_cycle_state); + queue_set_tr_deq(xhci, slot_id, ep_index, + deq_state->new_deq_seg, + deq_state->new_deq_ptr, + (u32) deq_state->new_cycle_state); + /* Stop the TD queueing code from ringing the doorbell until + * this command completes. The HC won't set the dequeue pointer + * if the ring is running, and ringing the doorbell starts the + * ring running. + */ + ep_ring->state |= SET_DEQ_PENDING; + xhci_ring_cmd_db(xhci); +} + /* * When we get a command completion for a Stop Endpoint Command, we need to * unlink any cancelled TDs from the ring. There are two ways to do that: @@ -457,7 +485,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, struct xhci_td *cur_td = 0; struct xhci_td *last_unlinked_td; - struct dequeue_state deq_state; + struct xhci_dequeue_state deq_state; #ifdef CONFIG_USB_HCD_STAT ktime_t stop_time = ktime_get(); #endif @@ -485,7 +513,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, * move the xHC endpoint ring dequeue pointer past this TD. */ if (cur_td == ep_ring->stopped_td) - find_new_dequeue_state(xhci, slot_id, ep_index, cur_td, + xhci_find_new_dequeue_state(xhci, slot_id, ep_index, cur_td, &deq_state); else td_to_noop(xhci, ep_ring, cur_td); @@ -501,24 +529,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { - xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " - "new deq ptr = %p (0x%llx dma), new cycle = %u\n", - deq_state.new_deq_seg, - (unsigned long long)deq_state.new_deq_seg->dma, - deq_state.new_deq_ptr, - (unsigned long long)xhci_trb_virt_to_dma(deq_state.new_deq_seg, deq_state.new_deq_ptr), - deq_state.new_cycle_state); - queue_set_tr_deq(xhci, slot_id, ep_index, - deq_state.new_deq_seg, - deq_state.new_deq_ptr, - (u32) deq_state.new_cycle_state); - /* Stop the TD queueing code from ringing the doorbell until - * this command completes. The HC won't set the dequeue pointer - * if the ring is running, and ringing the doorbell starts the - * ring running. - */ - ep_ring->state |= SET_DEQ_PENDING; - xhci_ring_cmd_db(xhci); + xhci_queue_new_dequeue_state(xhci, ep_ring, + slot_id, ep_index, &deq_state); } else { /* Otherwise just ring the doorbell to restart the ring */ ring_ep_doorbell(xhci, slot_id, ep_index); @@ -929,12 +941,15 @@ static int handle_tx_event(struct xhci_hcd *xhci, if (event_trb != ep_ring->dequeue) { /* The event was for the status stage */ if (event_trb == td->last_trb) { - /* Did we already see a short data stage? */ - if (td->urb->actual_length != 0) - status = -EREMOTEIO; - else + if (td->urb->actual_length != 0) { + /* Don't overwrite a previously set error code */ + if (status == -EINPROGRESS || status == 0) + /* Did we already see a short data stage? */ + status = -EREMOTEIO; + } else { td->urb->actual_length = td->urb->transfer_buffer_length; + } } else { /* Maybe the event was for the data stage? */ if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) { @@ -992,16 +1007,20 @@ static int handle_tx_event(struct xhci_hcd *xhci, TRB_LEN(event->transfer_len)); td->urb->actual_length = 0; } - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) - status = -EREMOTEIO; - else - status = 0; + /* Don't overwrite a previously set error code */ + if (status == -EINPROGRESS) { + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) + status = -EREMOTEIO; + else + status = 0; + } } else { td->urb->actual_length = td->urb->transfer_buffer_length; /* Ignore a short packet completion if the * untransferred length was zero. */ - status = 0; + if (status == -EREMOTEIO) + status = 0; } } else { /* Slow path - walk the list, starting from the dequeue @@ -1028,19 +1047,30 @@ static int handle_tx_event(struct xhci_hcd *xhci, TRB_LEN(event->transfer_len); } } - /* The Endpoint Stop Command completion will take care of - * any stopped TDs. A stopped TD may be restarted, so don't update the - * ring dequeue pointer or take this TD off any lists yet. - */ if (GET_COMP_CODE(event->transfer_len) == COMP_STOP_INVAL || GET_COMP_CODE(event->transfer_len) == COMP_STOP) { + /* The Endpoint Stop Command completion will take care of any + * stopped TDs. A stopped TD may be restarted, so don't update + * the ring dequeue pointer or take this TD off any lists yet. + */ ep_ring->stopped_td = td; ep_ring->stopped_trb = event_trb; } else { - /* Update ring dequeue pointer */ - while (ep_ring->dequeue != td->last_trb) + if (GET_COMP_CODE(event->transfer_len) == COMP_STALL) { + /* The transfer is completed from the driver's + * perspective, but we need to issue a set dequeue + * command for this stalled endpoint to move the dequeue + * pointer past the TD. We can't do that here because + * the halt condition must be cleared first. + */ + ep_ring->stopped_td = td; + ep_ring->stopped_trb = event_trb; + } else { + /* Update ring dequeue pointer */ + while (ep_ring->dequeue != td->last_trb) + inc_deq(xhci, ep_ring, false); inc_deq(xhci, ep_ring, false); - inc_deq(xhci, ep_ring, false); + } /* Clean up the endpoint's TD list */ urb = td->urb; @@ -1050,7 +1080,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, list_del(&td->cancelled_td_list); ep_ring->cancels_pending--; } - kfree(td); + /* Leave the TD around for the reset endpoint function to use */ + if (GET_COMP_CODE(event->transfer_len) != COMP_STALL) { + kfree(td); + } urb->hcpriv = NULL; } cleanup: @@ -1166,13 +1199,13 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, */ xhci_warn(xhci, "WARN urb submitted to disabled ep\n"); return -ENOENT; - case EP_STATE_HALTED: case EP_STATE_ERROR: - xhci_warn(xhci, "WARN waiting for halt or error on ep " - "to be cleared\n"); + xhci_warn(xhci, "WARN waiting for error on ep to be cleared\n"); /* FIXME event handling code for error needs to clear it */ /* XXX not sure if this should be -ENOENT or not */ return -EINVAL; + case EP_STATE_HALTED: + xhci_dbg(xhci, "WARN halted endpoint, queueing URB anyway.\n"); case EP_STATE_STOPPED: case EP_STATE_RUNNING: break; @@ -1724,10 +1757,12 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, u32 type = TRB_TYPE(TRB_SET_DEQ); addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr); - if (addr == 0) + if (addr == 0) { xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n"); xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n", deq_seg, deq_ptr); + return 0; + } return queue_command(xhci, lower_32_bits(addr) | cycle_state, upper_32_bits(addr), 0, trb_slot_id | trb_ep_index | type); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 9c108c63270..d31d32206ba 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -952,6 +952,12 @@ struct xhci_ring { u32 cycle_state; }; +struct xhci_dequeue_state { + struct xhci_segment *new_deq_seg; + union xhci_trb *new_deq_ptr; + int new_cycle_state; +}; + struct xhci_erst_entry { /* 64-bit event ring segment address */ u64 seg_addr; @@ -1203,6 +1209,12 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id); int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, unsigned int ep_index); +void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, + unsigned int slot_id, unsigned int ep_index, + struct xhci_td *cur_td, struct xhci_dequeue_state *state); +void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, + struct xhci_ring *ep_ring, unsigned int slot_id, + unsigned int ep_index, struct xhci_dequeue_state *deq_state); /* xHCI roothub code */ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, -- cgit v1.2.3 From 49276560c9004fce24c42e3c0ad75f34d956fc63 Mon Sep 17 00:00:00 2001 From: Khanh-Dang Nguyen Thu Lam Date: Tue, 28 Jul 2009 19:41:17 +0200 Subject: USB: pl2303: New vendor and product id I am submitting a patch for the pl2303 driver. This patch adds support for the "Sony QN-3USB" cable (vendor=0x054c, product=0x0437). This USB cable is a so-called data cable used to connect a Sony mobile phone to a computer. Supported models are Sony CMD-J5, J6, J7, J16, J26, J70 and Z7. I have used this patch with my Sony CMD-J70 for several days and I haven't encountered any kernel/hardware issue. From: Khanh-Dang Nguyen Thu Lam Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/pl2303.h | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 7d15bfa7c2d..3e86815b270 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -95,6 +95,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 12aac7d2462..ee9505e1dd9 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -126,3 +126,7 @@ /* Cressi Edy (diving computer) PC interface */ #define CRESSI_VENDOR_ID 0x04b8 #define CRESSI_EDY_PRODUCT_ID 0x0521 + +/* Sony, USB data cable for CMD-Jxx mobile phones */ +#define SONY_VENDOR_ID 0x054c +#define SONY_QN3USB_PRODUCT_ID 0x0437 -- cgit v1.2.3 From 18753ebc8a98efe0e8ff6167afb31cef220c8e50 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 29 Jul 2009 11:39:03 +0200 Subject: USB: devio: Properly do access_ok() checks access_ok() checks must be done on every part of the userspace structure that is accessed. If access_ok() on one part of the struct succeeded, it does not imply it will succeed on other parts of the struct. (Does depend on the architecture implementation of access_ok()). This changes the __get_user() users to first check access_ok() on the data structure. Signed-off-by: Michael Buesch Cc: stable Cc: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 38b8bce782d..e192fa05f8a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1321,7 +1321,8 @@ static int get_urb32(struct usbdevfs_urb *kurb, struct usbdevfs_urb32 __user *uurb) { __u32 uptr; - if (get_user(kurb->type, &uurb->type) || + if (!access_ok(VERIFY_READ, uurb, sizeof(*uurb)) || + __get_user(kurb->type, &uurb->type) || __get_user(kurb->endpoint, &uurb->endpoint) || __get_user(kurb->status, &uurb->status) || __get_user(kurb->flags, &uurb->flags) || @@ -1536,8 +1537,9 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) u32 udata; uioc = compat_ptr((long)arg); - if (get_user(ctrl.ifno, &uioc->ifno) || - get_user(ctrl.ioctl_code, &uioc->ioctl_code) || + if (!access_ok(VERIFY_READ, uioc, sizeof(*uioc)) || + __get_user(ctrl.ifno, &uioc->ifno) || + __get_user(ctrl.ioctl_code, &uioc->ioctl_code) || __get_user(udata, &uioc->data)) return -EFAULT; ctrl.data = compat_ptr(udata); -- cgit v1.2.3 From e8e2ff462dd92693f29eb848f42d3eb720390d59 Mon Sep 17 00:00:00 2001 From: "Gupta, Ajay Kumar" Date: Wed, 29 Jul 2009 11:58:57 +0530 Subject: USB: musb: fix the nop registration for OMAP3EVM OMAP3EVM uses ISP1504 phy which doesn't require any programming and thus has to use NOP otg transceiver. Cleanups being done: - Remove unwanted code in usb-musb.c file - Register NOP in OMAP3EVM board file using usb_nop_xceiv_register(). - Select NOP_USB_XCEIV for OMAP3EVM boards. - Don't enable TWL4030_USB in omap3_evm_defconfig Signed-off-by: Ajay Kumar Gupta Signed-off-by: Eino-Ville Talvala Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 70073b157f0..803adcb5ac1 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -12,6 +12,7 @@ config USB_MUSB_HDRC depends on !SUPERH select NOP_USB_XCEIV if ARCH_DAVINCI select TWL4030_USB if MACH_OMAP_3430SDP + select NOP_USB_XCEIV if MACH_OMAP3EVM select USB_OTG_UTILS tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' help -- cgit v1.2.3 From 01105a246345f011fde64d24a601090b646e9e4c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 30 Jul 2009 15:28:14 -0400 Subject: USB: usbfs: fix -ENOENT error code to be -ENODEV This patch (as1272) changes the error code returned when an open call for a USB device node fails to locate the corresponding device. The appropriate error code is -ENODEV, not -ENOENT. Signed-off-by: Alan Stern CC: Kay Sievers Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e192fa05f8a..4247eccf858 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -595,7 +595,7 @@ static int usbdev_open(struct inode *inode, struct file *file) if (!ps) goto out; - ret = -ENOENT; + ret = -ENODEV; /* usbdev device-node */ if (imajor(inode) == USB_DEVICE_MAJOR) -- cgit v1.2.3 From 7a0f0d951273eee889c2441846842348ebc00a2a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 31 Jul 2009 10:40:22 -0400 Subject: USB: EHCI: fix two new bugs related to Clear-TT-Buffer This patch (as1273) fixes two(!) bugs introduced by the new Clear-TT-Buffer implementation in ehci-hcd. It is now possible for an idle QH to have some URBs on its queue -- this will happen if a Clear-TT-Buffer is pending for the QH's endpoint. Consequently we should not issue a warning when someone tries to unlink an URB from an idle QH; instead we should process the request immediately. The refcounts for QHs could get messed up, because submit_async() would increment the refcount when calling qh_link_async() and qh_link_async() would then refuse to link the QH into the schedule if a Clear-TT-Buffer was pending. Instead we should increment the refcount only when the QH actually is added to the schedule. The current code tries to be clever by leaving the refcount alone if an unlink is immediately followed by a relink; the patch changes this to an unconditional decrement and increment (although they occur in the opposite order). Signed-off-by: Alan Stern CC: David Brownell Tested-by: Manuel Lauss Tested-by: Matthijs Kooijman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 3 ++- drivers/usb/host/ehci-q.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 7d03549c333..11c627ce602 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -903,7 +903,8 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) /* already started */ break; case QH_STATE_IDLE: - WARN_ON(1); + /* QH might be waiting for a Clear-TT-Buffer */ + qh_completions(ehci, qh); break; } break; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 9a1384747f3..b2738050557 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -940,6 +940,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head->qh_next.qh = qh; head->hw_next = dma; + qh_get(qh); qh->xacterrs = QH_XACTERR_MAX; qh->qh_state = QH_STATE_LINKED; /* qtd completions reported later by interrupt */ @@ -1080,7 +1081,7 @@ submit_async ( * the HC and TT handle it when the TT has a buffer ready. */ if (likely (qh->qh_state == QH_STATE_IDLE)) - qh_link_async (ehci, qh_get (qh)); + qh_link_async(ehci, qh); done: spin_unlock_irqrestore (&ehci->lock, flags); if (unlikely (qh == NULL)) @@ -1115,8 +1116,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) qh_link_async (ehci, qh); else { - qh_put (qh); // refcount from async list - /* it's not free to turn the async schedule on/off; leave it * active but idle for a while once it empties. */ @@ -1124,6 +1123,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) && ehci->async->qh_next.qh == NULL) timer_action (ehci, TIMER_ASYNC_OFF); } + qh_put(qh); /* refcount from async list */ if (next) { ehci->reclaim = NULL; -- cgit v1.2.3 From ef4638f955f2c4a667c8af20769d03f5ed3781ca Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 31 Jul 2009 10:41:40 -0400 Subject: USB: EHCI: fix counting of transaction error retries This patch (as1274) simplifies the counting of transaction-error retries. Now we will count up from 0 to QH_XACTERR_MAX instead of down from QH_XACTERR_MAX to 0. The patch also fixes a small bug: qh->xacterr was not getting initialized for interrupt endpoints. Signed-off-by: Alan Stern Tested-by: Matthijs Kooijman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 9 ++++----- drivers/usb/host/ehci-sched.c | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index b2738050557..7673554fa64 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -375,12 +375,11 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) */ if ((token & QTD_STS_XACT) && QTD_CERR(token) == 0 && - --qh->xacterrs > 0 && + ++qh->xacterrs < QH_XACTERR_MAX && !urb->unlinked) { ehci_dbg(ehci, "detected XactErr len %zu/%zu retry %d\n", - qtd->length - QTD_LENGTH(token), qtd->length, - QH_XACTERR_MAX - qh->xacterrs); + qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs); /* reset the token in the qtd and the * qh overlay (which still contains @@ -494,7 +493,7 @@ halt: last = qtd; /* reinit the xacterr counter for the next qtd */ - qh->xacterrs = QH_XACTERR_MAX; + qh->xacterrs = 0; } /* last urb's completion might still need calling */ @@ -941,7 +940,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head->hw_next = dma; qh_get(qh); - qh->xacterrs = QH_XACTERR_MAX; + qh->xacterrs = 0; qh->qh_state = QH_STATE_LINKED; /* qtd completions reported later by interrupt */ } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 74f7f83b29a..edd61ee9032 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -542,6 +542,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) } } qh->qh_state = QH_STATE_LINKED; + qh->xacterrs = 0; qh_get (qh); /* update per-qh bandwidth for usbfs */ -- cgit v1.2.3 From c47aacc67a3d26dfab9c9b8965975ed2b2010b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20H=C3=A4nninen?= Date: Fri, 31 Jul 2009 22:32:39 +0300 Subject: USB: ftdi_sio: add vendor and product id for Bayer glucose meter serial converter cable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Attached patch adds USB vendor and product IDs for Bayer's USB to serial converter cable used by Bayer blood glucose meters. It seems to be a FT232RL based device and works without any problem with ftdi_sio driver when this patch is applied. See: http://winglucofacts.com/cables/ Signed-off-by: Marko Hänninen Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b574878c78b..500087ea58a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -699,6 +699,7 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, + { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 24dbd99e87d..f203b2a5130 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -953,6 +953,13 @@ #define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */ #define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */ +/* + * Bayer Ascensia Contour blood glucose meter USB-converter cable. + * http://winglucofacts.com/cables/ + */ +#define BAYER_VID 0x1A79 +#define BAYER_CONTOUR_CABLE_PID 0x6001 + /* * BmRequestType: 1100 0000b * bRequest: FTDI_E2_READ -- cgit v1.2.3 From 50d0678e2026c18e4147f0b16b5853113659b82d Mon Sep 17 00:00:00 2001 From: Dhaval Vasa Date: Fri, 7 Aug 2009 17:26:49 +0530 Subject: USB: ftdi_sio: add product_id for Marvell OpenRD Base, Client reference: http://www.open-rd.org Signed-off-by: Dhaval Vasa Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio.h | 7 +++++++ 2 files changed, 9 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 500087ea58a..8fec5d4455c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -700,6 +700,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, + { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index f203b2a5130..8c92b88166a 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -960,6 +960,13 @@ #define BAYER_VID 0x1A79 #define BAYER_CONTOUR_CABLE_PID 0x6001 +/* + * Marvell OpenRD Base, Client + * http://www.open-rd.org + * OpenRD Base, Client use VID 0x0403 + */ +#define MARVELL_OPENRD_PID 0x9e90 + /* * BmRequestType: 1100 0000b * bRequest: FTDI_E2_READ -- cgit v1.2.3 From c15e3ca1d822abba78c00b1ffc3e7b382a50396e Mon Sep 17 00:00:00 2001 From: Rogerio Brito Date: Thu, 6 Aug 2009 15:20:19 -0700 Subject: USB: storage: include Prolific Technology USB drive in unusual_devs list Add a quirk entry for the Leading Driver UD-11 usb flash drive. As Alan Stern told me, the device doesn't deal correctly with the locking media feature of the device, and this patch incorporates it. Compiled, tested, working. Signed-off-by: Rogerio Brito Cc: Phil Dibowitz Cc: Alan Stern Cc: Robert Hancock Cc: stable Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 1b9c5dd0fb2..7477d411959 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -838,6 +838,13 @@ UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* Reported by Rogerio Brito */ +UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001, + "Prolific Technology, Inc.", + "Mass Storage Device", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_NOT_LOCKABLE ), + /* Reported by Richard -=[]=- */ /* Change to bcdDeviceMin (0x0100 to 0x0001) reported by * Thomas Bartosik */ -- cgit v1.2.3 From cf7fdd57f978d40ceb9a0f58a25f5cf9c84d6f33 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 4 Aug 2009 23:52:09 +0200 Subject: USB: fix oops on disconnect in cdc-acm This patch fixes an oops caused when during an unplug a device's table of endpoints is zeroed before the driver is notified. A pointer to the endpoint must be cached. this fixes a regression caused by commit 5186ffee2320942c3dc9745f7930e0eb15329ca6 Therefore it should go into 2.6.31 Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 10 +++++----- drivers/usb/class/cdc-acm.h | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e1f89416ef8..2bfc41ece0e 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -387,7 +387,6 @@ static void acm_rx_tasklet(unsigned long _acm) struct acm_ru *rcv; unsigned long flags; unsigned char throttled; - struct usb_host_endpoint *ep; dbg("Entering acm_rx_tasklet"); @@ -463,14 +462,12 @@ urbs: rcv->buffer = buf; - ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out) - [usb_pipeendpoint(acm->rx_endpoint)]; - if (usb_endpoint_xfer_int(&ep->desc)) + if (acm->is_int_ep) usb_fill_int_urb(rcv->urb, acm->dev, acm->rx_endpoint, buf->base, acm->readsize, - acm_read_bulk, rcv, ep->desc.bInterval); + acm_read_bulk, rcv, acm->bInterval); else usb_fill_bulk_urb(rcv->urb, acm->dev, acm->rx_endpoint, @@ -1183,6 +1180,9 @@ made_compressed_probe: spin_lock_init(&acm->read_lock); mutex_init(&acm->mutex); acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); + acm->is_int_ep = usb_endpoint_xfer_int(epread); + if (acm->is_int_ep) + acm->bInterval = epread->bInterval; tty_port_init(&acm->port); acm->port.ops = &acm_port_ops; diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 1602324808b..c4a0ee8ffcc 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -126,6 +126,8 @@ struct acm { unsigned int ctrl_caps; /* control capabilities from the class specific header */ unsigned int susp_count; /* number of suspended interfaces */ int combined_interfaces:1; /* control and data collapsed */ + int is_int_ep:1; /* interrupt endpoints contrary to spec used */ + u8 bInterval; struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ }; -- cgit v1.2.3