[PATCH v6 03/23] PCI: endpoint: Introduce configfs entry for configuring EP functions

2017-04-05 Thread Kishon Vijay Abraham I
Introduce a new configfs entry to configure the EP function (like
configuring the standard configuration header entries) and to bind the EP
function with EP controller.

Signed-off-by: Kishon Vijay Abraham I 
Signed-off-by: Bjorn Helgaas 
---
 drivers/pci/endpoint/Kconfig  |   9 +
 drivers/pci/endpoint/Makefile |   1 +
 drivers/pci/endpoint/pci-ep-cfs.c | 509 ++
 include/linux/pci-ep-cfs.h|  41 +++
 4 files changed, 560 insertions(+)
 create mode 100644 drivers/pci/endpoint/pci-ep-cfs.c
 create mode 100644 include/linux/pci-ep-cfs.h

diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig
index a5442ace7077..c86bca9b7de3 100644
--- a/drivers/pci/endpoint/Kconfig
+++ b/drivers/pci/endpoint/Kconfig
@@ -17,4 +17,13 @@ config PCI_ENDPOINT
 
   If in doubt, say "N" to disable Endpoint support.
 
+config PCI_ENDPOINT_CONFIGFS
+   bool "PCI Endpoint Configfs Support"
+   depends on PCI_ENDPOINT
+   select CONFIGFS_FS
+   help
+  This will enable the configfs entry that can be used to
+  configure the endpoint function and used to bind the
+  function with a endpoint controller.
+
 endmenu
diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile
index dc1bc16491e6..7219d51bb401 100644
--- a/drivers/pci/endpoint/Makefile
+++ b/drivers/pci/endpoint/Makefile
@@ -2,5 +2,6 @@
 # Makefile for PCI Endpoint Support
 #
 
+obj-$(CONFIG_PCI_ENDPOINT_CONFIGFS)+= pci-ep-cfs.o
 obj-$(CONFIG_PCI_ENDPOINT) += pci-epc-core.o pci-epf-core.o\
   pci-epc-mem.o
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c 
b/drivers/pci/endpoint/pci-ep-cfs.c
new file mode 100644
index ..424fdd6ed1ca
--- /dev/null
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
@@ -0,0 +1,509 @@
+/**
+ * configfs to configure the PCI endpoint
+ *
+ * Copyright (C) 2017 Texas Instruments
+ * Author: Kishon Vijay Abraham I 
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+static struct config_group *functions_group;
+static struct config_group *controllers_group;
+
+struct pci_epf_group {
+   struct config_group group;
+   struct pci_epf *epf;
+};
+
+struct pci_epc_group {
+   struct config_group group;
+   struct pci_epc *epc;
+   bool start;
+   unsigned long function_num_map;
+};
+
+static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item)
+{
+   return container_of(to_config_group(item), struct pci_epf_group, group);
+}
+
+static inline struct pci_epc_group *to_pci_epc_group(struct config_item *item)
+{
+   return container_of(to_config_group(item), struct pci_epc_group, group);
+}
+
+static ssize_t pci_epc_start_store(struct config_item *item, const char *page,
+  size_t len)
+{
+   int ret;
+   bool start;
+   struct pci_epc *epc;
+   struct pci_epc_group *epc_group = to_pci_epc_group(item);
+
+   epc = epc_group->epc;
+
+   ret = kstrtobool(page, );
+   if (ret)
+   return ret;
+
+   if (!start) {
+   pci_epc_stop(epc);
+   return len;
+   }
+
+   ret = pci_epc_start(epc);
+   if (ret) {
+   dev_err(>dev, "failed to start endpoint controller\n");
+   return -EINVAL;
+   }
+
+   epc_group->start = start;
+
+   return len;
+}
+
+static ssize_t pci_epc_start_show(struct config_item *item, char *page)
+{
+   return sprintf(page, "%d\n",
+  to_pci_epc_group(item)->start);
+}
+
+CONFIGFS_ATTR(pci_epc_, start);
+
+static struct configfs_attribute *pci_epc_attrs[] = {
+   _epc_attr_start,
+   NULL,
+};
+
+static int pci_epc_epf_link(struct config_item *epc_item,
+   struct config_item *epf_item)
+{
+   int ret;
+   u32 func_no = 0;
+   struct pci_epc *epc;
+   struct pci_epf *epf;
+   struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
+   struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
+
+   epc = epc_group->epc;
+   epf = epf_group->epf;
+   ret = pci_epc_add_epf(epc, epf);
+   if (ret)
+   goto err_add_epf;
+
+   func_no = find_first_zero_bit(_group->function_num_map,
+ 

[PATCH v6 03/23] PCI: endpoint: Introduce configfs entry for configuring EP functions

2017-04-05 Thread Kishon Vijay Abraham I
Introduce a new configfs entry to configure the EP function (like
configuring the standard configuration header entries) and to bind the EP
function with EP controller.

Signed-off-by: Kishon Vijay Abraham I 
Signed-off-by: Bjorn Helgaas 
---
 drivers/pci/endpoint/Kconfig  |   9 +
 drivers/pci/endpoint/Makefile |   1 +
 drivers/pci/endpoint/pci-ep-cfs.c | 509 ++
 include/linux/pci-ep-cfs.h|  41 +++
 4 files changed, 560 insertions(+)
 create mode 100644 drivers/pci/endpoint/pci-ep-cfs.c
 create mode 100644 include/linux/pci-ep-cfs.h

diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig
index a5442ace7077..c86bca9b7de3 100644
--- a/drivers/pci/endpoint/Kconfig
+++ b/drivers/pci/endpoint/Kconfig
@@ -17,4 +17,13 @@ config PCI_ENDPOINT
 
   If in doubt, say "N" to disable Endpoint support.
 
+config PCI_ENDPOINT_CONFIGFS
+   bool "PCI Endpoint Configfs Support"
+   depends on PCI_ENDPOINT
+   select CONFIGFS_FS
+   help
+  This will enable the configfs entry that can be used to
+  configure the endpoint function and used to bind the
+  function with a endpoint controller.
+
 endmenu
diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile
index dc1bc16491e6..7219d51bb401 100644
--- a/drivers/pci/endpoint/Makefile
+++ b/drivers/pci/endpoint/Makefile
@@ -2,5 +2,6 @@
 # Makefile for PCI Endpoint Support
 #
 
+obj-$(CONFIG_PCI_ENDPOINT_CONFIGFS)+= pci-ep-cfs.o
 obj-$(CONFIG_PCI_ENDPOINT) += pci-epc-core.o pci-epf-core.o\
   pci-epc-mem.o
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c 
b/drivers/pci/endpoint/pci-ep-cfs.c
new file mode 100644
index ..424fdd6ed1ca
--- /dev/null
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
@@ -0,0 +1,509 @@
+/**
+ * configfs to configure the PCI endpoint
+ *
+ * Copyright (C) 2017 Texas Instruments
+ * Author: Kishon Vijay Abraham I 
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+static struct config_group *functions_group;
+static struct config_group *controllers_group;
+
+struct pci_epf_group {
+   struct config_group group;
+   struct pci_epf *epf;
+};
+
+struct pci_epc_group {
+   struct config_group group;
+   struct pci_epc *epc;
+   bool start;
+   unsigned long function_num_map;
+};
+
+static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item)
+{
+   return container_of(to_config_group(item), struct pci_epf_group, group);
+}
+
+static inline struct pci_epc_group *to_pci_epc_group(struct config_item *item)
+{
+   return container_of(to_config_group(item), struct pci_epc_group, group);
+}
+
+static ssize_t pci_epc_start_store(struct config_item *item, const char *page,
+  size_t len)
+{
+   int ret;
+   bool start;
+   struct pci_epc *epc;
+   struct pci_epc_group *epc_group = to_pci_epc_group(item);
+
+   epc = epc_group->epc;
+
+   ret = kstrtobool(page, );
+   if (ret)
+   return ret;
+
+   if (!start) {
+   pci_epc_stop(epc);
+   return len;
+   }
+
+   ret = pci_epc_start(epc);
+   if (ret) {
+   dev_err(>dev, "failed to start endpoint controller\n");
+   return -EINVAL;
+   }
+
+   epc_group->start = start;
+
+   return len;
+}
+
+static ssize_t pci_epc_start_show(struct config_item *item, char *page)
+{
+   return sprintf(page, "%d\n",
+  to_pci_epc_group(item)->start);
+}
+
+CONFIGFS_ATTR(pci_epc_, start);
+
+static struct configfs_attribute *pci_epc_attrs[] = {
+   _epc_attr_start,
+   NULL,
+};
+
+static int pci_epc_epf_link(struct config_item *epc_item,
+   struct config_item *epf_item)
+{
+   int ret;
+   u32 func_no = 0;
+   struct pci_epc *epc;
+   struct pci_epf *epf;
+   struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
+   struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
+
+   epc = epc_group->epc;
+   epf = epf_group->epf;
+   ret = pci_epc_add_epf(epc, epf);
+   if (ret)
+   goto err_add_epf;
+
+   func_no = find_first_zero_bit(_group->function_num_map,
+