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.
Greg, please apply.
Matt
# This is a BitKeeper generated patch for the following project:
# Project Name: greg k-h's linux 2.5 USB kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.721 -> 1.722
# drivers/usb/storage/usb.h 1.40 -> 1.41
# drivers/usb/storage/transport.c 1.89 -> 1.90
# drivers/usb/storage/usb.c 1.80 -> 1.81
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/06/28 [EMAIL PROTECTED] 1.722
# Allocate and map the general-purpose I/O buffer for DMA.
# --------------------------------------------
#
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c Sat Jun 28 20:31:31 2003
+++ b/drivers/usb/storage/transport.c Sat Jun 28 20:31:31 2003
@@ -147,8 +147,19 @@
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);
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c Sat Jun 28 20:31:31 2003
+++ b/drivers/usb/storage/usb.c Sat Jun 28 20:31:31 2003
@@ -428,7 +428,7 @@
***********************************************************************/
/* 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 @@
* 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 @@
{
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 @@
{
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 @@
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 @@
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
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h Sat Jun 28 20:31:31 2003
+++ b/drivers/usb/storage/usb.h Sat Jun 28 20:31:31 2003
@@ -92,7 +92,14 @@
#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 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 */
--
Matthew Dharm Home: [EMAIL PROTECTED]
Maintainer, Linux USB Mass Storage Driver
Somebody call an exorcist!
-- Dust Puppy
User Friendly, 5/16/1998
pgp00000.pgp
Description: PGP signature
