PCI: endpoint: Use notification chain mechanism to notify EPC events to EPF
authorKishon Vijay Abraham I <kishon@ti.com>
Mon, 24 Feb 2020 09:53:34 +0000 (15:23 +0530)
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Mon, 24 Feb 2020 10:07:06 +0000 (10:07 +0000)
Use atomic_notifier_call_chain() to notify EPC events like linkup to EPF
driver instead of using linkup ops in EPF driver. This is in preparation
for adding proper locking mechanism to EPF ops. This will also enable to
add more events (in addition to linkup) in the future.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tested-by: Vidya Sagar <vidyas@nvidia.com>
drivers/pci/endpoint/functions/pci-epf-test.c
drivers/pci/endpoint/pci-epc-core.c
drivers/pci/endpoint/pci-epf-core.c
include/linux/pci-epc.h
include/linux/pci-epf.h

index 5d74f81..bddff15 100644 (file)
@@ -360,12 +360,16 @@ reset_handler:
                           msecs_to_jiffies(1));
 }
 
-static void pci_epf_test_linkup(struct pci_epf *epf)
+static int pci_epf_test_notifier(struct notifier_block *nb, unsigned long val,
+                                void *data)
 {
+       struct pci_epf *epf = container_of(nb, struct pci_epf, nb);
        struct pci_epf_test *epf_test = epf_get_drvdata(epf);
 
        queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
                           msecs_to_jiffies(1));
+
+       return NOTIFY_OK;
 }
 
 static void pci_epf_test_unbind(struct pci_epf *epf)
@@ -546,8 +550,12 @@ static int pci_epf_test_bind(struct pci_epf *epf)
                }
        }
 
-       if (!linkup_notifier)
+       if (linkup_notifier) {
+               epf->nb.notifier_call = pci_epf_test_notifier;
+               pci_epc_register_notifier(epc, &epf->nb);
+       } else {
                queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
+       }
 
        return 0;
 }
@@ -580,7 +588,6 @@ static int pci_epf_test_probe(struct pci_epf *epf)
 static struct pci_epf_ops ops = {
        .unbind = pci_epf_test_unbind,
        .bind   = pci_epf_test_bind,
-       .linkup = pci_epf_test_linkup,
 };
 
 static struct pci_epf_driver test_driver = {
index 2091508..2f64365 100644 (file)
@@ -539,16 +539,10 @@ EXPORT_SYMBOL_GPL(pci_epc_remove_epf);
  */
 void pci_epc_linkup(struct pci_epc *epc)
 {
-       unsigned long flags;
-       struct pci_epf *epf;
-
        if (!epc || IS_ERR(epc))
                return;
 
-       spin_lock_irqsave(&epc->lock, flags);
-       list_for_each_entry(epf, &epc->pci_epf, list)
-               pci_epf_linkup(epf);
-       spin_unlock_irqrestore(&epc->lock, flags);
+       atomic_notifier_call_chain(&epc->notifier, 0, NULL);
 }
 EXPORT_SYMBOL_GPL(pci_epc_linkup);
 
@@ -612,6 +606,7 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
 
        spin_lock_init(&epc->lock);
        INIT_LIST_HEAD(&epc->pci_epf);
+       ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier);
 
        device_initialize(&epc->dev);
        epc->dev.class = pci_epc_class;
index fb1306d..93f28c6 100644 (file)
@@ -21,26 +21,6 @@ static struct bus_type pci_epf_bus_type;
 static const struct device_type pci_epf_type;
 
 /**
- * pci_epf_linkup() - Notify the function driver that EPC device has
- *                   established a connection with the Root Complex.
- * @epf: the EPF device bound to the EPC device which has established
- *      the connection with the host
- *
- * Invoke to notify the function driver that EPC device has established
- * a connection with the Root Complex.
- */
-void pci_epf_linkup(struct pci_epf *epf)
-{
-       if (!epf->driver) {
-               dev_WARN(&epf->dev, "epf device not bound to driver\n");
-               return;
-       }
-
-       epf->driver->ops->linkup(epf);
-}
-EXPORT_SYMBOL_GPL(pci_epf_linkup);
-
-/**
  * pci_epf_unbind() - Notify the function driver that the binding between the
  *                   EPF device and EPC device has been lost
  * @epf: the EPF device which has lost the binding with the EPC device
@@ -214,7 +194,7 @@ int __pci_epf_register_driver(struct pci_epf_driver *driver,
        if (!driver->ops)
                return -EINVAL;
 
-       if (!driver->ops->bind || !driver->ops->unbind || !driver->ops->linkup)
+       if (!driver->ops->bind || !driver->ops->unbind)
                return -EINVAL;
 
        driver->driver.bus = &pci_epf_bus_type;
index 56f1846..36644cc 100644 (file)
@@ -89,6 +89,7 @@ struct pci_epc_mem {
  * @max_functions: max number of functions that can be configured in this EPC
  * @group: configfs group representing the PCI EPC device
  * @lock: spinlock to protect pci_epc ops
+ * @notifier: used to notify EPF of any EPC events (like linkup)
  */
 struct pci_epc {
        struct device                   dev;
@@ -99,6 +100,7 @@ struct pci_epc {
        struct config_group             *group;
        /* spinlock to protect against concurrent access of EP controller */
        spinlock_t                      lock;
+       struct atomic_notifier_head     notifier;
 };
 
 /**
@@ -141,6 +143,12 @@ static inline void *epc_get_drvdata(struct pci_epc *epc)
        return dev_get_drvdata(&epc->dev);
 }
 
+static inline int
+pci_epc_register_notifier(struct pci_epc *epc, struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&epc->notifier, nb);
+}
+
 struct pci_epc *
 __devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
                      struct module *owner);
index 2d6f075..4993f7f 100644 (file)
@@ -55,13 +55,10 @@ struct pci_epf_header {
  * @bind: ops to perform when a EPC device has been bound to EPF device
  * @unbind: ops to perform when a binding has been lost between a EPC device
  *         and EPF device
- * @linkup: ops to perform when the EPC device has established a connection with
- *         a host system
  */
 struct pci_epf_ops {
        int     (*bind)(struct pci_epf *epf);
        void    (*unbind)(struct pci_epf *epf);
-       void    (*linkup)(struct pci_epf *epf);
 };
 
 /**
@@ -112,6 +109,7 @@ struct pci_epf_bar {
  * @epc: the EPC device to which this EPF device is bound
  * @driver: the EPF driver to which this EPF device is bound
  * @list: to add pci_epf as a list of PCI endpoint functions to pci_epc
+ * @nb: notifier block to notify EPF of any EPC events (like linkup)
  */
 struct pci_epf {
        struct device           dev;
@@ -125,6 +123,7 @@ struct pci_epf {
        struct pci_epc          *epc;
        struct pci_epf_driver   *driver;
        struct list_head        list;
+       struct notifier_block   nb;
 };
 
 #define to_pci_epf(epf_dev) container_of((epf_dev), struct pci_epf, dev)
@@ -154,5 +153,4 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
 void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar);
 int pci_epf_bind(struct pci_epf *epf);
 void pci_epf_unbind(struct pci_epf *epf);
-void pci_epf_linkup(struct pci_epf *epf);
 #endif /* __LINUX_PCI_EPF_H */