[PATCH 7/7] usb: dwc3: pci: Add debugfs for device properties

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

 



Add the ability for PCI platforms to customize device properties via
debugfs attributes. For IP and FPGA validation purposes, this feature is
useful to test against various HW configurations that are normally
statically configured in a real HW. It allows changing of the device
properties while using the same PID and VID without recompiling the
driver with a different set of properties every time.

Overview of this feature:
 * dwc3_pci_probe() will not immediately create and add platform device
   (That is, nothing will happen when dwc3-pci module is first loaded)
 * The user initiates platform device creation and addition to device
   hierarchy by writing to 'start' debugfs attribute
 * dwc3-pci creates debugfs attributes for device properties
 * The user can set these properties via those attributes
 * dwc3-pci stores the properties that the user set (they are added to
   platform device when user initiates 'start')
 * Device properties cannot be changed after the platform device has
   been added to device hierarchy

This feature is not enabled by default, the user must enable
CONFIG_USB_DWC3_PCI_DEBUGFS in order to use this feature. Currently
there is only one property -- maximum_speed.

Signed-off-by: Thinh Nguyen <thinhn@xxxxxxxxxxxx>
---
 drivers/usb/dwc3/Kconfig       |  11 ++++
 drivers/usb/dwc3/Makefile      |   3 +
 drivers/usb/dwc3/dwc3-pci.h    |  26 ++++++++
 drivers/usb/dwc3/pci-debugfs.c | 144 +++++++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc3/pci.c         |  13 +++-
 5 files changed, 196 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/dwc3/pci-debugfs.c

diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index ab8c0e0d3b60..e6d03e88ca27 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -80,6 +80,17 @@ config USB_DWC3_PCI
 	  One such PCIe-based platform is Synopsys' PCIe HAPS model of
 	  this IP.
 
+if USB_DWC3_PCI
+config USB_DWC3_PCI_DEBUGFS
+	bool "Enable PCI Debugfs"
+	depends on DEBUG_FS
+	default n
+	help
+	  Enable debugging options for DWC3 PCIe-base platform. This allows
+	  setting of DWC3 properties dynamically.
+
+endif
+
 config USB_DWC3_KEYSTONE
 	tristate "Texas Instruments Keystone2 Platforms"
 	depends on ARCH_KEYSTONE || COMPILE_TEST
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 272b6f9fba28..828ae686c186 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -50,3 +50,6 @@ obj-$(CONFIG_USB_DWC3_OF_SIMPLE)	+= dwc3-of-simple.o
 obj-$(CONFIG_USB_DWC3_ST)		+= dwc3-st.o
 
 dwc3-pci-y				:= pci.o
+ifneq ($(CONFIG_USB_DWC3_PCI_DEBUGFS),)
+	dwc3-pci-y			+= pci-debugfs.o
+endif
diff --git a/drivers/usb/dwc3/dwc3-pci.h b/drivers/usb/dwc3/dwc3-pci.h
index 55f2b0a8e5e9..3d87225dac70 100644
--- a/drivers/usb/dwc3/dwc3-pci.h
+++ b/drivers/usb/dwc3/dwc3-pci.h
@@ -15,12 +15,23 @@
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 
+/**
+ * struct dwc3_params - property settings from debugfs attributes
+ * @maximum_speed: device maximum speed
+ */
+struct dwc3_params {
+	u8 maximum_speed;
+};
+
 /**
  * struct dwc3_pci - Driver private structure
  * @dwc3: child dwc3 platform_device
  * @pci: our link to PCI bus
  * @guid: _DSM GUID
  * @has_dsm_for_pm: true for devices which need to run _DSM on runtime PM
+ * @lock: locking mechanism
+ * @root: debugfs root folder pointer
+ * @params: property settings from debugfs attributes
  * @properties: null terminated array of device properties
  * @property_array_size: property array size
  */
@@ -33,6 +44,11 @@ struct dwc3_pci {
 	unsigned int has_dsm_for_pm:1;
 	struct work_struct wakeup_work;
 
+	/* device lock */
+	spinlock_t lock;
+
+	struct dentry *root;
+	struct dwc3_params params;
 	struct property_entry *properties;
 	int property_array_size;
 };
@@ -43,4 +59,14 @@ int dwc3_pci_add_properties(struct dwc3_pci *dwc,
 			    struct property_entry *properties);
 int dwc3_pci_add_platform_device(struct dwc3_pci *dwc);
 
+#ifdef CONFIG_USB_DWC3_PCI_DEBUGFS
+void dwc3_pci_debugfs_init(struct dwc3_pci *dwc);
+void dwc3_pci_debugfs_exit(struct dwc3_pci *dwc);
+#else
+static inline void dwc3_pci_debugfs_init(struct dwc3_pci *dwc)
+{ }
+static inline void dwc3_pci_debugfs_exit(struct dwc3_pci *dwc)
+{ }
+#endif
+
 #endif /* __DWC3_PCI_H */
diff --git a/drivers/usb/dwc3/pci-debugfs.c b/drivers/usb/dwc3/pci-debugfs.c
new file mode 100644
index 000000000000..8fb8ad1133a2
--- /dev/null
+++ b/drivers/usb/dwc3/pci-debugfs.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * pci-debugfs.c - DesignWare USB3 DRD Controller PCI DebugFS file
+ *
+ * Copyright (C) 2018 Synopsys, Inc.
+ *
+ * Authors: Felipe Balbi <balbi@xxxxxx>,
+ *	    Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+
+#include <linux/usb/ch9.h>
+
+#include "dwc3-pci.h"
+
+static void dwc3_params_init(struct dwc3_pci *dwc)
+{
+	dwc->params.maximum_speed = USB_SPEED_UNKNOWN;
+}
+
+static int dwc3_param_set_maxspeed(struct dwc3_pci *dwc)
+{
+	struct device *dev = &dwc->pci->dev;
+	struct dwc3_params *params = &dwc->params;
+	const char *speed = usb_speed_string(params->maximum_speed);
+	struct property_entry property = PROPERTY_ENTRY_STRING("maximum-speed",
+							       speed);
+
+	switch (params->maximum_speed) {
+	case USB_SPEED_LOW:
+	case USB_SPEED_FULL:
+	case USB_SPEED_HIGH:
+	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
+		return dwc3_pci_add_one_property(dwc, property);
+	default:
+		dev_err(dev, "Invalid speed: %d\n", params->maximum_speed);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dwc3_params_set(struct dwc3_pci *dwc)
+{
+	int ret;
+	struct dwc3_params *params = &dwc->params;
+
+	if (params->maximum_speed != USB_SPEED_UNKNOWN) {
+		ret = dwc3_param_set_maxspeed(dwc);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static ssize_t dwc3_start_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	struct seq_file *s = file->private_data;
+	struct dwc3_pci *dwc = s->private;
+	struct device *dev = &dwc->pci->dev;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (dwc->dwc3)
+		goto fail;
+
+	ret = dwc3_params_set(dwc);
+	if (ret)
+		goto fail;
+
+	ret = dwc3_pci_add_platform_device(dwc);
+	if (ret) {
+		dev_err(dev, "failed to register dwc3 device\n");
+		goto fail;
+	}
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return count;
+
+fail:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+	return count;
+}
+
+static int dwc3_start_show(struct seq_file *s, void *unused)
+{
+	return 0;
+}
+
+static int dwc3_start_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_start_show, inode->i_private);
+}
+
+static const struct file_operations dwc3_start_fops = {
+	.open = dwc3_start_open,
+	.write = dwc3_start_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+void dwc3_pci_debugfs_init(struct dwc3_pci *dwc)
+{
+	struct dentry *root;
+	struct dentry *file;
+	struct pci_dev *pci = dwc->pci;
+
+	dwc3_params_init(dwc);
+
+	root = debugfs_create_dir(dev_name(&pci->dev), NULL);
+	if (IS_ERR_OR_NULL(root)) {
+		dev_err(&pci->dev, "Can't create debugfs root\n");
+		return;
+	}
+
+	dwc->root = root;
+
+	file = debugfs_create_u8("maxspeed", 0644, root,
+				 &dwc->params.maximum_speed);
+	if (!file)
+		dev_dbg(&pci->dev, "Can't create maxspeed attribute\n");
+
+	file = debugfs_create_file("start", 0200, root, dwc, &dwc3_start_fops);
+	if (!file)
+		dev_dbg(&pci->dev, "Can't create debugfs start\n");
+}
+
+void dwc3_pci_debugfs_exit(struct dwc3_pci *dwc)
+{
+	debugfs_remove_recursive(dwc->root);
+}
diff --git a/drivers/usb/dwc3/pci.c b/drivers/usb/dwc3/pci.c
index c67a274232a5..fdb514679994 100644
--- a/drivers/usb/dwc3/pci.c
+++ b/drivers/usb/dwc3/pci.c
@@ -18,6 +18,8 @@
 #include <linux/gpio/consumer.h>
 #include <linux/acpi.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
 
 #include "dwc3-pci.h"
 
@@ -322,6 +324,8 @@ static int dwc3_pci_probe(struct pci_dev *pci,
 		goto err;
 	}
 
+	spin_lock_init(&dwc->lock);
+
 	dev_set_name(dev, "dwc3-pci.%02x:%02x.%d", pci->bus->number,
 		     PCI_SLOT(pci->devfn), PCI_FUNC(pci->devfn));
 
@@ -329,9 +333,13 @@ static int dwc3_pci_probe(struct pci_dev *pci,
 	if (ret)
 		goto err;
 
+	dwc3_pci_debugfs_init(dwc);
+
+#ifndef CONFIG_USB_DWC3_PCI_DEBUGFS
 	ret = dwc3_pci_add_platform_device(dwc);
 	if (ret)
 		goto err;
+#endif
 
 	device_init_wakeup(dev, true);
 	pci_set_drvdata(pci, dwc);
@@ -353,10 +361,13 @@ static void dwc3_pci_remove(struct pci_dev *pci)
 #ifdef CONFIG_PM
 	cancel_work_sync(&dwc->wakeup_work);
 #endif
+	dwc3_pci_debugfs_exit(dwc);
 	device_init_wakeup(&pci->dev, false);
 	pm_runtime_get(&pci->dev);
 	kfree(dwc->properties);
-	platform_device_unregister(dwc->dwc3);
+
+	if (dwc->dwc3)
+		platform_device_unregister(dwc->dwc3);
 }
 
 static const struct pci_device_id dwc3_pci_id_table[] = {
-- 
2.11.0

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