diff options
Diffstat (limited to 'drivers/pci/endpoint/pci-ep-cfs.c')
-rw-r--r-- | drivers/pci/endpoint/pci-ep-cfs.c | 73 |
1 files changed, 55 insertions, 18 deletions
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c index 4b8ac0ac84d5..0ea64e24ed61 100644 --- a/drivers/pci/endpoint/pci-ep-cfs.c +++ b/drivers/pci/endpoint/pci-ep-cfs.c @@ -23,6 +23,7 @@ struct pci_epf_group { struct config_group group; struct config_group primary_epc_group; struct config_group secondary_epc_group; + struct config_group *type_group; struct delayed_work cfs_work; struct pci_epf *epf; int index; @@ -178,6 +179,9 @@ static ssize_t pci_epc_start_store(struct config_item *item, const char *page, if (kstrtobool(page, &start) < 0) return -EINVAL; + if (start == epc_group->start) + return -EALREADY; + if (!start) { pci_epc_stop(epc); epc_group->start = 0; @@ -502,33 +506,64 @@ static struct configfs_item_operations pci_epf_ops = { .release = pci_epf_release, }; -static struct config_group *pci_epf_type_make(struct config_group *group, - const char *name) +static const struct config_item_type pci_epf_type = { + .ct_item_ops = &pci_epf_ops, + .ct_attrs = pci_epf_attrs, + .ct_owner = THIS_MODULE, +}; + +/** + * pci_epf_type_add_cfs() - Help function drivers to expose function specific + * attributes in configfs + * @epf: the EPF device that has to be configured using configfs + * @group: the parent configfs group (corresponding to entries in + * pci_epf_device_id) + * + * Invoke to expose function specific attributes in configfs. + * + * Return: A pointer to a config_group structure or NULL if the function driver + * does not have anything to expose (attributes configured by user) or if + * the function driver does not implement the add_cfs() method. + * + * Returns an error pointer if this function is called for an unbound EPF device + * or if the EPF driver add_cfs() method fails. + */ +static struct config_group *pci_epf_type_add_cfs(struct pci_epf *epf, + struct config_group *group) { - struct pci_epf_group *epf_group = to_pci_epf_group(&group->cg_item); struct config_group *epf_type_group; - epf_type_group = pci_epf_type_add_cfs(epf_group->epf, group); + if (!epf->driver) { + dev_err(&epf->dev, "epf device not bound to driver\n"); + return ERR_PTR(-ENODEV); + } + + if (!epf->driver->ops->add_cfs) + return NULL; + + mutex_lock(&epf->lock); + epf_type_group = epf->driver->ops->add_cfs(epf, group); + mutex_unlock(&epf->lock); + return epf_type_group; } -static void pci_epf_type_drop(struct config_group *group, - struct config_item *item) +static void pci_ep_cfs_add_type_group(struct pci_epf_group *epf_group) { - config_item_put(item); -} + struct config_group *group; -static struct configfs_group_operations pci_epf_type_group_ops = { - .make_group = &pci_epf_type_make, - .drop_item = &pci_epf_type_drop, -}; + group = pci_epf_type_add_cfs(epf_group->epf, &epf_group->group); + if (!group) + return; -static const struct config_item_type pci_epf_type = { - .ct_group_ops = &pci_epf_type_group_ops, - .ct_item_ops = &pci_epf_ops, - .ct_attrs = pci_epf_attrs, - .ct_owner = THIS_MODULE, -}; + if (IS_ERR(group)) { + dev_err(&epf_group->epf->dev, + "failed to create epf type specific attributes\n"); + return; + } + + configfs_register_group(&epf_group->group, group); +} static void pci_epf_cfs_work(struct work_struct *work) { @@ -547,6 +582,8 @@ static void pci_epf_cfs_work(struct work_struct *work) pr_err("failed to create 'secondary' EPC interface\n"); return; } + + pci_ep_cfs_add_type_group(epf_group); } static struct config_group *pci_epf_make(struct config_group *group, |