usb: xhci-plat: Add support to modify imod from sysfs

xhci allows interrupts to be moderated at 250ns interval;
provide an sysfs interface to modify interrupt rate from
userspace to understand throughput variation by changing imod.

Usage:
Below command will moderate interrupts at 1ms or (4000 * 250ns)
interval.
echo 4000 > /sys/devices/8a00000.ssusb/8a00000.dwc3/xhci-hcd.0.auto/
config_imod

Change-Id: I455d5a0f9a0314e86f711efd35315002b20f5343
Signed-off-by: Devdutt Patnaik <dpatnaik@codeaurora.org>
Signed-off-by: Azhar Shaikh <azhars@codeaurora.org>
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
This commit is contained in:
Devdutt Patnaik 2015-05-04 22:02:36 -07:00 committed by David Keitel
parent 2fe7dc7ee3
commit 82b8bbead9

View file

@ -73,6 +73,60 @@ static int xhci_plat_start(struct usb_hcd *hcd)
return xhci_run(hcd); return xhci_run(hcd);
} }
static ssize_t config_imod_store(struct device *pdev,
struct device_attribute *attr, const char *buff, size_t size)
{
struct usb_hcd *hcd = dev_get_drvdata(pdev);
struct xhci_hcd *xhci;
u32 temp;
u32 imod;
unsigned long flags;
if (kstrtouint(buff, 10, &imod) != 1)
return 0;
imod &= ER_IRQ_INTERVAL_MASK;
xhci = hcd_to_xhci(hcd);
if (xhci->shared_hcd->state == HC_STATE_SUSPENDED
&& hcd->state == HC_STATE_SUSPENDED)
return -EACCES;
spin_lock_irqsave(&xhci->lock, flags);
temp = readl_relaxed(&xhci->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
temp |= imod;
writel_relaxed(temp, &xhci->ir_set->irq_control);
spin_unlock_irqrestore(&xhci->lock, flags);
return size;
}
static ssize_t config_imod_show(struct device *pdev,
struct device_attribute *attr, char *buff)
{
struct usb_hcd *hcd = dev_get_drvdata(pdev);
struct xhci_hcd *xhci;
u32 temp;
unsigned long flags;
xhci = hcd_to_xhci(hcd);
if (xhci->shared_hcd->state == HC_STATE_SUSPENDED
&& hcd->state == HC_STATE_SUSPENDED)
return -EACCES;
spin_lock_irqsave(&xhci->lock, flags);
temp = readl_relaxed(&xhci->ir_set->irq_control) &
ER_IRQ_INTERVAL_MASK;
spin_unlock_irqrestore(&xhci->lock, flags);
return snprintf(buff, PAGE_SIZE, "%08u\n", temp);
}
static DEVICE_ATTR(config_imod, S_IRUGO | S_IWUSR,
config_imod_show, config_imod_store);
static int xhci_plat_probe(struct platform_device *pdev) static int xhci_plat_probe(struct platform_device *pdev)
{ {
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
@ -191,6 +245,11 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (ret) if (ret)
goto dealloc_usb2_hcd; goto dealloc_usb2_hcd;
ret = device_create_file(&pdev->dev, &dev_attr_config_imod);
if (ret)
dev_err(&pdev->dev, "%s: unable to create imod sysfs entry\n",
__func__);
pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev);
@ -224,6 +283,7 @@ static int xhci_plat_remove(struct platform_device *dev)
pm_runtime_disable(&dev->dev); pm_runtime_disable(&dev->dev);
device_remove_file(&dev->dev, &dev_attr_config_imod);
usb_remove_hcd(xhci->shared_hcd); usb_remove_hcd(xhci->shared_hcd);
usb_phy_shutdown(hcd->usb_phy); usb_phy_shutdown(hcd->usb_phy);