From 82b8bbead99a4e476ff7d11c360b8d87fd88ff49 Mon Sep 17 00:00:00 2001 From: Devdutt Patnaik Date: Mon, 4 May 2015 22:02:36 -0700 Subject: [PATCH] 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 Signed-off-by: Azhar Shaikh Signed-off-by: Mayank Rana --- drivers/usb/host/xhci-plat.c | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 7c3bdceaf629..197757c20102 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -73,6 +73,60 @@ static int xhci_plat_start(struct usb_hcd *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) { struct device_node *node = pdev->dev.of_node; @@ -191,6 +245,11 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret) 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_put_autosuspend(&pdev->dev); @@ -224,6 +283,7 @@ static int xhci_plat_remove(struct platform_device *dev) pm_runtime_disable(&dev->dev); + device_remove_file(&dev->dev, &dev_attr_config_imod); usb_remove_hcd(xhci->shared_hcd); usb_phy_shutdown(hcd->usb_phy);