Commit 31fd2ea0 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: usbcore misc cleanup (notably for non-dma hcds)

The support for non-dma HCDs is likely the most interesting bit here.

    - makes dma calls behave sensibly when used with host controllers
      that don't use dma (including sl811).  usb_buffer_map() is a nop
      while scatterlist dma mappings fail (as they must).

    - make usb_sg_init() behave sensibly when used with non-dma hcs.
      the urbs are initted with transfer_buffer, not transfer_dma.
      this is the higher level analogue to usb_buffer_map(), so it
      needs to succeed unless there's a Real Error (tm).

    - moves two compatibility inlines from ehci.h into hcd.h so
      it'll be more practical to have the other hcds work in other
      environments (notably lk 2.4) too

    - remove URB_TIMEOUT_KILLED flag ... no device driver tests it;
      hcds don't really (uhci sets it, never reads it; sl811 doesn't
      enable the path that might set it), and it's not well defined.
      if any hcd needs such state, keep it in hc-private storage.

    - in usb_sg_wait(), use yield() instead of schedule() to let
      other activities free resources needed to continue.  (This
      was noted recently by Oliver.)
parent fb4b62ad
...@@ -1029,8 +1029,11 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) ...@@ -1029,8 +1029,11 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
return status; return status;
} }
/* lower level hcd code should use *_dma exclusively */ /* lower level hcd code should use *_dma exclusively,
if (!(urb->transfer_flags & URB_NO_DMA_MAP)) { * unless it uses pio or talks to another transport.
*/
if (!(urb->transfer_flags & URB_NO_DMA_MAP)
&& hcd->controller->dma_mask) {
if (usb_pipecontrol (urb->pipe)) if (usb_pipecontrol (urb->pipe))
urb->setup_dma = dma_map_single ( urb->setup_dma = dma_map_single (
hcd->controller, hcd->controller,
......
...@@ -111,6 +111,13 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ ...@@ -111,6 +111,13 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
*/ */
}; };
/* 2.4 does this a bit differently ... */
static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
{
return &hcd->self;
}
struct hcd_dev { /* usb_device.hcpriv points to this */ struct hcd_dev { /* usb_device.hcpriv points to this */
struct list_head dev_list; /* on this hcd */ struct list_head dev_list; /* on this hcd */
struct list_head urb_list; /* pending on this dev */ struct list_head urb_list; /* pending on this dev */
...@@ -343,6 +350,13 @@ extern void usb_deregister_bus (struct usb_bus *); ...@@ -343,6 +350,13 @@ extern void usb_deregister_bus (struct usb_bus *);
extern int usb_register_root_hub (struct usb_device *usb_dev, extern int usb_register_root_hub (struct usb_device *usb_dev,
struct device *parent_dev); struct device *parent_dev);
/* for portability to 2.4, hcds should call this */
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, hcd->controller);
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* exported only within usbcore */ /* exported only within usbcore */
......
...@@ -206,7 +206,8 @@ static void sg_clean (struct usb_sg_request *io) ...@@ -206,7 +206,8 @@ static void sg_clean (struct usb_sg_request *io)
kfree (io->urbs); kfree (io->urbs);
io->urbs = 0; io->urbs = 0;
} }
usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); if (io->dev->dev.dma_mask != 0)
usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
io->dev = 0; io->dev = 0;
} }
...@@ -301,6 +302,7 @@ int usb_sg_init ( ...@@ -301,6 +302,7 @@ int usb_sg_init (
{ {
int i; int i;
int urb_flags; int urb_flags;
int dma;
if (!io || !dev || !sg if (!io || !dev || !sg
|| usb_pipecontrol (pipe) || usb_pipecontrol (pipe)
...@@ -314,8 +316,16 @@ int usb_sg_init ( ...@@ -314,8 +316,16 @@ int usb_sg_init (
io->sg = sg; io->sg = sg;
io->nents = nents; io->nents = nents;
/* not all host controllers use DMA (like the mainstream pci ones);
* they can use PIO (sl811) or be software over another transport.
*/
dma = (dev->dev.dma_mask == 0);
if (dma)
io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
else
io->entries = nents;
/* initialize all the urbs we'll use */ /* initialize all the urbs we'll use */
io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
if (io->entries <= 0) if (io->entries <= 0)
return io->entries; return io->entries;
...@@ -347,8 +357,17 @@ int usb_sg_init ( ...@@ -347,8 +357,17 @@ int usb_sg_init (
io->urbs [i]->status = -EINPROGRESS; io->urbs [i]->status = -EINPROGRESS;
io->urbs [i]->actual_length = 0; io->urbs [i]->actual_length = 0;
io->urbs [i]->transfer_dma = sg_dma_address (sg + i); if (dma) {
len = sg_dma_len (sg + i); /* hc may use _only_ transfer_dma */
io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
len = sg_dma_len (sg + i);
} else {
/* hc may use _only_ transfer_buffer */
io->urbs [i]->transfer_buffer =
page_address (sg [i].page) + sg [i].offset;
len = sg [i].length;
}
if (length) { if (length) {
len = min_t (unsigned, len, length); len = min_t (unsigned, len, length);
length -= len; length -= len;
...@@ -434,9 +453,7 @@ void usb_sg_wait (struct usb_sg_request *io) ...@@ -434,9 +453,7 @@ void usb_sg_wait (struct usb_sg_request *io)
retval = 0; retval = 0;
i--; i--;
// FIXME: should it usb_sg_cancel() on INTERRUPT? // FIXME: should it usb_sg_cancel() on INTERRUPT?
// how about imposing a backoff? yield ();
set_current_state (TASK_UNINTERRUPTIBLE);
schedule ();
break; break;
/* no error? continue immediately. /* no error? continue immediately.
......
...@@ -1224,7 +1224,8 @@ void usb_buffer_free ( ...@@ -1224,7 +1224,8 @@ void usb_buffer_free (
* *
* Return value is either null (indicating no buffer could be mapped), or * Return value is either null (indicating no buffer could be mapped), or
* the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the * the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the
* operation succeeds. * operation succeeds. If the device is connected to this system through
* a non-DMA controller, this operation always succeeds.
* *
* This call would normally be used for an urb which is reused, perhaps * This call would normally be used for an urb which is reused, perhaps
* as the target of a large periodic transfer, with usb_buffer_dmasync() * as the target of a large periodic transfer, with usb_buffer_dmasync()
...@@ -1245,12 +1246,15 @@ struct urb *usb_buffer_map (struct urb *urb) ...@@ -1245,12 +1246,15 @@ struct urb *usb_buffer_map (struct urb *urb)
|| !(controller = bus->controller)) || !(controller = bus->controller))
return 0; return 0;
urb->transfer_dma = dma_map_single (controller, if (controller->dma_mask) {
urb->transfer_dma = dma_map_single (controller,
urb->transfer_buffer, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE); ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors // FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
} else
urb->transfer_dma = ~0;
urb->transfer_flags |= URB_NO_DMA_MAP; urb->transfer_flags |= URB_NO_DMA_MAP;
return urb; return urb;
} }
...@@ -1271,7 +1275,8 @@ void usb_buffer_dmasync (struct urb *urb) ...@@ -1271,7 +1275,8 @@ void usb_buffer_dmasync (struct urb *urb)
|| !(controller = bus->controller)) || !(controller = bus->controller))
return; return;
dma_sync_single (controller, if (controller->dma_mask)
dma_sync_single (controller,
urb->transfer_dma, urb->transfer_buffer_length, urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE); ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
...@@ -1295,10 +1300,12 @@ void usb_buffer_unmap (struct urb *urb) ...@@ -1295,10 +1300,12 @@ void usb_buffer_unmap (struct urb *urb)
|| !(controller = bus->controller)) || !(controller = bus->controller))
return; return;
dma_unmap_single (controller, if (controller->dma_mask)
dma_unmap_single (controller,
urb->transfer_dma, urb->transfer_buffer_length, urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE); ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
urb->transfer_flags &= ~URB_NO_DMA_MAP;
} }
/** /**
...@@ -1336,7 +1343,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, ...@@ -1336,7 +1343,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
if (!dev if (!dev
|| usb_pipecontrol (pipe) || usb_pipecontrol (pipe)
|| !(bus = dev->bus) || !(bus = dev->bus)
|| !(controller = bus->controller)) || !(controller = bus->controller)
|| !controller->dma_mask)
return -1; return -1;
// FIXME generic api broken like pci, can't report errors // FIXME generic api broken like pci, can't report errors
...@@ -1362,7 +1370,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, ...@@ -1362,7 +1370,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
if (!dev if (!dev
|| !(bus = dev->bus) || !(bus = dev->bus)
|| !(controller = bus->controller)) || !(controller = bus->controller)
|| !controller->dma_mask)
return; return;
dma_sync_sg (controller, sg, n_hw_ents, dma_sync_sg (controller, sg, n_hw_ents,
...@@ -1386,7 +1395,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, ...@@ -1386,7 +1395,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
if (!dev if (!dev
|| !(bus = dev->bus) || !(bus = dev->bus)
|| !(controller = bus->controller)) || !(controller = bus->controller)
|| !controller->dma_mask)
return; return;
dma_unmap_sg (controller, sg, n_hw_ents, dma_unmap_sg (controller, sg, n_hw_ents,
......
...@@ -426,16 +426,6 @@ static inline int hcd_register_root (struct usb_hcd *hcd) ...@@ -426,16 +426,6 @@ static inline int hcd_register_root (struct usb_hcd *hcd)
#else /* LINUX_VERSION_CODE */ #else /* LINUX_VERSION_CODE */
// hcd_to_bus() eventually moves to hcd.h on 2.5 too
static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
{ return &hcd->self; }
// ... as does hcd_register_root()
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, &hcd->pdev->dev);
}
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags) #define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
#ifndef DEBUG #ifndef DEBUG
......
...@@ -219,7 +219,7 @@ static int hci_unlink_urb (struct urb * urb) ...@@ -219,7 +219,7 @@ static int hci_unlink_urb (struct urb * urb)
if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) { if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
/* URB active? */ /* URB active? */
if (urb->transfer_flags & (URB_ASYNC_UNLINK | URB_TIMEOUT_KILLED)) { if (urb->transfer_flags & URB_ASYNC_UNLINK) {
/* asynchronous with callback */ /* asynchronous with callback */
/* relink the urb to the del list */ /* relink the urb to the del list */
list_move (&urb->urb_list, &hci->del_list); list_move (&urb->urb_list, &hci->del_list);
...@@ -388,7 +388,6 @@ static void qu_urb_timeout (unsigned long lurb) ...@@ -388,7 +388,6 @@ static void qu_urb_timeout (unsigned long lurb)
struct urb *urb = (struct urb *) lurb; struct urb *urb = (struct urb *) lurb;
DBGFUNC ("enter qu_urb_timeout\n"); DBGFUNC ("enter qu_urb_timeout\n");
urb->transfer_flags |= URB_TIMEOUT_KILLED;
hci_unlink_urb (urb); hci_unlink_urb (urb);
} }
#endif #endif
......
...@@ -1747,7 +1747,6 @@ static void stall_callback(unsigned long ptr) ...@@ -1747,7 +1747,6 @@ static void stall_callback(unsigned long ptr)
tmp = tmp->next; tmp = tmp->next;
u->transfer_flags |= URB_TIMEOUT_KILLED;
uhci_urb_dequeue(hcd, u); uhci_urb_dequeue(hcd, u);
} }
......
...@@ -554,7 +554,6 @@ extern int usb_disabled(void); ...@@ -554,7 +554,6 @@ extern int usb_disabled(void);
#define URB_NO_FSBR 0x0020 /* UHCI-specific */ #define URB_NO_FSBR 0x0020 /* UHCI-specific */
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */ #define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */
#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */ #define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */
#define URB_TIMEOUT_KILLED 0x1000 /* only set by HCD! */
struct usb_iso_packet_descriptor { struct usb_iso_packet_descriptor {
unsigned int offset; unsigned int offset;
......
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