Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 10 Nov 2009 21:44:36 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 170449 for review
Message-ID:  <200911102144.nAALiaG4045048@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/chv.cgi?CH=170449

Change 170449 by hselasky@hselasky_laptop001 on 2009/11/10 21:43:38

	
	USB CORE:
		- improve and factor out USB High-Speed slot allocation mechanism.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/controller/ehci.c#43 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_core.h#30 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_device.c#57 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_hub.c#37 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_hub.h#15 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#172 edit
.. //depot/projects/usb/src/sys/dev/usb/usbdi.h#14 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/controller/ehci.c#43 (text+ko) ====

@@ -2020,8 +2020,8 @@
 
 	qh_endphub =
 	    (EHCI_QH_SET_MULT(xfer->max_packet_count & 3) |
-	    EHCI_QH_SET_CMASK(xfer->usb_cmask) |
-	    EHCI_QH_SET_SMASK(xfer->usb_smask) |
+	    EHCI_QH_SET_CMASK(xfer->endpoint->usb_cmask) |
+	    EHCI_QH_SET_SMASK(xfer->endpoint->usb_smask) |
 	    EHCI_QH_SET_HUBA(xfer->xroot->udev->hs_hub_addr) |
 	    EHCI_QH_SET_PORT(xfer->xroot->udev->hs_port_no));
 
@@ -2166,7 +2166,7 @@
 
 		DPRINTFN(2, "status=0x%08x, len=%u\n", status, len);
 
-		if (xfer->usb_smask & (1 << td_no)) {
+		if (xfer->endpoint->usb_smask & (1 << td_no)) {
 
 			if (*plen >= len) {
 				/*
@@ -2352,25 +2352,9 @@
 	uint16_t best;
 	uint16_t bit;
 	uint16_t x;
-	uint8_t slot;
 
-	/* Allocate a microframe slot first: */
-
-	slot = usb_intr_schedule_adjust(xfer->xroot->udev,
-	    xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX, 0x01);
-
-	if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) {
-		xfer->usb_uframe = slot;
-		xfer->usb_smask = (0x01 << slot) & 0xFF;
-		xfer->usb_cmask = 0x00;
-	} else {
-		xfer->usb_uframe = slot;
-		xfer->usb_smask = (0x01 << slot) & 0x3F;
-		xfer->usb_cmask = (-(0x04 << slot)) & 0xFE;
-	}
+	usb_hs_bandwidth_alloc(xfer);
 
-	DPRINTFN(11, "slot=%d\n", slot);
-
 	/*
 	 * Find the best QH position corresponding to the given interval:
 	 */
@@ -2405,14 +2389,12 @@
 {
 	ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus);
 
-	/* Free microframe slot: */
-
-	usb_intr_schedule_adjust(xfer->xroot->udev,
-	    -xfer->max_frame_size, xfer->usb_uframe, 0x01);
-
 	sc->sc_intr_stat[xfer->qh_pos]--;
 
 	ehci_device_done(xfer, USB_ERR_CANCELLED);
+
+	/* bandwidth must be freed after device done */
+	usb_hs_bandwidth_free(xfer);
 }
 
 static void
@@ -2734,35 +2716,9 @@
 	ehci_itd_t *td;
 	uint32_t temp;
 	uint8_t ds;
-	uint8_t slot;
-	uint8_t mask;
 
-	switch (usbd_xfer_get_fps_shift(xfer)) {
-	case 0:
-		mask = 0xFF;
-		break;
-	case 1:
-		mask = 0x55;
-		break;
-	case 2:
-		mask = 0x11;
-		break;
-	default:
-		mask = 0x01;
-		break;
-	}
-
-	/* Allocate a microframe multi-slot first: */
-
-	slot = usb_intr_schedule_adjust(xfer->xroot->udev,
-	    xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX, mask);
+	usb_hs_bandwidth_alloc(xfer);
 
-	xfer->usb_uframe = slot;
-	xfer->usb_cmask = 0;
-	xfer->usb_smask = mask << slot;
-
-	DPRINTFN(11, "slot=%d, mask=0x%02x\n", slot, mask);
-
 	/* initialize all TD's */
 
 	for (ds = 0; ds != 2; ds++) {
@@ -2805,14 +2761,10 @@
 static void
 ehci_device_isoc_hs_close(struct usb_xfer *xfer)
 {
+	ehci_device_done(xfer, USB_ERR_CANCELLED);
 
-	/* Free microframe multi-slot: */
-
-	usb_intr_schedule_adjust(xfer->xroot->udev,
-	    -xfer->max_frame_size, xfer->usb_uframe,
-	    xfer->usb_smask >> xfer->usb_uframe);
-
-	ehci_device_done(xfer, USB_ERR_CANCELLED);
+	/* bandwidth must be freed after device done */
+	usb_hs_bandwidth_free(xfer);
 }
 
 static void
@@ -2922,7 +2874,7 @@
 			*plen = xfer->max_frame_size;
 		}
 
-		if (xfer->usb_smask & (1 << td_no)) {
+		if (xfer->endpoint->usb_smask & (1 << td_no)) {
 			status = (EHCI_ITD_SET_LEN(*plen) |
 			    EHCI_ITD_ACTIVE |
 			    EHCI_ITD_SET_PG(0));

==== //depot/projects/usb/src/sys/dev/usb/usb_core.h#30 (text+ko) ====

@@ -161,9 +161,6 @@
 	uint8_t	address;		/* physical USB address */
 	uint8_t	endpointno;		/* physical USB endpoint */
 	uint8_t	max_packet_count;
-	uint8_t	usb_smask;
-	uint8_t	usb_cmask;
-	uint8_t	usb_uframe;
 	uint8_t	usb_state;
 	uint8_t fps_shift;		/* down shift of FPS, 0..3 */
 

==== //depot/projects/usb/src/sys/dev/usb/usb_device.c#57 (text+ko) ====

@@ -665,7 +665,7 @@
 			/* look for matching endpoints */
 			if ((iface_index == USB_IFACE_INDEX_ANY) ||
 			    (iface_index == ep->iface_index)) {
-				if (ep->refcount != 0) {
+				if (ep->refcount_alloc != 0) {
 					/*
 					 * This typically indicates a
 					 * more serious error.

==== //depot/projects/usb/src/sys/dev/usb/usb_hub.c#37 (text+ko) ====

@@ -1145,7 +1145,7 @@
 }
 
 /*------------------------------------------------------------------------*
- *	usb_intr_schedule_adjust
+ *	usb_hs_bandwidth_adjust
  *
  * This function will update the bandwith usage for the microframe
  * having index "slot" by "len" bytes. "len" can be negative.  If the
@@ -1156,8 +1156,8 @@
  * Returns:
  *    The slot in which the bandwidth update was done: 0..7
  *------------------------------------------------------------------------*/
-uint8_t
-usb_intr_schedule_adjust(struct usb_device *udev, int16_t len,
+static uint8_t
+usb_hs_bandwidth_adjust(struct usb_device *udev, int16_t len,
     uint8_t slot, uint8_t mask)
 {
 	struct usb_bus *bus = udev->bus;
@@ -1210,6 +1210,132 @@
 }
 
 /*------------------------------------------------------------------------*
+ *	usb_hs_bandwidth_alloc
+ *
+ * This function is a wrapper function for "usb_hs_bandwidth_adjust()".
+ *------------------------------------------------------------------------*/
+void
+usb_hs_bandwidth_alloc(struct usb_xfer *xfer)
+{
+	struct usb_device *udev;
+	uint8_t slot;
+	uint8_t mask;
+	uint8_t speed;
+
+	udev = xfer->xroot->udev;
+
+	if (udev->flags.usb_mode != USB_MODE_HOST)
+		return;		/* not supported */
+
+	xfer->endpoint->refcount_bw++;
+	if (xfer->endpoint->refcount_bw != 1)
+		return;		/* already allocated */
+
+	speed = usbd_get_speed(udev);
+
+	switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) {
+	case UE_INTERRUPT:
+		/* allocate a microframe slot */
+
+		mask = 0x01;
+		slot = usb_hs_bandwidth_adjust(udev,
+		    xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX, mask);
+
+		xfer->endpoint->usb_uframe = slot;
+		xfer->endpoint->usb_smask = mask << slot;
+
+		if ((speed != USB_SPEED_FULL) &&
+		    (speed != USB_SPEED_LOW)) {
+			xfer->endpoint->usb_cmask = 0x00 ;
+		} else {
+			xfer->endpoint->usb_cmask = (-(0x04 << slot)) & 0xFE;
+		}
+		break;
+
+	case UE_ISOCHRONOUS:
+		switch (usbd_xfer_get_fps_shift(xfer)) {
+		case 0:
+			mask = 0xFF;
+			break;
+		case 1:
+			mask = 0x55;
+			break;
+		case 2:
+			mask = 0x11;
+			break;
+		default:
+			mask = 0x01;
+			break;
+		}
+
+		/* allocate a microframe multi-slot */
+
+		slot = usb_hs_bandwidth_adjust(udev,
+		    xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX, mask);
+
+		xfer->endpoint->usb_uframe = slot;
+		xfer->endpoint->usb_cmask = 0;
+		xfer->endpoint->usb_smask = mask << slot;
+		break;
+
+	default:
+		xfer->endpoint->usb_uframe = 0;
+		xfer->endpoint->usb_cmask = 0;
+		xfer->endpoint->usb_smask = 0;
+		break;
+	}
+
+	DPRINTFN(11, "slot=%d, mask=0x%02x\n", 
+	    xfer->endpoint->usb_uframe, 
+	    xfer->endpoint->usb_smask >> xfer->endpoint->usb_uframe);
+}
+
+/*------------------------------------------------------------------------*
+ *	usb_hs_bandwidth_free
+ *
+ * This function is a wrapper function for "usb_hs_bandwidth_adjust()".
+ *------------------------------------------------------------------------*/
+void
+usb_hs_bandwidth_free(struct usb_xfer *xfer)
+{
+	struct usb_device *udev;
+	uint8_t slot;
+	uint8_t mask;
+
+	udev = xfer->xroot->udev;
+
+	if (udev->flags.usb_mode != USB_MODE_HOST)
+		return;		/* not supported */
+
+	xfer->endpoint->refcount_bw--;
+	if (xfer->endpoint->refcount_bw != 0)
+		return;		/* still allocated */
+
+	switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) {
+	case UE_INTERRUPT:
+	case UE_ISOCHRONOUS:
+
+		slot = xfer->endpoint->usb_uframe;
+		mask = xfer->endpoint->usb_smask;
+
+		/* free microframe slot(s): */ 	  
+		usb_hs_bandwidth_adjust(udev,
+		    -xfer->max_frame_size, slot, mask >> slot);
+
+		DPRINTFN(11, "slot=%d, mask=0x%02x\n", 
+		    slot, mask >> slot);
+
+		xfer->endpoint->usb_uframe = 0;
+		xfer->endpoint->usb_cmask = 0;
+		xfer->endpoint->usb_smask = 0;
+		break;
+
+	default:
+		break;
+	}
+}
+
+/*------------------------------------------------------------------------*
  *	usbd_fs_isoc_schedule_init_sub
  *
  * This function initialises an USB FULL speed isochronous schedule

==== //depot/projects/usb/src/sys/dev/usb/usb_hub.h#15 (text+ko) ====

@@ -66,8 +66,8 @@
 
 /* function prototypes */
 
-uint8_t	usb_intr_schedule_adjust(struct usb_device *udev, int16_t len,
-	    uint8_t slot, uint8_t mask);
+void	usb_hs_bandwidth_alloc(struct usb_xfer *xfer);
+void	usb_hs_bandwidth_free(struct usb_xfer *xfer);
 void	usbd_fs_isoc_schedule_init_all(struct usb_fs_isoc_schedule *fss);
 void	usb_bus_port_set_device(struct usb_bus *bus, struct usb_port *up,
 	    struct usb_device *udev, uint8_t device_index);

==== //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#172 (text+ko) ====

@@ -942,10 +942,18 @@
 				 * configuration and alternate setting
 				 * when USB transfers are in use on
 				 * the given interface. Search the USB
-				 * code for "endpoint->refcount" if you
+				 * code for "endpoint->refcount_alloc" if you
 				 * want more information.
 				 */
-				xfer->endpoint->refcount++;
+				USB_BUS_LOCK(info->bus);
+				if (xfer->endpoint->refcount_alloc >= USB_EP_REF_MAX)
+					parm.err = USB_ERR_INVAL;
+
+				xfer->endpoint->refcount_alloc++;
+
+				if (xfer->endpoint->refcount_alloc == 0)
+					panic("usbd_transfer_setup(): Refcount wrapped to zero\n");
+				USB_BUS_UNLOCK(info->bus);
 
 				/*
 				 * Whenever we set ppxfer[] then we
@@ -960,6 +968,10 @@
 				 */
 				ppxfer[n] = xfer;
 			}
+
+			/* check for error */
+			if (parm.err)
+				goto done;
 		}
 
 		if (buf || parm.err) {
@@ -1179,7 +1191,9 @@
 		 * NOTE: default endpoint does not have an
 		 * interface, even if endpoint->iface_index == 0
 		 */
-		xfer->endpoint->refcount--;
+		USB_BUS_LOCK(info->bus);
+		xfer->endpoint->refcount_alloc--;
+		USB_BUS_UNLOCK(info->bus);
 
 		usb_callout_drain(&xfer->timeout_handle);
 

==== //depot/projects/usb/src/sys/dev/usb/usbdi.h#14 (text+ko) ====

@@ -130,13 +130,22 @@
 	struct usb_pipe_methods *methods;	/* set by HC driver */
 
 	uint16_t isoc_next;
-	uint16_t refcount;
 
 	uint8_t	toggle_next:1;		/* next data toggle value */
 	uint8_t	is_stalled:1;		/* set if endpoint is stalled */
 	uint8_t	is_synced:1;		/* set if we a synchronised */
 	uint8_t	unused:5;
 	uint8_t	iface_index;		/* not used by "default endpoint" */
+
+	uint8_t refcount_alloc;		/* allocation refcount */
+	uint8_t refcount_bw;		/* bandwidth refcount */
+#define	USB_EP_REF_MAX 0x3f
+
+	/* High-Speed resource allocation (valid if "refcount_bw" > 0) */
+
+	uint8_t	usb_smask;		/* USB start mask */
+	uint8_t	usb_cmask;		/* USB complete mask */
+	uint8_t	usb_uframe;		/* USB microframe */
 };
 
 /*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200911102144.nAALiaG4045048>