PCI: endpoint: Assign function number for each PF in EPC core

The PCIe endpoint core relies on the drivers that invoke the
pci_epc_add_epf() API to allocate and assign a function number
to each physical function (PF). Since endpoint function device can
be created by multiple mechanisms (configfs, devicetree, etc..),
allowing each of these mechanisms to assign a function number
would result in mutliple endpoint function devices having the
same function number. In order to avoid this, let EPC core assign
a function number to the endpoint device.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
This commit is contained in:
Kishon Vijay Abraham I 2020-02-24 15:23:38 +05:30 committed by Lorenzo Pieralisi
parent 07301c9826
commit 2499ee84e0
3 changed files with 29 additions and 26 deletions

View File

@ -29,7 +29,6 @@ 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)
@ -89,37 +88,22 @@ static int pci_epc_epf_link(struct config_item *epc_item,
struct config_item *epf_item)
{
int ret;
u32 func_no = 0;
struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
struct pci_epc *epc = epc_group->epc;
struct pci_epf *epf = epf_group->epf;
func_no = find_first_zero_bit(&epc_group->function_num_map,
BITS_PER_LONG);
if (func_no >= BITS_PER_LONG)
return -EINVAL;
set_bit(func_no, &epc_group->function_num_map);
epf->func_no = func_no;
ret = pci_epc_add_epf(epc, epf);
if (ret)
goto err_add_epf;
return ret;
ret = pci_epf_bind(epf);
if (ret)
goto err_epf_bind;
if (ret) {
pci_epc_remove_epf(epc, epf);
return ret;
}
return 0;
err_epf_bind:
pci_epc_remove_epf(epc, epf);
err_add_epf:
clear_bit(func_no, &epc_group->function_num_map);
return ret;
}
static void pci_epc_epf_unlink(struct config_item *epc_item,
@ -134,7 +118,6 @@ static void pci_epc_epf_unlink(struct config_item *epc_item,
epc = epc_group->epc;
epf = epf_group->epf;
clear_bit(epf->func_no, &epc_group->function_num_map);
pci_epf_unbind(epf);
pci_epc_remove_epf(epc, epf);
}

View File

@ -471,22 +471,39 @@ EXPORT_SYMBOL_GPL(pci_epc_write_header);
*/
int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)
{
u32 func_no;
int ret = 0;
if (epf->epc)
return -EBUSY;
if (IS_ERR(epc))
return -EINVAL;
if (epf->func_no > epc->max_functions - 1)
return -EINVAL;
mutex_lock(&epc->lock);
func_no = find_first_zero_bit(&epc->function_num_map,
BITS_PER_LONG);
if (func_no >= BITS_PER_LONG) {
ret = -EINVAL;
goto ret;
}
if (func_no > epc->max_functions - 1) {
dev_err(&epc->dev, "Exceeding max supported Function Number\n");
ret = -EINVAL;
goto ret;
}
set_bit(func_no, &epc->function_num_map);
epf->func_no = func_no;
epf->epc = epc;
mutex_lock(&epc->lock);
list_add_tail(&epf->list, &epc->pci_epf);
ret:
mutex_unlock(&epc->lock);
return 0;
return ret;
}
EXPORT_SYMBOL_GPL(pci_epc_add_epf);
@ -503,6 +520,7 @@ void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf)
return;
mutex_lock(&epc->lock);
clear_bit(epf->func_no, &epc->function_num_map);
list_del(&epf->list);
epf->epc = NULL;
mutex_unlock(&epc->lock);

View File

@ -92,6 +92,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: mutex to protect pci_epc ops
* @function_num_map: bitmap to manage physical function number
* @notifier: used to notify EPF of any EPC events (like linkup)
*/
struct pci_epc {
@ -103,6 +104,7 @@ struct pci_epc {
struct config_group *group;
/* mutex to protect against concurrent access of EP controller */
struct mutex lock;
unsigned long function_num_map;
struct atomic_notifier_head notifier;
};