[PATCH] USB: usbtest - Add tests to ensure HCDs can accept byte aligned buffers.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds two new tests: #17 and #18 which are similar to
tests #1 and #2 except that instead of allocating the data buffers
with usb_alloc_coherent() and setting URB_NO_TRANSFER_DMA_MAP
they use kmalloc() plus a 0-3 byte offset and let the core
do the DMA mapping.

This mimics the behaviour of drivers such as usbnet which add
an offset to the transfer_buffer to align the IP header and
causes problems for HCDs that don't accept arbitary alignment
for DMA buffers.

Signed-off-by: Martin Fuzzey <mfuzzey@xxxxxxxxx>

---

 drivers/usb/misc/usbtest.c |  102 +++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 96 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 16dffe9..5acf2ac 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -84,6 +84,8 @@ static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test)
 #define WARNING(tdev, fmt, args...) \
 	dev_warn(&(tdev)->intf->dev , fmt , ## args)
 
+#define GUARD_BYTE	0xA5
+
 /*-------------------------------------------------------------------------*/
 
 static int
@@ -184,10 +186,12 @@ static void simple_callback (struct urb *urb)
 	complete(urb->context);
 }
 
-static struct urb *simple_alloc_urb (
+static struct urb *usbtest_alloc_urb(
 	struct usb_device	*udev,
 	int			pipe,
-	unsigned long		bytes
+	unsigned long		bytes,
+	unsigned int		transfer_flags,
+	unsigned int		offset
 )
 {
 	struct urb		*urb;
@@ -199,11 +203,23 @@ static struct urb *simple_alloc_urb (
 	urb->interval = (udev->speed == USB_SPEED_HIGH)
 			? (INTERRUPT_RATE << 3)
 			: INTERRUPT_RATE;
-	urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+	urb->transfer_flags = transfer_flags;
 	if (usb_pipein (pipe))
 		urb->transfer_flags |= URB_SHORT_NOT_OK;
-	urb->transfer_buffer = usb_alloc_coherent (udev, bytes, GFP_KERNEL,
-			&urb->transfer_dma);
+
+	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
+		urb->transfer_buffer = usb_alloc_coherent(udev, bytes,
+			GFP_KERNEL, &urb->transfer_dma);
+	else {
+		/* To test unaligned transfers add an offset and fill the
+			unused memory with a guard value */
+		urb->transfer_buffer = kmalloc(bytes + offset, GFP_KERNEL);
+		if (urb->transfer_buffer) {
+			memset(urb->transfer_buffer, GUARD_BYTE, offset);
+			urb->transfer_buffer += offset;
+		}
+	}
+
 	if (!urb->transfer_buffer) {
 		usb_free_urb (urb);
 		urb = NULL;
@@ -212,6 +228,15 @@ static struct urb *simple_alloc_urb (
 	return urb;
 }
 
+static struct urb *simple_alloc_urb(
+	struct usb_device	*udev,
+	int			pipe,
+	unsigned long		bytes
+)
+{
+	return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0);
+}
+
 static unsigned pattern = 0;
 static unsigned mod_pattern;
 module_param_named(pattern, mod_pattern, uint, S_IRUGO | S_IWUSR);
@@ -236,13 +261,27 @@ static inline void simple_fill_buf (struct urb *urb)
 	}
 }
 
+static inline void *containing_buffer(void *buf)
+{
+	return (void *)((unsigned)buf & ~(ARCH_KMALLOC_MINALIGN - 1));
+}
+
 static inline int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
 {
 	unsigned	i;
 	u8		expected;
 	u8		*buf = urb->transfer_buffer;
+	u8		*guard = containing_buffer(buf);
 	unsigned	len = urb->actual_length;
 
+	for (i = 0; guard < buf; i++, guard++) {
+		if (*guard != GUARD_BYTE) {
+			ERROR(tdev, "guard byte[%d] %d (not %d)\n",
+				i, *guard, GUARD_BYTE);
+			return -EINVAL;
+		}
+	}
+
 	for (i = 0; i < len; i++, buf++) {
 		switch (pattern) {
 		/* all-zeroes has no synchronization issues */
@@ -272,8 +311,11 @@ static inline int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
 
 static void simple_free_urb (struct urb *urb)
 {
-	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
+		usb_free_coherent(urb->dev, urb->transfer_buffer_length,
 			  urb->transfer_buffer, urb->transfer_dma);
+	else
+		kfree(containing_buffer(urb->transfer_buffer));
 	usb_free_urb (urb);
 }
 
@@ -1560,6 +1602,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
 	struct usb_sg_request	req;
 	struct timeval		start;
 	unsigned		i;
+	unsigned		offset;
 
 	// FIXME USBDEVFS_CONNECTINFO doesn't say how fast the device is.
 
@@ -1858,6 +1901,53 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
 
 	// FIXME scatterlist cancel (needs helper thread)
 
+	/* Tests for bulk I/O using DMA mapping by core with various offsets
+		simulates use by usbnet drivers which add offset to align
+		the IP header
+	*/
+	case 17:
+		if (dev->out_pipe == 0)
+			break;
+		dev_info(&intf->dev,
+			"TEST 17:  write %d bytes %u times core dmamap\n",
+			param->length, param->iterations);
+		for (offset = 0; offset < 4; offset++) {
+			dev_info(&intf->dev, "offset=%d\n", offset);
+			urb = usbtest_alloc_urb(udev, dev->out_pipe,
+				param->length, 0, offset);
+			if (!urb) {
+				retval = -ENOMEM;
+				break;
+			}
+			retval = simple_io(dev, urb, param->iterations,
+				0, 0, "test17");
+			simple_free_urb(urb);
+			if (retval)
+				break;
+		}
+		break;
+
+	case 18:
+		if (dev->in_pipe == 0)
+			break;
+		dev_info(&intf->dev,
+			"TEST 18:  read %d bytes %u times core dmamap\n",
+			param->length, param->iterations);
+		for (offset = 0; offset < 4; offset++) {
+			dev_info(&intf->dev, "offset=%d\n", offset);
+			urb = usbtest_alloc_urb(udev, dev->in_pipe,
+				param->length, 0, offset);
+			if (!urb) {
+				retval = -ENOMEM;
+				break;
+			}
+			retval = simple_io(dev, urb, param->iterations,
+				0, 0, "test18");
+			simple_free_urb(urb);
+			if (retval)
+				break;
+		}
+		break;
 	}
 	do_gettimeofday (&param->duration);
 	param->duration.tv_sec -= start.tv_sec;

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux