Commit 6bfe650b authored by Matthew Dharm's avatar Matthew Dharm Committed by Greg Kroah-Hartman

[PATCH] USB storage: General purpose I/O buffer allocation and management

This patch makes our private I/O buffer allocated such that it's pre-mapped
for DMA.  We then add some logic to make sure that we don't try to re-map
it.

We also make the size of the buffer large enough for other sub-drivers,
which will be converted shortly.
parent 0681fb47
......@@ -147,9 +147,20 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
us->current_urb->context = &urb_done;
us->current_urb->actual_length = 0;
us->current_urb->error_count = 0;
us->current_urb->transfer_flags = URB_ASYNC_UNLINK;
us->current_urb->status = 0;
/* we assume that if transfer_buffer isn't us->iobuf then it
* hasn't been mapped for DMA. Yes, this is clunky, but it's
* easier than always having the caller tell us whether the
* transfer buffer has already been mapped. */
us->current_urb->transfer_flags =
(us->current_urb->transfer_buffer == us->iobuf)
? URB_ASYNC_UNLINK | URB_NO_SETUP_DMA_MAP
| URB_NO_TRANSFER_DMA_MAP
: URB_ASYNC_UNLINK | URB_NO_SETUP_DMA_MAP;
us->current_urb->transfer_dma = us->iobuf_dma;
us->current_urb->setup_dma = us->cr_dma;
/* submit the URB */
status = usb_submit_urb(us->current_urb, GFP_NOIO);
if (status) {
......
......@@ -428,7 +428,7 @@ static int usb_stor_control_thread(void * __us)
***********************************************************************/
/* Associate our private data with the USB device */
static void associate_dev(struct us_data *us, struct usb_interface *intf)
static int associate_dev(struct us_data *us, struct usb_interface *intf)
{
US_DEBUGP("-- %s\n", __FUNCTION__);
......@@ -441,6 +441,22 @@ static void associate_dev(struct us_data *us, struct usb_interface *intf)
* device's reference count */
usb_set_intfdata(intf, us);
usb_get_dev(us->pusb_dev);
/* Allocate the device-related DMA-mapped buffers */
us->cr = usb_buffer_alloc(us->pusb_dev, sizeof(*us->cr),
GFP_KERNEL, &us->cr_dma);
if (!us->cr) {
US_DEBUGP("usb_ctrlrequest allocation failed\n");
return -ENOMEM;
}
us->iobuf = usb_buffer_alloc(us->pusb_dev, US_IOBUF_SIZE,
GFP_KERNEL, &us->iobuf_dma);
if (!us->iobuf) {
US_DEBUGP("I/O buffer allocation failed\n");
return -ENOMEM;
}
return 0;
}
/* Get the unusual_devs entries and the string descriptors */
......@@ -742,25 +758,12 @@ static int usb_stor_acquire_resources(struct us_data *us)
{
int p;
/* Allocate the USB control blocks */
us->cr = kmalloc(sizeof(*us->cr), GFP_KERNEL);
if (!us->cr) {
US_DEBUGP("usb_ctrlrequest allocation failed\n");
return -ENOMEM;
}
us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!us->current_urb) {
US_DEBUGP("URB allocation failed\n");
return -ENOMEM;
}
us->iobuf = kmalloc(US_IOBUF_SIZE, GFP_KERNEL);
if (!us->iobuf) {
US_DEBUGP("I/O buffer allocation failed\n");
return -ENOMEM;
}
/* Lock the device while we carry out the next two operations */
down(&us->dev_semaphore);
......@@ -810,8 +813,24 @@ static void dissociate_dev(struct us_data *us)
{
US_DEBUGP("-- %s\n", __FUNCTION__);
down(&us->dev_semaphore);
/* Free the device-related DMA-mapped buffers */
if (us->cr) {
usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr,
us->cr_dma);
us->cr = NULL;
}
if (us->iobuf) {
usb_buffer_free(us->pusb_dev, US_IOBUF_SIZE, us->iobuf,
us->iobuf_dma);
us->iobuf = NULL;
}
/* Remove our private data from the interface and decrement the
* device's reference count */
usb_set_intfdata(us->pusb_intf, NULL);
usb_put_dev(us->pusb_dev);
us->pusb_dev = NULL;
us->pusb_intf = NULL;
up(&us->dev_semaphore);
......@@ -850,18 +869,11 @@ void usb_stor_release_resources(struct us_data *us)
us->extra_destructor(us->extra);
}
/* Destroy the extra data */
if (us->extra) {
/* Free the extra data and the URB */
if (us->extra)
kfree(us->extra);
}
/* Free the USB control blocks */
if (us->iobuf)
kfree(us->iobuf);
if (us->current_urb)
usb_free_urb(us->current_urb);
if (us->cr)
kfree(us->cr);
/* Free the structure itself */
kfree(us);
......@@ -892,7 +904,9 @@ static int storage_probe(struct usb_interface *intf,
init_completion(&(us->notify));
/* Associate the us_data structure with the USB device */
associate_dev(us, intf);
result = associate_dev(us, intf);
if (result)
goto BadDevice;
/*
* Get the unusual_devs entries and the descriptors
......
......@@ -92,7 +92,14 @@ struct us_unusual_dev {
#define USB_STOR_STRING_LEN 32
#define US_IOBUF_SIZE 32 /* Big enough for bulk-only CBW */
/*
* We provide a DMA-mapped I/O buffer for use with small USB transfers.
* It turns out that CB[I] needs a 12-byte buffer and Bulk-only needs a
* 31-byte buffer. But Freecom needs a 64-byte buffer, so that's the
* size we'll allocate.
*/
#define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */
typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
typedef int (*trans_reset)(struct us_data*);
......@@ -147,6 +154,8 @@ struct us_data {
struct usb_ctrlrequest *cr; /* control requests */
struct usb_sg_request current_sg; /* scatter-gather req. */
unsigned char *iobuf; /* I/O buffer */
dma_addr_t cr_dma; /* buffer DMA addresses */
dma_addr_t iobuf_dma;
/* mutual exclusion structures */
struct semaphore sema; /* to sleep thread on */
......
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