ChangeSet 1.831.15.14, 2002/12/09 10:59:40-08:00, [EMAIL PROTECTED]
[PATCH] usb-storage: make CBI interrupt URBs one-shot
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 Mon Dec 9 11:41:02 2002
+++ b/drivers/usb/storage/transport.c Mon Dec 9 11:41:02 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 Mon Dec 9 11:41:02 2002
+++ b/drivers/usb/storage/transport.h Mon Dec 9 11:41:02 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 Mon Dec 9 11:41:02 2002
+++ b/drivers/usb/storage/usb.c Mon Dec 9 11:41:02 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 Mon Dec 9 11:41:02 2002
+++ b/drivers/usb/storage/usb.h Mon Dec 9 11:41:02 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 */
-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel