All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
To: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>,
	Rob Herring <robh@kernel.org>,
	Bjorn Helgaas <bhelgaas@google.com>,
	Kishon Vijay Abraham I <kishon@ti.com>
Cc: linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org,
	Masami Hiramatsu <masami.hiramatsu@linaro.org>,
	Jassi Brar <jaswinder.singh@linaro.org>,
	Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Subject: [PATCH v2 2/3] PCI: endpoint: Add endpoint restart management
Date: Mon, 25 Jan 2021 00:09:36 +0900	[thread overview]
Message-ID: <1611500977-24816-3-git-send-email-hayashi.kunihiko@socionext.com> (raw)
In-Reply-To: <1611500977-24816-1-git-send-email-hayashi.kunihiko@socionext.com>

Add new functions to manage recovery of configuration parameters and
restart the controller when asserting bus-reset from root-complex (RC).

This feature is only available if bus-reset (PERST#) line is physically
routed between RC and endpoint and the signal from RC affects endpoint.
This feature works as follows.

- This adds a polling thread, that polls and detects the bus-reset signal,
  and recovers configuration parameters for endpoint. The polling period
  is fixed at EPC_RESTART_POLL_PERIOD_MS.

- After the endpoint controller starts and the user sets configuration
  parameters using sysfs or function drivers, once RC asserts bus-reset
  and endpoint can receive it, the endpoint controller will also reset
  and initialize configuration parameters.

- If the thread detects bus-reset signal, the thread stops the controller,
  unbinds it, quickly binds it and restart it. The configuration
  paremters are restored to the user's values.

Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
 drivers/pci/endpoint/Kconfig           |   9 +++
 drivers/pci/endpoint/Makefile          |   1 +
 drivers/pci/endpoint/pci-epc-restart.c | 114 +++++++++++++++++++++++++++++++++
 include/linux/pci-epc.h                |  15 +++++
 4 files changed, 139 insertions(+)
 create mode 100644 drivers/pci/endpoint/pci-epc-restart.c

diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig
index 17bbdc9..016c82a 100644
--- a/drivers/pci/endpoint/Kconfig
+++ b/drivers/pci/endpoint/Kconfig
@@ -28,6 +28,15 @@ config PCI_ENDPOINT_CONFIGFS
 	   configure the endpoint function and used to bind the
 	   function with a endpoint controller.
 
+config PCI_ENDPOINT_RESTART
+	bool "PCI Endpoint Restart Management Support"
+	depends on PCI_ENDPOINT
+	help
+	   Enable restart management functions, which detects bus-reset
+	   from root complex, and recover endpoint configuration.
+	   This is only available if bus-reset line is physically routed
+	   between root complex and endpoint.
+
 source "drivers/pci/endpoint/functions/Kconfig"
 
 endmenu
diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile
index 95b2fe4..7301aea 100644
--- a/drivers/pci/endpoint/Makefile
+++ b/drivers/pci/endpoint/Makefile
@@ -4,5 +4,6 @@
 #
 
 obj-$(CONFIG_PCI_ENDPOINT_CONFIGFS)	+= pci-ep-cfs.o
+obj-$(CONFIG_PCI_ENDPOINT_RESTART)	+= pci-epc-restart.o
 obj-$(CONFIG_PCI_ENDPOINT)		+= pci-epc-core.o pci-epf-core.o\
 					   pci-epc-mem.o functions/
diff --git a/drivers/pci/endpoint/pci-epc-restart.c b/drivers/pci/endpoint/pci-epc-restart.c
new file mode 100644
index 0000000..ab956be
--- /dev/null
+++ b/drivers/pci/endpoint/pci-epc-restart.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * PCI Endpoint Controller Restart Management
+ *
+ * Copyright (C) 2019-2020 Socionext Inc.
+ * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+
+#define EPC_RESTART_POLL_PERIOD_MS	80
+
+static int pci_epc_restart_thread(void *dev_id)
+{
+	struct pci_epc *epc = dev_id;
+	struct pci_epf *epf;
+	int ret = 0;
+
+	dev_info(&epc->dev, "[epc-restart] thread start\n");
+
+	while (!kthread_should_stop()) {
+		if (epc->restart_poll) {
+			/* call polling function */
+			ret = epc->restart_poll(epc->restart_poll_data);
+			if (!ret) {
+				msleep(EPC_RESTART_POLL_PERIOD_MS);
+				continue;
+			} else if (ret < 0) {
+				break;
+			}
+		} else {
+			/* wait for interrupt */
+			ret = wait_for_completion_interruptible(&epc->restart_comp);
+			if (ret <= 0)
+				break;
+		}
+
+		if (!pci_epc_is_started(epc))
+			continue;
+
+		/*
+		 * After stop linkup, call unbind() once and call bind() again.
+		 * to reload config parameters to the controller.
+		 */
+		pci_epc_stop(epc);
+		list_for_each_entry(epf, &epc->pci_epf, list) {
+			pci_epf_unbind(epf);
+			pci_epf_bind(epf);
+		}
+		pci_epc_start(epc);
+
+		dev_info(&epc->dev, "[epc-restart] assert\n");
+	}
+
+	dev_info(&epc->dev, "[epc-restart] thread exit\n");
+
+	return ret;
+}
+
+/**
+ * pci_epc_restart_init() - initialize epc-restart thread
+ * @epc: the EPC device
+ */
+int pci_epc_restart_init(struct pci_epc *epc)
+{
+	init_completion(&epc->restart_comp);
+
+	epc->restart_task = kthread_run(pci_epc_restart_thread, epc,
+				"pci-epc-restart");
+	if (IS_ERR(epc->restart_task))
+		return PTR_ERR(epc->restart_task);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pci_epc_restart_init);
+
+/**
+ * pci_epc_restart_cleanup() - clean up epc-restart thread
+ * @epc: the EPC device
+ */
+void pci_epc_restart_cleanup(struct pci_epc *epc)
+{
+	if (epc->restart_task)
+		kthread_stop(epc->restart_task);
+}
+EXPORT_SYMBOL_GPL(pci_epc_restart_cleanup);
+
+/**
+ * pci_epc_restart_notify() - notify to epc-restart thread
+ * @epc: the EPC device
+ */
+void pci_epc_restart_notify(struct pci_epc *epc)
+{
+	complete(&epc->restart_comp);
+}
+EXPORT_SYMBOL_GPL(pci_epc_restart_notify);
+
+/**
+ * pci_epc_restart_register_poll_func() - register polling method for restart thread
+ * @epc: the EPC device
+ * @func: polling function
+ * @data: data for polling function
+ */
+void pci_epc_restart_register_poll_func(struct pci_epc *epc, bool (*func)(void *),
+					void *data)
+{
+	epc->restart_poll = func;
+	epc->restart_poll_data = data;
+}
+EXPORT_SYMBOL_GPL(pci_epc_restart_register_poll_func);
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 5808952..45d2592 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -132,6 +132,10 @@ struct pci_epc_mem {
  * @function_num_map: bitmap to manage physical function number
  * @notifier: used to notify EPF of any EPC events (like linkup)
  * @started: true if this EPC is started
+ * @restart_task: pointer to task for restart thread
+ * @restart_comp: completion object for receiving reset interrupts from RC
+ * @restart_poll: function to poll reset detection from RC
+ * @restart_poll_data: an argument that restart_poll function gets
  */
 struct pci_epc {
 	struct device			dev;
@@ -147,6 +151,11 @@ struct pci_epc {
 	unsigned long			function_num_map;
 	struct atomic_notifier_head	notifier;
 	bool				started;
+	/* for epc-restart */
+	struct task_struct		*restart_task;
+	struct completion		restart_comp;
+	bool				(*restart_poll)(void *func);
+	void				*restart_poll_data;
 };
 
 /**
@@ -254,4 +263,10 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
 				     phys_addr_t *phys_addr, size_t size);
 void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
 			   void __iomem *virt_addr, size_t size);
+int pci_epc_restart_init(struct pci_epc *epc);
+void pci_epc_restart_cleanup(struct pci_epc *epc);
+void pci_epc_restart_notify(struct pci_epc *epc);
+void pci_epc_restart_register_poll_func(struct pci_epc *epc,
+					bool (*func)(void *), void *data);
+
 #endif /* __LINUX_PCI_EPC_H */
-- 
2.7.4


WARNING: multiple messages have this Message-ID (diff)
From: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
To: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>,
	Rob Herring <robh@kernel.org>,
	Bjorn Helgaas <bhelgaas@google.com>,
	Kishon Vijay Abraham I <kishon@ti.com>
Cc: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>,
	Masami Hiramatsu <masami.hiramatsu@linaro.org>,
	linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
	Jassi Brar <jaswinder.singh@linaro.org>,
	linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 2/3] PCI: endpoint: Add endpoint restart management
Date: Mon, 25 Jan 2021 00:09:36 +0900	[thread overview]
Message-ID: <1611500977-24816-3-git-send-email-hayashi.kunihiko@socionext.com> (raw)
In-Reply-To: <1611500977-24816-1-git-send-email-hayashi.kunihiko@socionext.com>

Add new functions to manage recovery of configuration parameters and
restart the controller when asserting bus-reset from root-complex (RC).

This feature is only available if bus-reset (PERST#) line is physically
routed between RC and endpoint and the signal from RC affects endpoint.
This feature works as follows.

- This adds a polling thread, that polls and detects the bus-reset signal,
  and recovers configuration parameters for endpoint. The polling period
  is fixed at EPC_RESTART_POLL_PERIOD_MS.

- After the endpoint controller starts and the user sets configuration
  parameters using sysfs or function drivers, once RC asserts bus-reset
  and endpoint can receive it, the endpoint controller will also reset
  and initialize configuration parameters.

- If the thread detects bus-reset signal, the thread stops the controller,
  unbinds it, quickly binds it and restart it. The configuration
  paremters are restored to the user's values.

Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
 drivers/pci/endpoint/Kconfig           |   9 +++
 drivers/pci/endpoint/Makefile          |   1 +
 drivers/pci/endpoint/pci-epc-restart.c | 114 +++++++++++++++++++++++++++++++++
 include/linux/pci-epc.h                |  15 +++++
 4 files changed, 139 insertions(+)
 create mode 100644 drivers/pci/endpoint/pci-epc-restart.c

diff --git a/drivers/pci/endpoint/Kconfig b/drivers/pci/endpoint/Kconfig
index 17bbdc9..016c82a 100644
--- a/drivers/pci/endpoint/Kconfig
+++ b/drivers/pci/endpoint/Kconfig
@@ -28,6 +28,15 @@ config PCI_ENDPOINT_CONFIGFS
 	   configure the endpoint function and used to bind the
 	   function with a endpoint controller.
 
+config PCI_ENDPOINT_RESTART
+	bool "PCI Endpoint Restart Management Support"
+	depends on PCI_ENDPOINT
+	help
+	   Enable restart management functions, which detects bus-reset
+	   from root complex, and recover endpoint configuration.
+	   This is only available if bus-reset line is physically routed
+	   between root complex and endpoint.
+
 source "drivers/pci/endpoint/functions/Kconfig"
 
 endmenu
diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile
index 95b2fe4..7301aea 100644
--- a/drivers/pci/endpoint/Makefile
+++ b/drivers/pci/endpoint/Makefile
@@ -4,5 +4,6 @@
 #
 
 obj-$(CONFIG_PCI_ENDPOINT_CONFIGFS)	+= pci-ep-cfs.o
+obj-$(CONFIG_PCI_ENDPOINT_RESTART)	+= pci-epc-restart.o
 obj-$(CONFIG_PCI_ENDPOINT)		+= pci-epc-core.o pci-epf-core.o\
 					   pci-epc-mem.o functions/
diff --git a/drivers/pci/endpoint/pci-epc-restart.c b/drivers/pci/endpoint/pci-epc-restart.c
new file mode 100644
index 0000000..ab956be
--- /dev/null
+++ b/drivers/pci/endpoint/pci-epc-restart.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * PCI Endpoint Controller Restart Management
+ *
+ * Copyright (C) 2019-2020 Socionext Inc.
+ * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+
+#define EPC_RESTART_POLL_PERIOD_MS	80
+
+static int pci_epc_restart_thread(void *dev_id)
+{
+	struct pci_epc *epc = dev_id;
+	struct pci_epf *epf;
+	int ret = 0;
+
+	dev_info(&epc->dev, "[epc-restart] thread start\n");
+
+	while (!kthread_should_stop()) {
+		if (epc->restart_poll) {
+			/* call polling function */
+			ret = epc->restart_poll(epc->restart_poll_data);
+			if (!ret) {
+				msleep(EPC_RESTART_POLL_PERIOD_MS);
+				continue;
+			} else if (ret < 0) {
+				break;
+			}
+		} else {
+			/* wait for interrupt */
+			ret = wait_for_completion_interruptible(&epc->restart_comp);
+			if (ret <= 0)
+				break;
+		}
+
+		if (!pci_epc_is_started(epc))
+			continue;
+
+		/*
+		 * After stop linkup, call unbind() once and call bind() again.
+		 * to reload config parameters to the controller.
+		 */
+		pci_epc_stop(epc);
+		list_for_each_entry(epf, &epc->pci_epf, list) {
+			pci_epf_unbind(epf);
+			pci_epf_bind(epf);
+		}
+		pci_epc_start(epc);
+
+		dev_info(&epc->dev, "[epc-restart] assert\n");
+	}
+
+	dev_info(&epc->dev, "[epc-restart] thread exit\n");
+
+	return ret;
+}
+
+/**
+ * pci_epc_restart_init() - initialize epc-restart thread
+ * @epc: the EPC device
+ */
+int pci_epc_restart_init(struct pci_epc *epc)
+{
+	init_completion(&epc->restart_comp);
+
+	epc->restart_task = kthread_run(pci_epc_restart_thread, epc,
+				"pci-epc-restart");
+	if (IS_ERR(epc->restart_task))
+		return PTR_ERR(epc->restart_task);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pci_epc_restart_init);
+
+/**
+ * pci_epc_restart_cleanup() - clean up epc-restart thread
+ * @epc: the EPC device
+ */
+void pci_epc_restart_cleanup(struct pci_epc *epc)
+{
+	if (epc->restart_task)
+		kthread_stop(epc->restart_task);
+}
+EXPORT_SYMBOL_GPL(pci_epc_restart_cleanup);
+
+/**
+ * pci_epc_restart_notify() - notify to epc-restart thread
+ * @epc: the EPC device
+ */
+void pci_epc_restart_notify(struct pci_epc *epc)
+{
+	complete(&epc->restart_comp);
+}
+EXPORT_SYMBOL_GPL(pci_epc_restart_notify);
+
+/**
+ * pci_epc_restart_register_poll_func() - register polling method for restart thread
+ * @epc: the EPC device
+ * @func: polling function
+ * @data: data for polling function
+ */
+void pci_epc_restart_register_poll_func(struct pci_epc *epc, bool (*func)(void *),
+					void *data)
+{
+	epc->restart_poll = func;
+	epc->restart_poll_data = data;
+}
+EXPORT_SYMBOL_GPL(pci_epc_restart_register_poll_func);
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 5808952..45d2592 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -132,6 +132,10 @@ struct pci_epc_mem {
  * @function_num_map: bitmap to manage physical function number
  * @notifier: used to notify EPF of any EPC events (like linkup)
  * @started: true if this EPC is started
+ * @restart_task: pointer to task for restart thread
+ * @restart_comp: completion object for receiving reset interrupts from RC
+ * @restart_poll: function to poll reset detection from RC
+ * @restart_poll_data: an argument that restart_poll function gets
  */
 struct pci_epc {
 	struct device			dev;
@@ -147,6 +151,11 @@ struct pci_epc {
 	unsigned long			function_num_map;
 	struct atomic_notifier_head	notifier;
 	bool				started;
+	/* for epc-restart */
+	struct task_struct		*restart_task;
+	struct completion		restart_comp;
+	bool				(*restart_poll)(void *func);
+	void				*restart_poll_data;
 };
 
 /**
@@ -254,4 +263,10 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
 				     phys_addr_t *phys_addr, size_t size);
 void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
 			   void __iomem *virt_addr, size_t size);
+int pci_epc_restart_init(struct pci_epc *epc);
+void pci_epc_restart_cleanup(struct pci_epc *epc);
+void pci_epc_restart_notify(struct pci_epc *epc);
+void pci_epc_restart_register_poll_func(struct pci_epc *epc,
+					bool (*func)(void *), void *data);
+
 #endif /* __LINUX_PCI_EPC_H */
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2021-01-24 15:12 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-24 15:09 [PATCH v2 0/3] PCI: endpoint: Add endpoint restart management support Kunihiko Hayashi
2021-01-24 15:09 ` Kunihiko Hayashi
2021-01-24 15:09 ` [PATCH v2 1/3] PCI: endpoint: Add 'started' to pci_epc to set whether the controller is started Kunihiko Hayashi
2021-01-24 15:09   ` Kunihiko Hayashi
2021-01-28 14:11   ` Kishon Vijay Abraham I
2021-01-28 14:11     ` Kishon Vijay Abraham I
2021-02-02 16:13     ` Kunihiko Hayashi
2021-02-02 16:13       ` Kunihiko Hayashi
2021-01-24 15:09 ` Kunihiko Hayashi [this message]
2021-01-24 15:09   ` [PATCH v2 2/3] PCI: endpoint: Add endpoint restart management Kunihiko Hayashi
2021-01-24 15:09 ` [PATCH v2 3/3] PCI: uniphier-ep: Add EPC restart management support Kunihiko Hayashi
2021-01-24 15:09   ` Kunihiko Hayashi
2021-01-28 14:29   ` Kishon Vijay Abraham I
2021-01-28 14:29     ` Kishon Vijay Abraham I
2021-02-02 16:13     ` Kunihiko Hayashi
2021-02-02 16:13       ` Kunihiko Hayashi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1611500977-24816-3-git-send-email-hayashi.kunihiko@socionext.com \
    --to=hayashi.kunihiko@socionext.com \
    --cc=bhelgaas@google.com \
    --cc=jaswinder.singh@linaro.org \
    --cc=kishon@ti.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=lorenzo.pieralisi@arm.com \
    --cc=masami.hiramatsu@linaro.org \
    --cc=robh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.