Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs
From: Oliver Neukum
Date: Wed Oct 28 2015 - 05:28:48 EST
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-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/