Hi,

I'd like to get some feedback on this patch before
sending it to Linus.

It adds infrastructure to usb.c [usb_check_bandwidth(),
usb_claim_bandwidth(), and usb_release_bandwidth()]
and modifies uhci.c to use these functions [I used
uhci.c simply because I know it better].

I have a few questions about when/where I need to
add spinlocks and I'm not real fond of using
urb->bandwidth to store the URB's bandwidth usage
since a driver could maliciously change it, but
this isn't the only example of where a driver could
do something like that to lie to the system.

With this patch, usb.c (usbcore.o) has a "bandwidth" parameter
that is used to enable/disable enforcement of bandwidth
allocation.  For now it defaults to "disable" (0).
To enable it, use:  insmod usbcore.o bandwidth=1

Even with bandwidth allocation disabled, it still goes
thru all of the steps and then prints/logs a message
if the allocation would have failed.

Comments?

~Randy
--- linux/include/linux/usb.h.orig      Sun May 14 10:49:29 2000
+++ linux/include/linux/usb.h   Sun May 14 15:22:28 2000
@@ -331,6 +331,9 @@
  * New USB Structures                                                         *
  *----------------------------------------------------------------------------*/
 
+/*
+ * urb->transfer_flags:
+ */
 #define USB_DISABLE_SPD         0x0001
 #define USB_ISO_ASAP            0x0002
 #define USB_URB_EARLY_COMPLETE  0x0004
@@ -362,10 +365,11 @@
        void *transfer_buffer;          // associated data buffer
        int transfer_buffer_length;     // data buffer length
        int actual_length;              // actual data buffer length    
+       int bandwidth;                  // bandwidth for this transfer request (INT or 
+ISO)
        unsigned char *setup_packet;    // setup packet (control only)
        //
        int start_frame;                // start frame (iso/irq only)
-       int number_of_packets;          // number of packets in this request (iso/irq 
only)
+       int number_of_packets;          // number of packets in this request (iso)
        int interval;                   // polling interval (irq only)
        int error_count;                // number of errors in this transfer (iso only)
        int timeout;                    // timeout (in jiffies)
@@ -483,7 +487,7 @@
        struct list_head bus_list;
        void *hcpriv;                   /* Host Controller private data */
 
-       unsigned int bandwidth_allocated; /* on this Host Controller; */
+       int bandwidth_allocated;        /* on this Host Controller; */
                                          /* applies to Int. and Isoc. pipes; */
                                          /* measured in microseconds/frame; */
                                          /* range is 0..900, where 900 = */
@@ -554,7 +558,10 @@
 extern void usb_free_dev(struct usb_device *);
 extern void usb_inc_dev_use(struct usb_device *);
 #define usb_dec_dev_use usb_free_dev
-extern void usb_release_bandwidth(struct usb_device *, int);
+
+extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
+extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int 
+bustime, int isoc);
+extern void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc);
 
 extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, 
__u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
 
--- linux/drivers/usb-2399-pre91/uhci.c Fri May 12 13:21:55 2000
+++ linux/drivers/usb/uhci.c    Sun May 14 16:11:05 2000
@@ -1294,6 +1294,7 @@
        struct uhci *uhci;
        unsigned long flags;
        struct urb *u;
+       int bustime;
 
        if (!urb)
                return -EINVAL;
@@ -1323,13 +1324,40 @@
                ret = uhci_submit_control(urb);
                break;
        case PIPE_INTERRUPT:
-               ret = uhci_submit_interrupt(urb);
+               if (urb->bandwidth == 0) {      /* not yet checked/allocated */
+                       bustime = usb_check_bandwidth (urb->dev, urb);
+                       if (bustime < 0)
+                               ret = bustime;
+                       else {
+                               ret = uhci_submit_interrupt(urb);
+                               if (ret == -EINPROGRESS)
+                                       usb_claim_bandwidth (urb->dev, urb, bustime, 
+0);
+                       }
+               } else {        /* bandwidth is already set */
+                       ret = uhci_submit_interrupt(urb);
+               }
                break;
        case PIPE_BULK:
                ret = uhci_submit_bulk(urb, u);
                break;
        case PIPE_ISOCHRONOUS:
-               ret = uhci_submit_isochronous(urb);
+               if (urb->bandwidth == 0) {      /* not yet checked/allocated */
+                       if (urb->number_of_packets <= 0) {
+                               ret = -EINVAL;
+                               break;
+                       }
+                       bustime = usb_check_bandwidth (urb->dev, urb);
+                       if (bustime < 0) {
+                               ret = bustime;
+                               break;
+                       }
+
+                       ret = uhci_submit_isochronous(urb);
+                       if (ret == -EINPROGRESS)
+                               usb_claim_bandwidth (urb->dev, urb, bustime, 1);
+               } else {        /* bandwidth is already set */
+                       ret = uhci_submit_isochronous(urb);
+               }
                break;
        }
 
@@ -1385,6 +1413,10 @@
        case PIPE_CONTROL:
        case PIPE_BULK:
        case PIPE_ISOCHRONOUS:
+               /* Release bandwidth for Interrupt or Isoc. transfers */
+               /* Spinlock needed ? */
+               if (urb->bandwidth)
+                       usb_release_bandwidth (urb->dev, urb, 1);
                uhci_unlink_generic(urb);
                break;
        case PIPE_INTERRUPT:
@@ -1392,8 +1424,13 @@
                urb->complete(urb);
                if (urb->interval)
                        uhci_reset_interrupt(urb);
-               else
+               else {
+                       /* Release bandwidth for Interrupt or Isoc. transfers */
+                       /* Spinlock needed ? */
+                       if (urb->bandwidth)
+                               usb_release_bandwidth (urb->dev, urb, 0);
                        uhci_unlink_generic(urb);
+               }
                return;         /* <-- Note the return */
        }
 
@@ -1473,6 +1510,21 @@
        /* Short circuit the virtual root hub */
        if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
                return rh_unlink_urb(urb);
+
+       /* Release bandwidth for Interrupt or Isoc. transfers */
+       /* Spinlock needed ? */
+       if (urb->bandwidth) {
+               switch (usb_pipetype(urb->pipe)) {
+               case PIPE_INTERRUPT:
+                       usb_release_bandwidth (urb->dev, urb, 0);
+                       break;
+               case PIPE_ISOCHRONOUS:
+                       usb_release_bandwidth (urb->dev, urb, 1);
+                       break;
+               default:
+                       break;
+               }
+       }
 
        if (urb->status == -EINPROGRESS) {
                uhci_unlink_generic(urb);
--- linux/drivers/usb-2399-pre91/usb.c  Mon May  8 17:37:28 2000
+++ linux/drivers/usb/usb.c     Sun May 14 14:28:25 2000
@@ -6,6 +6,7 @@
  * (C) Copyright Andreas Gal 1999
  * (C) Copyright Gregory P. Smith 1999
  * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
  *
  * NOTE! This is not actually a driver at all, rather this is
  * just a collection of helper routines that implement the
@@ -31,6 +32,9 @@
 #endif
 #include <linux/usb.h>
 
+static int bandwidth = 0; /* default to NOT enforcing bandwidth allocation */
+MODULE_PARM(bandwidth, "i");
+
 /*
  * Prototypes for the device driver probing/loading functions
  */
@@ -144,11 +148,11 @@
 
 
 /*
- * calc_bus_time:
+ * usb_calc_bus_time:
  *
  * returns (approximate) USB bus time in nanoseconds for a USB transaction.
  */
-static long calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount)
+static long usb_calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount)
 {
        unsigned long   tmp;
 
@@ -178,16 +182,16 @@
 
        tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
        return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
-} /* end calc_bus_time */
+}
 
 /*
- * check_bandwidth_alloc():
+ * usb_check_bandwidth():
  *
  * old_alloc is from host_controller->bandwidth_allocated in microseconds;
  * bustime is from calc_bus_time(), but converted to microseconds.
  *
- * returns 0 if successful,
- * -1 if bandwidth request fails.
+ * returns <bustime in us> if successful,
+ * or USB_ST_BANDWIDTH_ERROR if bandwidth request fails.
  *
  * FIXME:
  * This initial implementation does not use Endpoint.bInterval
@@ -204,21 +208,67 @@
  * However, this first cut at USB bandwidth allocation does not
  * contain any frame allocation tracking.
  */
-static int check_bandwidth_alloc (unsigned int old_alloc, long bustime)
+int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
 {
-       unsigned int    new_alloc;
+       int             new_alloc;
+       int             old_alloc = dev->bus->bandwidth_allocated;
+       unsigned int    pipe = urb->pipe;
+       long            bustime;
+
+       bustime = usb_calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe),
+                       usb_pipeisoc(pipe), usb_maxpacket(dev, pipe, 
+usb_pipeout(pipe)));
+       if (usb_pipeisoc(pipe))
+               bustime = NS_TO_US(bustime) / urb->number_of_packets;
+       else
+               bustime = NS_TO_US(bustime);
 
-       new_alloc = old_alloc + bustime;
+       new_alloc = old_alloc + (int)bustime;
                /* what new total allocated bus time would be */
 
-       dbg("usb-bandwidth-alloc: was: %u, new: %u, "
-               "bustime = %ld us, Pipe allowed: %s",
-               old_alloc, new_alloc, bustime,
-               (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ?
-                       "yes" : "no");
+       if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC)
+               dbg("usb-check-bandwidth %sFAILED: was %u, would be %u, bustime = %ld 
+us",
+                       bandwidth ? "" : "would have ",
+                       old_alloc, new_alloc, bustime);
+
+       if (!bandwidth)
+               return (bustime);
+       return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? bustime : 
+USB_ST_BANDWIDTH_ERROR;
+}
+
+void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int 
+isoc)
+{
+       dev->bus->bandwidth_allocated += bustime;
+       if (isoc)
+               dev->bus->bandwidth_isoc_reqs++;
+       else
+               dev->bus->bandwidth_int_reqs++;
+       urb->bandwidth = bustime;
+       
+       dbg("bw_alloc increased by %d to %d for %d requesters",
+               bustime,
+               dev->bus->bandwidth_allocated,
+               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+}
+
+/*
+ * usb_release_bandwidth():
+ *
+ * called to release a pipe's bandwidth (in microseconds)
+ */
+void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc)
+{
+       dev->bus->bandwidth_allocated -= urb->bandwidth;
+       if (isoc)
+               dev->bus->bandwidth_isoc_reqs--;
+       else
+               dev->bus->bandwidth_int_reqs--;
 
-       return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? 0 : -1;
-} /* end check_bandwidth_alloc */
+       dbg("bw_alloc reduced by %d to %d for %d requesters",
+               urb->bandwidth,
+               dev->bus->bandwidth_allocated,
+               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+       urb->bandwidth = 0;
+}
 
 /*
  * New functions for (de)registering a controller
@@ -659,21 +709,6 @@
 }
 
 /*
- * usb_release_bandwidth():
- *
- * called to release an interrupt pipe's bandwidth (in microseconds)
- */
-void usb_release_bandwidth(struct usb_device *dev, int bw_alloc)
-{
-       dev->bus->bandwidth_allocated -= bw_alloc;
-       dev->bus->bandwidth_int_reqs--;
-       dbg("bw_alloc reduced to %d for %d requesters",
-               dev->bus->bandwidth_allocated,
-               dev->bus->bandwidth_int_reqs +
-               dev->bus->bandwidth_isoc_reqs);
-}
-
-/*
  * usb_get_current_frame_number()
  *
  * returns the current frame number for the parent USB bus/controller
@@ -684,6 +719,7 @@
        return usb_dev->bus->op->get_frame_number (usb_dev);
 }
 /*-------------------------------------------------------------------*/
+
 static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor 
*endpoint, unsigned char *buffer, int size)
 {
        struct usb_descriptor_header *header;
@@ -1724,6 +1760,9 @@
 EXPORT_SYMBOL(usb_reset_device);
 EXPORT_SYMBOL(usb_connect);
 EXPORT_SYMBOL(usb_disconnect);
+
+EXPORT_SYMBOL(usb_check_bandwidth);
+EXPORT_SYMBOL(usb_claim_bandwidth);
 EXPORT_SYMBOL(usb_release_bandwidth);
 
 EXPORT_SYMBOL(usb_set_address);

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to