This patch makes interrupt URBs one-shot for CBI transfers.  This is good
for code reduction, simplification, and aborting.

 transport.c |  163 +++++++++++++++++++++---------------------------------------
 transport.h |    5 +
 usb.c       |   63 +----------------------
 usb.h       |    8 --
 4 files changed, 67 insertions, 172 deletions

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.656   -> 1.657  
#       drivers/usb/storage/usb.h       1.28    -> 1.29   
#       drivers/usb/storage/transport.h 1.19    -> 1.20   
#       drivers/usb/storage/transport.c 1.69    -> 1.70   
#       drivers/usb/storage/usb.c       1.58    -> 1.59   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/12/08      [EMAIL PROTECTED]       1.657
# Change interrupt used for CBI from periodic to one-shot.  This (a) reduces
# consumed bandwidth, (b) makes the logic clearer, and (c) makes the abort
# mechanism more uniform.
# --------------------------------------------
#
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c   Sun Dec  8 16:38:50 2002
+++ b/drivers/usb/storage/transport.c   Sun Dec  8 16:38:50 2002
@@ -503,6 +503,35 @@
        return status;
 }
 
+/* This is our function to submit interrupt URBs with enough control
+ * to make aborts/resets/timeouts work
+ *
+ * This routine always uses us->recv_intr_pipe as the pipe and
+ * us->ep_int->bInterval as the interrupt interval.
+ */
+int usb_stor_interrupt_msg(struct us_data *us, void *data,
+                       unsigned int len, unsigned int *act_len)
+{
+       unsigned int pipe = us->recv_intr_pipe;
+       unsigned int maxp;
+       int status;
+
+       /* calculate the max packet size */
+       maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe));
+       if (maxp > len)
+               maxp = len;
+
+       /* fill and submit the URB */
+       usb_fill_int_urb(us->current_urb, us->pusb_dev, pipe, data,
+                       maxp, usb_stor_blocking_completion, NULL,
+                       us->ep_int->bInterval);
+       status = usb_stor_msg_common(us);
+
+       /* store the actual length of the data transferred */
+       *act_len = us->current_urb->actual_length;
+       return status;
+}
+
 /* This is a version of usb_clear_halt() that doesn't read the status from
  * the device -- this is because some devices crash their internal firmware
  * when the status is requested after a halt.
@@ -627,6 +656,29 @@
 }
 
 /*
+ * Receive one buffer via interrupt transfer
+ *
+ * This function does basically the same thing as usb_stor_interrupt_msg()
+ * above, except that return codes are USB_STOR_XFER_xxx rather than the
+ * urb status.
+ */
+int usb_stor_intr_transfer(struct us_data *us, void *buf,
+               unsigned int length, unsigned int *act_len)
+{
+       int result;
+       unsigned int partial;
+
+       /* transfer the data */
+       US_DEBUGP("usb_stor_intr_transfer(): xfer %u bytes\n", length);
+       result = usb_stor_interrupt_msg(us, buf, length, &partial);
+       if (act_len)
+               *act_len = partial;
+
+       return interpret_urb_result(us, us->recv_intr_pipe,
+                       length, result, partial);
+}
+
+/*
  * Transfer one buffer via bulk transfer
  *
  * This function does basically the same thing as usb_stor_bulk_msg()
@@ -947,7 +999,7 @@
        host = us->srb->host;
        scsi_unlock(host);
 
-       /* If the state machine is blocked waiting for an URB or an IRQ,
+       /* If the state machine is blocked waiting for an URB,
         * let's wake it up */
 
        /* If we have an URB pending, cancel it.  The test_and_clear_bit()
@@ -964,12 +1016,6 @@
                usb_sg_cancel(us->current_sg);
        }
 
-       /* If we are waiting for an IRQ, simulate it */
-       if (test_bit(US_FLIDX_IP_WANTED, &us->flags)) {
-               US_DEBUGP("-- simulating missing IRQ\n");
-               usb_stor_CBI_irq(us->irq_urb, NULL);
-       }
-
        /* Wait for the aborted command to finish */
        wait_for_completion(&us->notify);
 
@@ -981,94 +1027,11 @@
  * Control/Bulk/Interrupt transport
  */
 
-/* The interrupt handler for CBI devices */
-void usb_stor_CBI_irq(struct urb *urb, struct pt_regs *regs)
-{
-       struct us_data *us = (struct us_data *)urb->context;
-       int status;
-
-       US_DEBUGP("USB IRQ received for device on host %d\n", us->host_no);
-       US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
-       US_DEBUGP("-- IRQ state is %d\n", urb->status);
-       US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
-                       us->irqbuf[0], us->irqbuf[1]);
-
-       /* has the current command been aborted? */
-       if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-
-               /* was this a wanted interrupt? */
-               if (!test_and_clear_bit(US_FLIDX_IP_WANTED, &us->flags)) {
-                       US_DEBUGP("ERROR: Unwanted interrupt received!\n");
-                       goto exit;
-               }
-               US_DEBUGP("-- command aborted\n");
-
-               /* wake up the command thread */
-               up(&us->ip_waitq);
-               goto exit;
-       }
-
-       /* is the device removed? */
-       if (urb->status == -ENOENT) {
-               US_DEBUGP("-- device has been removed\n");
-
-               /* was this a wanted interrupt? */
-               if (!test_and_clear_bit(US_FLIDX_IP_WANTED, &us->flags))
-                       return;
-
-               /* indicate a transport error -- this is the best we can do */
-               us->irqdata[0] = us->irqdata[1] = 0xFF;
-
-               /* wake up the command thread */
-               up(&us->ip_waitq);
-               return;
-       }
-
-       /* reject improper IRQs */
-       if (urb->actual_length != 2) {
-               US_DEBUGP("-- IRQ too short\n");
-               goto exit;
-       }
-
-       /* was this a command-completion interrupt? */
-       if (us->irqbuf[0] && (us->subclass != US_SC_UFI)) {
-               US_DEBUGP("-- not a command-completion IRQ\n");
-               goto exit;
-       }
-
-       /* was this a wanted interrupt? */
-       if (!test_and_clear_bit(US_FLIDX_IP_WANTED, &us->flags)) {
-               US_DEBUGP("ERROR: Unwanted interrupt received!\n");
-               goto exit;
-       }
-               
-       /* copy the valid data */
-       us->irqdata[0] = us->irqbuf[0];
-       us->irqdata[1] = us->irqbuf[1];
-
-       /* wake up the command thread */
-       up(&(us->ip_waitq));
-
-exit:
-       /* resubmit the urb */
-       status = usb_submit_urb (urb, GFP_ATOMIC);
-       if (status)
-               err ("%s - usb_submit_urb failed with result %d",
-                    __FUNCTION__, status);
-}
-
 int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
        unsigned int transfer_length = usb_stor_transfer_length(srb);
        int result;
 
-       /* re-initialize the mutex so that we avoid any races with
-        * early/late IRQs from previous commands */
-       init_MUTEX_LOCKED(&(us->ip_waitq));
-
-       /* Set up for status notification */
-       set_bit(US_FLIDX_IP_WANTED, &us->flags);
-
        /* COMMAND STAGE */
        /* let's send the command via the control pipe */
        result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
@@ -1079,8 +1042,6 @@
        /* check the return code for the command */
        US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
        if (result != USB_STOR_XFER_GOOD) {
-               /* Reset flag for status notification */
-               clear_bit(US_FLIDX_IP_WANTED, &us->flags);
                /* Uh oh... serious problem here */
                return USB_STOR_TRANSPORT_ERROR;
        }
@@ -1093,25 +1054,17 @@
                result = usb_stor_bulk_transfer_srb(us, pipe, srb,
                                        transfer_length);
                US_DEBUGP("CBI data stage result is 0x%x\n", result);
-               if (result == USB_STOR_XFER_ERROR) {
-                       clear_bit(US_FLIDX_IP_WANTED, &us->flags);
+               if (result == USB_STOR_XFER_ERROR)
                        return USB_STOR_TRANSPORT_ERROR;
-               }
        }
 
        /* STATUS STAGE */
-
-       /* go to sleep until we get this interrupt */
-       down(&(us->ip_waitq));
-
-       /* has the current command been aborted? */
-       if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-               US_DEBUGP("CBI interrupt aborted\n");
-               return USB_STOR_TRANSPORT_ERROR;
-       }
-
+       result = usb_stor_intr_transfer(us, us->irqdata,
+                                       sizeof(us->irqdata), NULL);
        US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", 
                        us->irqdata[0], us->irqdata[1]);
+       if (result != USB_STOR_XFER_GOOD)
+               return USB_STOR_TRANSPORT_ERROR;
 
        /* UFI gives us ASC and ASCQ, like a request sense
         *
diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
--- a/drivers/usb/storage/transport.h   Sun Dec  8 16:38:50 2002
+++ b/drivers/usb/storage/transport.h   Sun Dec  8 16:38:50 2002
@@ -145,7 +145,6 @@
 
 #define US_CBI_ADSC            0
 
-extern void usb_stor_CBI_irq(struct urb*, struct pt_regs *);
 extern int usb_stor_CBI_transport(Scsi_Cmnd*, struct us_data*);
 
 extern int usb_stor_CB_transport(Scsi_Cmnd*, struct us_data*);
@@ -164,11 +163,15 @@
 extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
                u8 request, u8 requesttype, u16 value, u16 index,
                void *data, u16 size);
+extern int usb_stor_interrupt_msg(struct us_data *us, void *data,
+               unsigned int len, unsigned int *act_len);
 
 extern int usb_stor_clear_halt(struct us_data*, unsigned int pipe);
 extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
                u8 request, u8 requesttype, u16 value, u16 index,
                void *data, u16 size);
+extern int usb_stor_intr_transfer(struct us_data *us, void *buf,
+               unsigned int length, unsigned int *act_len);
 extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
                void *buf, unsigned int length, unsigned int *act_len);
 extern int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c Sun Dec  8 16:38:50 2002
+++ b/drivers/usb/storage/usb.c Sun Dec  8 16:38:50 2002
@@ -477,24 +477,21 @@
        return 0;
 }      
 
-/* Set up the URB, the usb_ctrlrequest, and the IRQ pipe and handler.
+/* Set up the URB and the usb_ctrlrequest.
  * ss->dev_semaphore must already be locked.
  * Note that this function assumes that all the data in the us_data
- * strucuture is current.  This includes the ep_int field, which gives us
- * the endpoint for the interrupt.
+ * structure is current.
  * Returns non-zero on failure, zero on success
  */ 
 static int usb_stor_allocate_urbs(struct us_data *ss)
 {
-       unsigned int pipe;
-       int maxp;
-       int result;
-
        /* calculate and store the pipe values */
        ss->send_bulk_pipe = usb_sndbulkpipe(ss->pusb_dev, ss->ep_out);
        ss->recv_bulk_pipe = usb_rcvbulkpipe(ss->pusb_dev, ss->ep_in);
        ss->send_ctrl_pipe = usb_sndctrlpipe(ss->pusb_dev, 0);
        ss->recv_ctrl_pipe = usb_rcvctrlpipe(ss->pusb_dev, 0);
+       ss->recv_intr_pipe = usb_rcvintpipe(ss->pusb_dev,
+                   ss->ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
 
        /* allocate the usb_ctrlrequest for control packets */
        US_DEBUGP("Allocating usb_ctrlrequest\n");
@@ -519,45 +516,6 @@
                return 5;
        }
 
-       /* allocate the IRQ URB, if it is needed */
-       if (ss->protocol == US_PR_CBI) {
-               US_DEBUGP("Allocating IRQ for CBI transport\n");
-
-               /* lock access to the data structure */
-               down(&(ss->irq_urb_sem));
-
-               /* allocate the URB */
-               ss->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!ss->irq_urb) {
-                       up(&(ss->irq_urb_sem));
-                       US_DEBUGP("couldn't allocate interrupt URB");
-                       return 3;
-               }
-
-               /* calculate the pipe and max packet size */
-               pipe = usb_rcvintpipe(ss->pusb_dev,
-                   ss->ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-               maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
-               if (maxp > sizeof(ss->irqbuf))
-                       maxp = sizeof(ss->irqbuf);
-
-               /* fill in the URB with our data */
-               usb_fill_int_urb(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf,
-                       maxp, usb_stor_CBI_irq, ss, ss->ep_int->bInterval); 
-
-               /* submit the URB for processing */
-               result = usb_submit_urb(ss->irq_urb, GFP_KERNEL);
-               US_DEBUGP("usb_submit_urb() returns %d\n", result);
-               if (result) {
-                       up(&(ss->irq_urb_sem));
-                       return 4;
-               }
-
-               /* unlock the data structure */
-               up(&(ss->irq_urb_sem));
-
-       } /* ss->protocol == US_PR_CBI */
-
        return 0;       /* success */
 }
 
@@ -568,17 +526,6 @@
 {
        int result;
 
-       /* release the IRQ, if we have one */
-       down(&(ss->irq_urb_sem));
-       if (ss->irq_urb) {
-               US_DEBUGP("-- releasing irq URB\n");
-               result = usb_unlink_urb(ss->irq_urb);
-               US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
-               usb_free_urb(ss->irq_urb);
-               ss->irq_urb = NULL;
-       }
-       up(&(ss->irq_urb_sem));
-
        /* free the scatter-gather request block */
        if (ss->current_sg) {
                kfree(ss->current_sg);
@@ -810,8 +757,6 @@
 
                /* Initialize the mutexes only when the struct is new */
                init_completion(&(ss->notify));
-               init_MUTEX_LOCKED(&(ss->ip_waitq));
-               init_MUTEX(&(ss->irq_urb_sem));
                init_MUTEX_LOCKED(&(ss->dev_semaphore));
 
                /* copy over the subclass and protocol data */
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h Sun Dec  8 16:38:50 2002
+++ b/drivers/usb/storage/usb.h Sun Dec  8 16:38:50 2002
@@ -105,7 +105,6 @@
 #define US_FL_FIX_CAPACITY    0x00000080 /* READ CAPACITY response too big  */
 
 #define US_FL_DEV_ATTACHED    0x00010000 /* is the device attached?        */
-#define US_FLIDX_IP_WANTED   17  /* 0x00020000 is an IRQ expected?         */
 #define US_FLIDX_CAN_CANCEL  18  /* 0x00040000  okay to cancel current_urb? */
 #define US_FLIDX_CANCEL_SG   19  /* 0x00080000 okay to cancel current_sg?  */
 
@@ -139,6 +138,7 @@
        unsigned int            recv_bulk_pipe;
        unsigned int            send_ctrl_pipe;
        unsigned int            recv_ctrl_pipe;
+       unsigned int            recv_intr_pipe;
 
        /* information about the device -- always good */
        char                    vendor[USB_STOR_STRING_LEN];
@@ -173,13 +173,7 @@
        int                     pid;             /* control thread       */
        atomic_t                sm_state;        /* what we are doing    */
 
-       /* interrupt info for CBI devices -- only good if attached */
-       struct semaphore        ip_waitq;        /* for CBI interrupts   */
-
        /* interrupt communications data */
-       struct semaphore        irq_urb_sem;     /* to protect irq_urb   */
-       struct urb              *irq_urb;        /* for USB int requests */
-       unsigned char           irqbuf[2];       /* buffer for USB IRQ   */
        unsigned char           irqdata[2];      /* data from USB IRQ    */
 
        /* control and bulk communications data */

-- 
Matthew Dharm                              Home: [EMAIL PROTECTED] 
Maintainer, Linux USB Mass Storage Driver

What, are you one of those Microsoft-bashing Linux freaks?
                                        -- Customer to Greg
User Friendly, 2/10/1999

Attachment: msg09860/pgp00000.pgp
Description: PGP signature

Reply via email to