Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs

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

 



On Wed, 2015-10-28 at 16:00 +0800, Lu Baolu wrote:
> The xHCI host exports xHCI-specific extended capabilities utilizing
> a method similar to PCI extended capabilities. In many cases, users
> want to know whether a specific extended capability is supported by
> a host. Unfortunately, currently there's no existing mechanisms in
> the kernel to do this.
> 
> This patch exposes extended capabilities supported by the xHCI host
> via debugfs.
> 
> Signed-off-by: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx>
> ---
>  drivers/usb/host/xhci-dbg.c      | 212 +++++++++++++++++++++++++++++++++++++++
>  drivers/usb/host/xhci-ext-caps.h |   9 +-
>  drivers/usb/host/xhci.c          |  27 ++++-
>  drivers/usb/host/xhci.h          |  10 ++
>  4 files changed, 256 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
> index 74c42f7..d3dcfed 100644
> --- a/drivers/usb/host/xhci-dbg.c
> +++ b/drivers/usb/host/xhci-dbg.c
> @@ -20,6 +20,11 @@
>   * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
>   */
>  
> +#include <linux/vmalloc.h>
> +#include <linux/slab.h>
> +#include <linux/debugfs.h>
> +#include <linux/usb.h>
> +
>  #include "xhci.h"
>  
>  #define XHCI_INIT_VALUE 0x0
> @@ -612,3 +617,210 @@ void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
>  	va_end(args);
>  }
>  EXPORT_SYMBOL_GPL(xhci_dbg_trace);
> +
> +#ifdef CONFIG_DEBUG_FS
> +struct debug_buffer {
> +	ssize_t (*fill_func)(struct debug_buffer *);
> +	struct usb_bus *bus;
> +	struct mutex mutex;
> +	size_t count;
> +	char *output_buf;
> +	size_t alloc_size;
> +};
> +
> +static const char *get_extcap_desc(u32 cap_id)
> +{
> +	switch (cap_id) {
> +	case XHCI_EXT_CAPS_LEGACY:
> +		return "USB Legacy Support";
> +	case XHCI_EXT_CAPS_PROTOCOL:
> +		return "Supported Protocol";
> +	case XHCI_EXT_CAPS_PM:
> +		return "Extended Power Management";
> +	case XHCI_EXT_CAPS_VIRT:
> +		return "I/O Virtualization (xHCI-IOV)";
> +	case XHCI_EXT_CAPS_ROUTE:
> +		return "Message Interrupt";
> +	case XHCI_EXT_CAPS_LOCALMEM:
> +		return "Local Memory";
> +	case XHCI_EXT_CAPS_DEBUG:
> +		return "USB Debug Capability";
> +	default:
> +		if (XHCI_EXT_CAPS_VENDOR(XHCI_EXT_CAPS_ID(cap_id)))
> +			return "Vendor Defined";
> +		else
> +			return "Unknown";
> +	}
> +}
> +
> +static ssize_t fill_extcap_buffer(struct debug_buffer *buf)
> +{
> +	__le32 __iomem	*addr;
> +	struct usb_hcd	*hcd;
> +	struct xhci_hcd	*xhci;
> +	u32		offset, cap_id;
> +	char		*next;
> +	int		size, temp;
> +	unsigned long	flags;
> +	int		time_to_leave;
> +
> +	hcd = bus_to_hcd(buf->bus);
> +	xhci = hcd_to_xhci(hcd);
> +	next = buf->output_buf;
> +	size = buf->alloc_size;
> +
> +	spin_lock_irqsave(&xhci->lock, flags);
> +
> +	addr = &xhci->cap_regs->hcc_params;
> +	offset = XHCI_HCC_EXT_CAPS(readl(addr));
> +	if (!HCD_HW_ACCESSIBLE(hcd) || !offset) {
> +		size = scnprintf(next, size,
> +			"bus %s, device %s\n%s\nNo extended capabilities\n",
> +			hcd->self.controller->bus->name,
> +			dev_name(hcd->self.controller),
> +			hcd->product_desc);
> +		goto done;
> +	}
> +
> +	temp = scnprintf(next, size, "@addr(virt)\t\tCAP_ID\tDescription\n");
> +	size -= temp;
> +	next += temp;
> +
> +	addr = &xhci->cap_regs->hc_capbase + offset;
> +	time_to_leave = XHCI_EXT_MAX_CAPID;
> +	while (time_to_leave--) {
> +		cap_id = readl(addr);
> +		temp = scnprintf(next, size, "@%p\t%02x\t%s\n",
> +			addr, XHCI_EXT_CAPS_ID(cap_id),
> +			get_extcap_desc(XHCI_EXT_CAPS_ID(cap_id)));
> +		size -= temp;
> +		next += temp;
> +
> +		offset = XHCI_EXT_CAPS_NEXT(cap_id);
> +		if (!offset)
> +			break;
> +		addr += offset;
> +	}
> +
> +done:
> +	spin_unlock_irqrestore(&xhci->lock, flags);
> +
> +	return buf->alloc_size - size;
> +}
> +
> +static struct debug_buffer *buffer_init(struct usb_bus *bus,
> +				ssize_t (*fill_func)(struct debug_buffer *))
> +{
> +	struct debug_buffer *buf;
> +
> +	buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
> +	if (!buf)
> +		return NULL;
> +
> +	buf->bus = bus;
> +	buf->fill_func = fill_func;
> +	mutex_init(&buf->mutex);
> +
> +	return buf;
> +}
> +
> +static int fill_buffer(struct debug_buffer *buf)
> +{
> +	int ret;
> +
> +	if (buf->output_buf)
> +		return -EINVAL;
> +
> +	buf->alloc_size = PAGE_SIZE;
> +	buf->output_buf = vmalloc(buf->alloc_size);

That really makes no sense. If you allocate exactly
PAGE_SIZE, you should allocate a page.

	Regards
		Oliver


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