Skip to content

Commit 1cf362e

Browse files
kishonLorenzo Pieralisi
authored andcommitted
PCI: endpoint: Add support to add virtual function in endpoint core
Add support to add virtual function in endpoint core. The virtual function can only be associated with a physical function instead of a endpoint controller. Provide APIs to associate a virtual function with a physical function here. [[email protected]: PCI: endpoint: Fix missing unlock on error in pci_epf_add_vepf() - Reported-by: Hulk Robot <[email protected]>] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kishon Vijay Abraham I <[email protected]> Signed-off-by: Wei Yongjun <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]>
1 parent f00bfc6 commit 1cf362e

File tree

3 files changed

+113
-3
lines changed

3 files changed

+113
-3
lines changed

drivers/pci/endpoint/pci-epc-core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
548548
u32 func_no;
549549
int ret = 0;
550550

551-
if (IS_ERR_OR_NULL(epc))
551+
if (IS_ERR_OR_NULL(epc) || epf->is_vf)
552552
return -EINVAL;
553553

554554
if (type == PRIMARY_INTERFACE && epf->epc)

drivers/pci/endpoint/pci-epf-core.c

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,20 @@ EXPORT_SYMBOL_GPL(pci_epf_type_add_cfs);
6262
*/
6363
void pci_epf_unbind(struct pci_epf *epf)
6464
{
65+
struct pci_epf *epf_vf;
66+
6567
if (!epf->driver) {
6668
dev_WARN(&epf->dev, "epf device not bound to driver\n");
6769
return;
6870
}
6971

7072
mutex_lock(&epf->lock);
71-
epf->driver->ops->unbind(epf);
73+
list_for_each_entry(epf_vf, &epf->pci_vepf, list) {
74+
if (epf_vf->is_bound)
75+
epf_vf->driver->ops->unbind(epf_vf);
76+
}
77+
if (epf->is_bound)
78+
epf->driver->ops->unbind(epf);
7279
mutex_unlock(&epf->lock);
7380
module_put(epf->driver->owner);
7481
}
@@ -83,6 +90,7 @@ EXPORT_SYMBOL_GPL(pci_epf_unbind);
8390
*/
8491
int pci_epf_bind(struct pci_epf *epf)
8592
{
93+
struct pci_epf *epf_vf;
8694
int ret;
8795

8896
if (!epf->driver) {
@@ -94,13 +102,97 @@ int pci_epf_bind(struct pci_epf *epf)
94102
return -EAGAIN;
95103

96104
mutex_lock(&epf->lock);
105+
list_for_each_entry(epf_vf, &epf->pci_vepf, list) {
106+
epf_vf->func_no = epf->func_no;
107+
epf_vf->epc = epf->epc;
108+
epf_vf->sec_epc = epf->sec_epc;
109+
ret = epf_vf->driver->ops->bind(epf_vf);
110+
if (ret)
111+
goto ret;
112+
epf_vf->is_bound = true;
113+
}
114+
97115
ret = epf->driver->ops->bind(epf);
116+
if (ret)
117+
goto ret;
118+
epf->is_bound = true;
119+
120+
mutex_unlock(&epf->lock);
121+
return 0;
122+
123+
ret:
98124
mutex_unlock(&epf->lock);
125+
pci_epf_unbind(epf);
99126

100127
return ret;
101128
}
102129
EXPORT_SYMBOL_GPL(pci_epf_bind);
103130

131+
/**
132+
* pci_epf_add_vepf() - associate virtual EP function to physical EP function
133+
* @epf_pf: the physical EP function to which the virtual EP function should be
134+
* associated
135+
* @epf_vf: the virtual EP function to be added
136+
*
137+
* A physical endpoint function can be associated with multiple virtual
138+
* endpoint functions. Invoke pci_epf_add_epf() to add a virtual PCI endpoint
139+
* function to a physical PCI endpoint function.
140+
*/
141+
int pci_epf_add_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
142+
{
143+
u32 vfunc_no;
144+
145+
if (IS_ERR_OR_NULL(epf_pf) || IS_ERR_OR_NULL(epf_vf))
146+
return -EINVAL;
147+
148+
if (epf_pf->epc || epf_vf->epc || epf_vf->epf_pf)
149+
return -EBUSY;
150+
151+
if (epf_pf->sec_epc || epf_vf->sec_epc)
152+
return -EBUSY;
153+
154+
mutex_lock(&epf_pf->lock);
155+
vfunc_no = find_first_zero_bit(&epf_pf->vfunction_num_map,
156+
BITS_PER_LONG);
157+
if (vfunc_no >= BITS_PER_LONG) {
158+
mutex_unlock(&epf_pf->lock);
159+
return -EINVAL;
160+
}
161+
162+
set_bit(vfunc_no, &epf_pf->vfunction_num_map);
163+
epf_vf->vfunc_no = vfunc_no;
164+
165+
epf_vf->epf_pf = epf_pf;
166+
epf_vf->is_vf = true;
167+
168+
list_add_tail(&epf_vf->list, &epf_pf->pci_vepf);
169+
mutex_unlock(&epf_pf->lock);
170+
171+
return 0;
172+
}
173+
EXPORT_SYMBOL_GPL(pci_epf_add_vepf);
174+
175+
/**
176+
* pci_epf_remove_vepf() - remove virtual EP function from physical EP function
177+
* @epf_pf: the physical EP function from which the virtual EP function should
178+
* be removed
179+
* @epf_vf: the virtual EP function to be removed
180+
*
181+
* Invoke to remove a virtual endpoint function from the physcial endpoint
182+
* function.
183+
*/
184+
void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
185+
{
186+
if (IS_ERR_OR_NULL(epf_pf) || IS_ERR_OR_NULL(epf_vf))
187+
return;
188+
189+
mutex_lock(&epf_pf->lock);
190+
clear_bit(epf_vf->vfunc_no, &epf_pf->vfunction_num_map);
191+
list_del(&epf_vf->list);
192+
mutex_unlock(&epf_pf->lock);
193+
}
194+
EXPORT_SYMBOL_GPL(pci_epf_remove_vepf);
195+
104196
/**
105197
* pci_epf_free_space() - free the allocated PCI EPF register space
106198
* @epf: the EPF device from whom to free the memory
@@ -317,6 +409,10 @@ struct pci_epf *pci_epf_create(const char *name)
317409
return ERR_PTR(-ENOMEM);
318410
}
319411

412+
/* VFs are numbered starting with 1. So set BIT(0) by default */
413+
epf->vfunction_num_map = 1;
414+
INIT_LIST_HEAD(&epf->pci_vepf);
415+
320416
dev = &epf->dev;
321417
device_initialize(dev);
322418
dev->bus = &pci_epf_bus_type;

include/linux/pci-epf.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,10 @@ struct pci_epf_bar {
121121
* @bar: represents the BAR of EPF device
122122
* @msi_interrupts: number of MSI interrupts required by this function
123123
* @msix_interrupts: number of MSI-X interrupts required by this function
124-
* @func_no: unique function number within this endpoint device
124+
* @func_no: unique (physical) function number within this endpoint device
125+
* @vfunc_no: unique virtual function number within a physical function
125126
* @epc: the EPC device to which this EPF device is bound
127+
* @epf_pf: the physical EPF device to which this virtual EPF device is bound
126128
* @driver: the EPF driver to which this EPF device is bound
127129
* @list: to add pci_epf as a list of PCI endpoint functions to pci_epc
128130
* @nb: notifier block to notify EPF of any EPC events (like linkup)
@@ -133,6 +135,10 @@ struct pci_epf_bar {
133135
* @sec_epc_bar: represents the BAR of EPF device associated with secondary EPC
134136
* @sec_epc_func_no: unique (physical) function number within the secondary EPC
135137
* @group: configfs group associated with the EPF device
138+
* @is_bound: indicates if bind notification to function driver has been invoked
139+
* @is_vf: true - virtual function, false - physical function
140+
* @vfunction_num_map: bitmap to manage virtual function number
141+
* @pci_vepf: list of virtual endpoint functions associated with this function
136142
*/
137143
struct pci_epf {
138144
struct device dev;
@@ -142,8 +148,10 @@ struct pci_epf {
142148
u8 msi_interrupts;
143149
u16 msix_interrupts;
144150
u8 func_no;
151+
u8 vfunc_no;
145152

146153
struct pci_epc *epc;
154+
struct pci_epf *epf_pf;
147155
struct pci_epf_driver *driver;
148156
struct list_head list;
149157
struct notifier_block nb;
@@ -156,6 +164,10 @@ struct pci_epf {
156164
struct pci_epf_bar sec_epc_bar[6];
157165
u8 sec_epc_func_no;
158166
struct config_group *group;
167+
unsigned int is_bound;
168+
unsigned int is_vf;
169+
unsigned long vfunction_num_map;
170+
struct list_head pci_vepf;
159171
};
160172

161173
/**
@@ -199,4 +211,6 @@ int pci_epf_bind(struct pci_epf *epf);
199211
void pci_epf_unbind(struct pci_epf *epf);
200212
struct config_group *pci_epf_type_add_cfs(struct pci_epf *epf,
201213
struct config_group *group);
214+
int pci_epf_add_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf);
215+
void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf);
202216
#endif /* __LINUX_PCI_EPF_H */

0 commit comments

Comments
 (0)