Commit cb9cae03 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6:
  USB: update Kconfig help text for CONFIG_USB_SUSPEND
  usb: musb: gadget: restart request on clearing endpoint halt
  usb: musb: host: Issue a memory barrier before starting DMA
  usb: musb: gadget: fix dma length in txstate
  usb: musb: gadget: complete request only if data is transfered over
  usb: musb: gadget: fix DMA length for OUT transfer
  usb: musb: gadget: enable autoclear for OUT transfer in both DMA 0 and DMA 1
  usb: musb: gadget: fix bulk IN infinit hangs in double buffer case
  usb: musb: gadget: fix kernel panic if using out ep with FIFO_TXRX style
  USB: fix bug in initialization of interface minor numbers
parents 06706b58 2dab3948
...@@ -91,12 +91,12 @@ config USB_DYNAMIC_MINORS ...@@ -91,12 +91,12 @@ config USB_DYNAMIC_MINORS
If you are unsure about this, say N here. If you are unsure about this, say N here.
config USB_SUSPEND config USB_SUSPEND
bool "USB runtime power management (suspend/resume and wakeup)" bool "USB runtime power management (autosuspend) and wakeup"
depends on USB && PM_RUNTIME depends on USB && PM_RUNTIME
help help
If you say Y here, you can use driver calls or the sysfs If you say Y here, you can use driver calls or the sysfs
"power/level" file to suspend or resume individual USB "power/control" file to enable or disable autosuspend for
peripherals and to enable or disable autosuspend (see individual USB peripherals (see
Documentation/usb/power-management.txt for more details). Documentation/usb/power-management.txt for more details).
Also, USB "remote wakeup" signaling is supported, whereby some Also, USB "remote wakeup" signaling is supported, whereby some
......
...@@ -159,9 +159,9 @@ void usb_major_cleanup(void) ...@@ -159,9 +159,9 @@ void usb_major_cleanup(void)
int usb_register_dev(struct usb_interface *intf, int usb_register_dev(struct usb_interface *intf,
struct usb_class_driver *class_driver) struct usb_class_driver *class_driver)
{ {
int retval = -EINVAL; int retval;
int minor_base = class_driver->minor_base; int minor_base = class_driver->minor_base;
int minor = 0; int minor;
char name[20]; char name[20];
char *temp; char *temp;
...@@ -173,12 +173,17 @@ int usb_register_dev(struct usb_interface *intf, ...@@ -173,12 +173,17 @@ int usb_register_dev(struct usb_interface *intf,
*/ */
minor_base = 0; minor_base = 0;
#endif #endif
intf->minor = -1;
dbg ("looking for a minor, starting at %d", minor_base);
if (class_driver->fops == NULL) if (class_driver->fops == NULL)
goto exit; return -EINVAL;
if (intf->minor >= 0)
return -EADDRINUSE;
retval = init_usb_class();
if (retval)
return retval;
dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base);
down_write(&minor_rwsem); down_write(&minor_rwsem);
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) { for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
...@@ -186,20 +191,12 @@ int usb_register_dev(struct usb_interface *intf, ...@@ -186,20 +191,12 @@ int usb_register_dev(struct usb_interface *intf,
continue; continue;
usb_minors[minor] = class_driver->fops; usb_minors[minor] = class_driver->fops;
intf->minor = minor;
retval = 0;
break; break;
} }
up_write(&minor_rwsem); up_write(&minor_rwsem);
if (intf->minor < 0)
if (retval) return -EXFULL;
goto exit;
retval = init_usb_class();
if (retval)
goto exit;
intf->minor = minor;
/* create a usb class device for this usb interface */ /* create a usb class device for this usb interface */
snprintf(name, sizeof(name), class_driver->name, minor - minor_base); snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
...@@ -213,11 +210,11 @@ int usb_register_dev(struct usb_interface *intf, ...@@ -213,11 +210,11 @@ int usb_register_dev(struct usb_interface *intf,
"%s", temp); "%s", temp);
if (IS_ERR(intf->usb_dev)) { if (IS_ERR(intf->usb_dev)) {
down_write(&minor_rwsem); down_write(&minor_rwsem);
usb_minors[intf->minor] = NULL; usb_minors[minor] = NULL;
intf->minor = -1;
up_write(&minor_rwsem); up_write(&minor_rwsem);
retval = PTR_ERR(intf->usb_dev); retval = PTR_ERR(intf->usb_dev);
} }
exit:
return retval; return retval;
} }
EXPORT_SYMBOL_GPL(usb_register_dev); EXPORT_SYMBOL_GPL(usb_register_dev);
......
...@@ -1802,6 +1802,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1802,6 +1802,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
intf->dev.groups = usb_interface_groups; intf->dev.groups = usb_interface_groups;
intf->dev.dma_mask = dev->dev.dma_mask; intf->dev.dma_mask = dev->dev.dma_mask;
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device); INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
intf->minor = -1;
device_initialize(&intf->dev); device_initialize(&intf->dev);
dev_set_name(&intf->dev, "%d-%s:%d.%d", dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath, dev->bus->busnum, dev->devpath,
......
...@@ -322,6 +322,7 @@ cppi_channel_allocate(struct dma_controller *c, ...@@ -322,6 +322,7 @@ cppi_channel_allocate(struct dma_controller *c,
index, transmit ? 'T' : 'R', cppi_ch); index, transmit ? 'T' : 'R', cppi_ch);
cppi_ch->hw_ep = ep; cppi_ch->hw_ep = ep;
cppi_ch->channel.status = MUSB_DMA_STATUS_FREE; cppi_ch->channel.status = MUSB_DMA_STATUS_FREE;
cppi_ch->channel.max_len = 0x7fffffff;
DBG(4, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R'); DBG(4, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R');
return &cppi_ch->channel; return &cppi_ch->channel;
......
...@@ -300,6 +300,11 @@ static void txstate(struct musb *musb, struct musb_request *req) ...@@ -300,6 +300,11 @@ static void txstate(struct musb *musb, struct musb_request *req)
#ifndef CONFIG_MUSB_PIO_ONLY #ifndef CONFIG_MUSB_PIO_ONLY
if (is_dma_capable() && musb_ep->dma) { if (is_dma_capable() && musb_ep->dma) {
struct dma_controller *c = musb->dma_controller; struct dma_controller *c = musb->dma_controller;
size_t request_size;
/* setup DMA, then program endpoint CSR */
request_size = min_t(size_t, request->length - request->actual,
musb_ep->dma->max_len);
use_dma = (request->dma != DMA_ADDR_INVALID); use_dma = (request->dma != DMA_ADDR_INVALID);
...@@ -307,11 +312,6 @@ static void txstate(struct musb *musb, struct musb_request *req) ...@@ -307,11 +312,6 @@ static void txstate(struct musb *musb, struct musb_request *req)
#ifdef CONFIG_USB_INVENTRA_DMA #ifdef CONFIG_USB_INVENTRA_DMA
{ {
size_t request_size;
/* setup DMA, then program endpoint CSR */
request_size = min_t(size_t, request->length,
musb_ep->dma->max_len);
if (request_size < musb_ep->packet_sz) if (request_size < musb_ep->packet_sz)
musb_ep->dma->desired_mode = 0; musb_ep->dma->desired_mode = 0;
else else
...@@ -373,8 +373,8 @@ static void txstate(struct musb *musb, struct musb_request *req) ...@@ -373,8 +373,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
use_dma = use_dma && c->channel_program( use_dma = use_dma && c->channel_program(
musb_ep->dma, musb_ep->packet_sz, musb_ep->dma, musb_ep->packet_sz,
0, 0,
request->dma, request->dma + request->actual,
request->length); request_size);
if (!use_dma) { if (!use_dma) {
c->channel_release(musb_ep->dma); c->channel_release(musb_ep->dma);
musb_ep->dma = NULL; musb_ep->dma = NULL;
...@@ -386,8 +386,8 @@ static void txstate(struct musb *musb, struct musb_request *req) ...@@ -386,8 +386,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
use_dma = use_dma && c->channel_program( use_dma = use_dma && c->channel_program(
musb_ep->dma, musb_ep->packet_sz, musb_ep->dma, musb_ep->packet_sz,
request->zero, request->zero,
request->dma, request->dma + request->actual,
request->length); request_size);
#endif #endif
} }
#endif #endif
...@@ -501,26 +501,14 @@ void musb_g_tx(struct musb *musb, u8 epnum) ...@@ -501,26 +501,14 @@ void musb_g_tx(struct musb *musb, u8 epnum)
request->zero = 0; request->zero = 0;
} }
/* ... or if not, then complete it. */ if (request->actual == request->length) {
musb_g_giveback(musb_ep, request, 0); musb_g_giveback(musb_ep, request, 0);
request = musb_ep->desc ? next_request(musb_ep) : NULL;
/* if (!request) {
* Kickstart next transfer if appropriate; DBG(4, "%s idle now\n",
* the packet that just completed might not musb_ep->end_point.name);
* be transmitted for hours or days. return;
* REVISIT for double buffering... }
* FIXME revisit for stalls too...
*/
musb_ep_select(mbase, epnum);
csr = musb_readw(epio, MUSB_TXCSR);
if (csr & MUSB_TXCSR_FIFONOTEMPTY)
return;
request = musb_ep->desc ? next_request(musb_ep) : NULL;
if (!request) {
DBG(4, "%s idle now\n",
musb_ep->end_point.name);
return;
} }
} }
...@@ -568,11 +556,19 @@ static void rxstate(struct musb *musb, struct musb_request *req) ...@@ -568,11 +556,19 @@ static void rxstate(struct musb *musb, struct musb_request *req)
{ {
const u8 epnum = req->epnum; const u8 epnum = req->epnum;
struct usb_request *request = &req->request; struct usb_request *request = &req->request;
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out; struct musb_ep *musb_ep;
void __iomem *epio = musb->endpoints[epnum].regs; void __iomem *epio = musb->endpoints[epnum].regs;
unsigned fifo_count = 0; unsigned fifo_count = 0;
u16 len = musb_ep->packet_sz; u16 len;
u16 csr = musb_readw(epio, MUSB_RXCSR); u16 csr = musb_readw(epio, MUSB_RXCSR);
struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
if (hw_ep->is_shared_fifo)
musb_ep = &hw_ep->ep_in;
else
musb_ep = &hw_ep->ep_out;
len = musb_ep->packet_sz;
/* We shouldn't get here while DMA is active, but we do... */ /* We shouldn't get here while DMA is active, but we do... */
if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
...@@ -647,8 +643,8 @@ static void rxstate(struct musb *musb, struct musb_request *req) ...@@ -647,8 +643,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
*/ */
csr |= MUSB_RXCSR_DMAENAB; csr |= MUSB_RXCSR_DMAENAB;
#ifdef USE_MODE1
csr |= MUSB_RXCSR_AUTOCLEAR; csr |= MUSB_RXCSR_AUTOCLEAR;
#ifdef USE_MODE1
/* csr |= MUSB_RXCSR_DMAMODE; */ /* csr |= MUSB_RXCSR_DMAMODE; */
/* this special sequence (enabling and then /* this special sequence (enabling and then
...@@ -663,10 +659,11 @@ static void rxstate(struct musb *musb, struct musb_request *req) ...@@ -663,10 +659,11 @@ static void rxstate(struct musb *musb, struct musb_request *req)
if (request->actual < request->length) { if (request->actual < request->length) {
int transfer_size = 0; int transfer_size = 0;
#ifdef USE_MODE1 #ifdef USE_MODE1
transfer_size = min(request->length, transfer_size = min(request->length - request->actual,
channel->max_len); channel->max_len);
#else #else
transfer_size = len; transfer_size = min(request->length - request->actual,
(unsigned)len);
#endif #endif
if (transfer_size <= musb_ep->packet_sz) if (transfer_size <= musb_ep->packet_sz)
musb_ep->dma->desired_mode = 0; musb_ep->dma->desired_mode = 0;
...@@ -740,9 +737,15 @@ void musb_g_rx(struct musb *musb, u8 epnum) ...@@ -740,9 +737,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
u16 csr; u16 csr;
struct usb_request *request; struct usb_request *request;
void __iomem *mbase = musb->mregs; void __iomem *mbase = musb->mregs;
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out; struct musb_ep *musb_ep;
void __iomem *epio = musb->endpoints[epnum].regs; void __iomem *epio = musb->endpoints[epnum].regs;
struct dma_channel *dma; struct dma_channel *dma;
struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
if (hw_ep->is_shared_fifo)
musb_ep = &hw_ep->ep_in;
else
musb_ep = &hw_ep->ep_out;
musb_ep_select(mbase, epnum); musb_ep_select(mbase, epnum);
...@@ -1081,7 +1084,7 @@ struct free_record { ...@@ -1081,7 +1084,7 @@ struct free_record {
/* /*
* Context: controller locked, IRQs blocked. * Context: controller locked, IRQs blocked.
*/ */
static void musb_ep_restart(struct musb *musb, struct musb_request *req) void musb_ep_restart(struct musb *musb, struct musb_request *req)
{ {
DBG(3, "<== %s request %p len %u on hw_ep%d\n", DBG(3, "<== %s request %p len %u on hw_ep%d\n",
req->tx ? "TX/IN" : "RX/OUT", req->tx ? "TX/IN" : "RX/OUT",
......
...@@ -105,4 +105,6 @@ extern void musb_gadget_cleanup(struct musb *); ...@@ -105,4 +105,6 @@ extern void musb_gadget_cleanup(struct musb *);
extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int); extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
extern void musb_ep_restart(struct musb *, struct musb_request *);
#endif /* __MUSB_GADGET_H */ #endif /* __MUSB_GADGET_H */
...@@ -261,6 +261,7 @@ __acquires(musb->lock) ...@@ -261,6 +261,7 @@ __acquires(musb->lock)
ctrlrequest->wIndex & 0x0f; ctrlrequest->wIndex & 0x0f;
struct musb_ep *musb_ep; struct musb_ep *musb_ep;
struct musb_hw_ep *ep; struct musb_hw_ep *ep;
struct musb_request *request;
void __iomem *regs; void __iomem *regs;
int is_in; int is_in;
u16 csr; u16 csr;
...@@ -302,6 +303,14 @@ __acquires(musb->lock) ...@@ -302,6 +303,14 @@ __acquires(musb->lock)
musb_writew(regs, MUSB_RXCSR, csr); musb_writew(regs, MUSB_RXCSR, csr);
} }
/* Maybe start the first request in the queue */
request = to_musb_request(
next_request(musb_ep));
if (!musb_ep->busy && request) {
DBG(3, "restarting the request\n");
musb_ep_restart(musb, request);
}
/* select ep0 again */ /* select ep0 again */
musb_ep_select(mbase, 0); musb_ep_select(mbase, 0);
} break; } break;
......
...@@ -660,6 +660,12 @@ static bool musb_tx_dma_program(struct dma_controller *dma, ...@@ -660,6 +660,12 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
qh->segsize = length; qh->segsize = length;
/*
* Ensure the data reaches to main memory before starting
* DMA transfer
*/
wmb();
if (!dma->channel_program(channel, pkt_size, mode, if (!dma->channel_program(channel, pkt_size, mode,
urb->transfer_dma + offset, length)) { urb->transfer_dma + offset, length)) {
dma->channel_release(channel); dma->channel_release(channel);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment