Introduce new APIs to register/unregister a BMC device instance for fpgahp driver. The fpgahp_bmc_device data structure represents a FPGA BMC device which has some specific callbacks for FPGA hotplug operations. The first one is available_images, which will return a list of available images for FPGA. The second one is the image_load, which will provide a reload trigger operation to BMC via secure update driver for Intel PAC N3000 Card. Signed-off-by: Tianfei Zhang <tianfei.zhang@xxxxxxxxx> --- drivers/pci/hotplug/fpgahp.c | 78 +++++++++++++++++++++++++++++ include/linux/fpga/fpgahp_manager.h | 38 ++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/drivers/pci/hotplug/fpgahp.c b/drivers/pci/hotplug/fpgahp.c index 71cee65383e2..79bae97a1d39 100644 --- a/drivers/pci/hotplug/fpgahp.c +++ b/drivers/pci/hotplug/fpgahp.c @@ -34,6 +34,84 @@ static void fpgahp_add_fhpc(struct fpgahp_controller *fhpc) mutex_unlock(&fhpc_lock); } +static struct fpgahp_bmc_device *fpgahp_find_bmc(struct device *bmc_device) +{ + struct fpgahp_bmc_device *bmc = NULL; + struct fpgahp_controller *fhpc; + + mutex_lock(&fhpc_lock); + + list_for_each_entry(fhpc, &fhpc_list, node) { + struct fpgahp_manager *mgr = &fhpc->mgr; + struct pci_dev *pcidev = mgr->priv; + + if (!mgr->registered) + continue; + + /* + * BMC device (like security dev) is a subordinate device under + * PCI device, so check if the parent device of BMC device recursively + */ + if (device_is_ancestor(&pcidev->dev, bmc_device)) { + bmc = &mgr->bmc; + break; + } + } + + mutex_unlock(&fhpc_lock); + + return bmc; +} + +/** + * fpgahp_bmc_device_register - register FPGA BMC device into fpgahp driver + * @ops: pointer to structure of fpgahp manager ops + * @dev: device struct of BMC device + * @priv: private data for FPGA device + * + * Return: pointer to struct fpgahp_manager pointer or ERR_PTR() + */ +struct fpgahp_bmc_device * +fpgahp_bmc_device_register(const struct fpgahp_bmc_ops *ops, + struct device *dev, void *priv) +{ + struct fpgahp_manager *mgr; + struct fpgahp_bmc_device *bmc; + + if (!ops) + return ERR_PTR(-EINVAL); + + bmc = fpgahp_find_bmc(dev); + if (!bmc) + return ERR_PTR(-EINVAL); + + mgr = to_fpgahp_mgr(bmc); + + mutex_lock(&mgr->lock); + bmc->priv = priv; + bmc->device = dev; + bmc->ops = ops; + bmc->registered = true; + mutex_unlock(&mgr->lock); + + return bmc; +} +EXPORT_SYMBOL_NS_GPL(fpgahp_bmc_device_register, FPGAHP); + +/** + * fpgahp_bmc_device_unregister - unregister FPGA BMC device from fpgahp driver + * @bmc: point to the fpgahp_bmc_device + */ +void fpgahp_bmc_device_unregister(struct fpgahp_bmc_device *bmc) +{ + struct fpgahp_manager *mgr = to_fpgahp_mgr(bmc); + + mutex_lock(&mgr->lock); + bmc->registered = false; + mutex_unlock(&mgr->lock); +} +EXPORT_SYMBOL_NS_GPL(fpgahp_bmc_device_unregister, FPGAHP); + static int fpgahp_init_controller(struct controller *ctrl, struct pcie_device *dev) { struct pci_dev *hotplug_bridge = dev->port; diff --git a/include/linux/fpga/fpgahp_manager.h b/include/linux/fpga/fpgahp_manager.h index 5e31877f03de..982fbc661f55 100644 --- a/include/linux/fpga/fpgahp_manager.h +++ b/include/linux/fpga/fpgahp_manager.h @@ -11,6 +11,33 @@ struct pci_dev; struct fpgahp_manager; +struct fpgahp_bmc_device; + +/** + * struct fpgahp_bmc_ops - fpga hotplug BMC specific operations + * @available_images: Required: available images for fpgahp trigger + * @image_trigger: Required: trigger the image reload on BMC + */ +struct fpgahp_bmc_ops { + ssize_t (*available_images)(struct fpgahp_bmc_device *bmc, char *buf); + int (*image_trigger)(struct fpgahp_bmc_device *bmc, const char *buf, + u32 *wait_time_msec); +}; + +/** + * struct fpgahp_bmc_device - represent a fpga hotplug BMC device + * + * @ops: ops of this fpgahp_bmc_device + * @priv: private data for fpgahp_bmc_device + * @device: device of BMC device + * @registered: register status + */ +struct fpgahp_bmc_device { + const struct fpgahp_bmc_ops *ops; + void *priv; + struct device *device; + bool registered; +}; /** * struct fpgahp_manager_ops - fpgahp manager specific operations @@ -43,6 +70,7 @@ enum fpgahp_manager_states { * @ops: ops of this fpgahp_manager * @state: the status of fpgahp_manager * @name: name of the fpgahp_manager + * @bmc: fpgahp BMC device * @registered: register status */ struct fpgahp_manager { @@ -51,12 +79,22 @@ struct fpgahp_manager { const struct fpgahp_manager_ops *ops; enum fpgahp_manager_states state; const char *name; + struct fpgahp_bmc_device bmc; bool registered; }; +static inline struct fpgahp_manager *to_fpgahp_mgr(struct fpgahp_bmc_device *bmc) +{ + return container_of(bmc, struct fpgahp_manager, bmc); +} + struct fpgahp_manager *fpgahp_register(struct pci_dev *hotplug_bridge, const char *name, const struct fpgahp_manager_ops *ops, void *priv); void fpgahp_unregister(struct fpgahp_manager *mgr); +struct fpgahp_bmc_device *fpgahp_bmc_device_register(const struct fpgahp_bmc_ops *ops, + struct device *dev, void *priv); +void fpgahp_bmc_device_unregister(struct fpgahp_bmc_device *bmc); + #endif -- 2.38.1