Commit 2499ee84 authored by Kishon Vijay Abraham I's avatar Kishon Vijay Abraham I Committed by Lorenzo Pieralisi
Browse files

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: default avatarKishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
parent 07301c98
Loading
Loading
Loading
Loading
+5 −22
Original line number Diff line number Diff line
@@ -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,39 +88,24 @@ 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;

	return 0;

err_epf_bind:
	if (ret) {
		pci_epc_remove_epf(epc, epf);

err_add_epf:
	clear_bit(func_no, &epc_group->function_num_map);

		return ret;
	}

	return 0;
}

static void pci_epc_epf_unlink(struct config_item *epc_item,
			       struct config_item *epf_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);
}
+22 −4
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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;
};