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)
return status;
}
/* lower level hcd code should use *_dma exclusively */
if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
/* lower level hcd code should use *_dma exclusively,
* 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))
urb->setup_dma = dma_map_single (
hcd->controller,
......
......@@ -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 list_head dev_list; /* on this hcd */
struct list_head urb_list; /* pending on this dev */
......@@ -343,6 +350,13 @@ extern void usb_deregister_bus (struct usb_bus *);
extern int usb_register_root_hub (struct usb_device *usb_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 */
......
......@@ -206,6 +206,7 @@ static void sg_clean (struct usb_sg_request *io)
kfree (io->urbs);
io->urbs = 0;
}
if (io->dev->dev.dma_mask != 0)
usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
io->dev = 0;
}
......@@ -301,6 +302,7 @@ int usb_sg_init (
{
int i;
int urb_flags;
int dma;
if (!io || !dev || !sg
|| usb_pipecontrol (pipe)
......@@ -314,8 +316,16 @@ int usb_sg_init (
io->sg = sg;
io->nents = nents;
/* initialize all the urbs we'll use */
/* 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 */
if (io->entries <= 0)
return io->entries;
......@@ -347,8 +357,17 @@ int usb_sg_init (
io->urbs [i]->status = -EINPROGRESS;
io->urbs [i]->actual_length = 0;
if (dma) {
/* 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) {
len = min_t (unsigned, len, length);
length -= len;
......@@ -434,9 +453,7 @@ void usb_sg_wait (struct usb_sg_request *io)
retval = 0;
i--;
// FIXME: should it usb_sg_cancel() on INTERRUPT?
// how about imposing a backoff?
set_current_state (TASK_UNINTERRUPTIBLE);
schedule ();
yield ();
break;
/* no error? continue immediately.
......
......@@ -1224,7 +1224,8 @@ void usb_buffer_free (
*
* 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
* 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
* as the target of a large periodic transfer, with usb_buffer_dmasync()
......@@ -1245,12 +1246,15 @@ struct urb *usb_buffer_map (struct urb *urb)
|| !(controller = bus->controller))
return 0;
if (controller->dma_mask) {
urb->transfer_dma = dma_map_single (controller,
urb->transfer_buffer, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
} else
urb->transfer_dma = ~0;
urb->transfer_flags |= URB_NO_DMA_MAP;
return urb;
}
......@@ -1271,6 +1275,7 @@ void usb_buffer_dmasync (struct urb *urb)
|| !(controller = bus->controller))
return;
if (controller->dma_mask)
dma_sync_single (controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
......@@ -1295,10 +1300,12 @@ void usb_buffer_unmap (struct urb *urb)
|| !(controller = bus->controller))
return;
if (controller->dma_mask)
dma_unmap_single (controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? 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,
if (!dev
|| usb_pipecontrol (pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller))
|| !(controller = bus->controller)
|| !controller->dma_mask)
return -1;
// 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,
if (!dev
|| !(bus = dev->bus)
|| !(controller = bus->controller))
|| !(controller = bus->controller)
|| !controller->dma_mask)
return;
dma_sync_sg (controller, sg, n_hw_ents,
......@@ -1386,7 +1395,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
if (!dev
|| !(bus = dev->bus)
|| !(controller = bus->controller))
|| !(controller = bus->controller)
|| !controller->dma_mask)
return;
dma_unmap_sg (controller, sg, n_hw_ents,
......
......@@ -426,16 +426,6 @@ static inline int hcd_register_root (struct usb_hcd *hcd)
#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)
#ifndef DEBUG
......
......@@ -219,7 +219,7 @@ static int hci_unlink_urb (struct urb * urb)
if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
/* URB active? */
if (urb->transfer_flags & (URB_ASYNC_UNLINK | URB_TIMEOUT_KILLED)) {
if (urb->transfer_flags & URB_ASYNC_UNLINK) {
/* asynchronous with callback */
/* relink the urb to the del list */
list_move (&urb->urb_list, &hci->del_list);
......@@ -388,7 +388,6 @@ static void qu_urb_timeout (unsigned long lurb)
struct urb *urb = (struct urb *) lurb;
DBGFUNC ("enter qu_urb_timeout\n");
urb->transfer_flags |= URB_TIMEOUT_KILLED;
hci_unlink_urb (urb);
}
#endif
......
......@@ -1747,7 +1747,6 @@ static void stall_callback(unsigned long ptr)
tmp = tmp->next;
u->transfer_flags |= URB_TIMEOUT_KILLED;
uhci_urb_dequeue(hcd, u);
}
......
......@@ -554,7 +554,6 @@ extern int usb_disabled(void);
#define URB_NO_FSBR 0x0020 /* UHCI-specific */
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */
#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 {
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