Re: [RFC] pass sg lists to HCDs if supported

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

 



On Wed, Feb 04, 2009 at 06:54:04PM +0000, David Vrabel wrote:
> Here's a new version of the patch:
> 
> No new fields are added to struct urb.  urb->transfer_buffer points to a
> struct sg_table if urb->transfer_flags & URB_HAS_SG.
> 
> The sg table stores both the original number of entries and the number
> of DMA mapped entries allowing HCDs to choose whether to iterate over
> the DMA mapped entries or the original unmapped ones.

I'm a bit confused as to why a host controller would want to limit the
number of entries in an sg list (instead of say, the size of the overall
transfer or some other metric).  I can't see why I wouldn't want to
limit the number of sg list entries for xHCI, but I'm not familiar with
what the scsi core does with Scsi_Host->sg_tablesize.

The only usage of bus->sg_tablesize is here:

Index: linux-working/drivers/usb/core/message.c
...
+	if (dev->bus->sg_tablesize) {
+		ret = usb_sg_init_with_sg(io, dev, pipe, period, sg, length, mem_flags);
+	} else {
+		ret = usb_sg_init_without_sg(io, dev, pipe, period, sg, length, mem_flags);
+	}

Index: linux-working/drivers/usb/storage/usb.c
...
+	/*
+	 * If the USB HCD supports sg lists, limit sg_tablesize.
+	 */
+	{
+		struct usb_device *usb_dev = interface_to_usbdev(intf);
+		if (usb_dev->bus->sg_tablesize) {
+			host->sg_tablesize = usb_dev->bus->sg_tablesize;
+		}
+	}
 	us = host_to_us(host);
 	memset(us, 0, sizeof(struct us_data));
 	mutex_init(&(us->dev_mutex));

Index: linux-working/include/linux/usb.h
...
 	u8 otg_port;			/* 0, or number of OTG/HNP port */
 	unsigned is_b_host:1;		/* true during some HNP roleswitches */
 	unsigned b_hnp_enable:1;	/* OTG: did A-Host enable HNP? */
+	int sg_tablesize;               /* 0 or largest number of sg list entries */
 
 	int devnum_next;		/* Next open device number in
 					 * round-robin allocation */
@@ -1114,6 +1115,7 @@

I think there's also a memory leak:

Index: linux-working/drivers/usb/core/message.c
...
+	/* initialize one urb with transfer_buffer pointing to a new sg_table */
+	io->urbs = kmalloc(sizeof(struct urb *) + sizeof(struct sg_table), mem_flags);
+	if (!io->urbs)
+		return -ENOMEM;
+
+	sgt = (struct sg_table *)&io->urbs[1];
+	sgt->sgl = sg;
+	sgt->orig_nents = io->nents;
+
+	/* not all host controllers use DMA (like the mainstream pci ones);
+	 * they can use PIO (sl811) or be software over another transport.
+	 */
+	if (dev->dev.dma_mask != NULL)
+		sgt->nents = usb_buffer_map_sg(dev, usb_pipein(pipe), sg, io->nents);
+	else
+		sgt->nents = sgt->orig_nents;
+	if (sgt->nents <= 0)
+		return sgt->nents;
+
+	io->urbs[0] = usb_alloc_urb(0, mem_flags);
+	if (!io->urbs[0])
+		return -ENOMEM;
+	io->entries = 1;

Do you want to free io->urbs[0] and sg_table if usb_alloc_urb() fails?
sg_clean() won't free anything io->urbs points to because io->entries is
set to zero by sg_init().

Other than that, and my confusion with bus->sg_tablesize, the patch
looks fine.  I think can easily rework my xHCI patches to look for
URB_HAS_SG and pull the sg list out of urb->transfer_buffer.

Sarah Sharp
--
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