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) ...@@ -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->context = &urb_done;
us->current_urb->actual_length = 0; us->current_urb->actual_length = 0;
us->current_urb->error_count = 0; us->current_urb->error_count = 0;
us->current_urb->transfer_flags = URB_ASYNC_UNLINK;
us->current_urb->status = 0; 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 */ /* submit the URB */
status = usb_submit_urb(us->current_urb, GFP_NOIO); status = usb_submit_urb(us->current_urb, GFP_NOIO);
if (status) { if (status) {
......
...@@ -428,7 +428,7 @@ static int usb_stor_control_thread(void * __us) ...@@ -428,7 +428,7 @@ static int usb_stor_control_thread(void * __us)
***********************************************************************/ ***********************************************************************/
/* Associate our private data with the USB device */ /* 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__); US_DEBUGP("-- %s\n", __FUNCTION__);
...@@ -441,6 +441,22 @@ static void associate_dev(struct us_data *us, struct usb_interface *intf) ...@@ -441,6 +441,22 @@ static void associate_dev(struct us_data *us, struct usb_interface *intf)
* device's reference count */ * device's reference count */
usb_set_intfdata(intf, us); usb_set_intfdata(intf, us);
usb_get_dev(us->pusb_dev); 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 */ /* Get the unusual_devs entries and the string descriptors */
...@@ -742,25 +758,12 @@ static int usb_stor_acquire_resources(struct us_data *us) ...@@ -742,25 +758,12 @@ static int usb_stor_acquire_resources(struct us_data *us)
{ {
int p; 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); us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!us->current_urb) { if (!us->current_urb) {
US_DEBUGP("URB allocation failed\n"); US_DEBUGP("URB allocation failed\n");
return -ENOMEM; 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 */ /* Lock the device while we carry out the next two operations */
down(&us->dev_semaphore); down(&us->dev_semaphore);
...@@ -810,8 +813,24 @@ static void dissociate_dev(struct us_data *us) ...@@ -810,8 +813,24 @@ static void dissociate_dev(struct us_data *us)
{ {
US_DEBUGP("-- %s\n", __FUNCTION__); US_DEBUGP("-- %s\n", __FUNCTION__);
down(&us->dev_semaphore); 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_set_intfdata(us->pusb_intf, NULL);
usb_put_dev(us->pusb_dev); usb_put_dev(us->pusb_dev);
us->pusb_dev = NULL; us->pusb_dev = NULL;
us->pusb_intf = NULL; us->pusb_intf = NULL;
up(&us->dev_semaphore); up(&us->dev_semaphore);
...@@ -850,18 +869,11 @@ void usb_stor_release_resources(struct us_data *us) ...@@ -850,18 +869,11 @@ void usb_stor_release_resources(struct us_data *us)
us->extra_destructor(us->extra); us->extra_destructor(us->extra);
} }
/* Destroy the extra data */ /* Free the extra data and the URB */
if (us->extra) { if (us->extra)
kfree(us->extra); kfree(us->extra);
}
/* Free the USB control blocks */
if (us->iobuf)
kfree(us->iobuf);
if (us->current_urb) if (us->current_urb)
usb_free_urb(us->current_urb); usb_free_urb(us->current_urb);
if (us->cr)
kfree(us->cr);
/* Free the structure itself */ /* Free the structure itself */
kfree(us); kfree(us);
...@@ -892,7 +904,9 @@ static int storage_probe(struct usb_interface *intf, ...@@ -892,7 +904,9 @@ static int storage_probe(struct usb_interface *intf,
init_completion(&(us->notify)); init_completion(&(us->notify));
/* Associate the us_data structure with the USB device */ /* 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 * Get the unusual_devs entries and the descriptors
......
...@@ -92,7 +92,14 @@ struct us_unusual_dev { ...@@ -92,7 +92,14 @@ struct us_unusual_dev {
#define USB_STOR_STRING_LEN 32 #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_cmnd)(Scsi_Cmnd*, struct us_data*);
typedef int (*trans_reset)(struct us_data*); typedef int (*trans_reset)(struct us_data*);
...@@ -147,6 +154,8 @@ struct us_data { ...@@ -147,6 +154,8 @@ struct us_data {
struct usb_ctrlrequest *cr; /* control requests */ struct usb_ctrlrequest *cr; /* control requests */
struct usb_sg_request current_sg; /* scatter-gather req. */ struct usb_sg_request current_sg; /* scatter-gather req. */
unsigned char *iobuf; /* I/O buffer */ unsigned char *iobuf; /* I/O buffer */
dma_addr_t cr_dma; /* buffer DMA addresses */
dma_addr_t iobuf_dma;
/* mutual exclusion structures */ /* mutual exclusion structures */
struct semaphore sema; /* to sleep thread on */ 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