/** * pci_epf_unbind() - Notify the function driver that the binding between the * EPF device and EPC device has been lost * @epf: the EPF device which has lost the binding with the EPC device * * Invoke to notify the function driver that the binding between the EPF device * and EPC device has been lost.
*/ void pci_epf_unbind(struct pci_epf *epf)
{ struct pci_epf *epf_vf;
if (!epf->driver) {
dev_WARN(&epf->dev, "epf device not bound to driver\n"); return;
}
mutex_lock(&epf->lock);
list_for_each_entry(epf_vf, &epf->pci_vepf, list) { if (epf_vf->is_bound)
epf_vf->driver->ops->unbind(epf_vf);
} if (epf->is_bound)
epf->driver->ops->unbind(epf);
mutex_unlock(&epf->lock);
module_put(epf->driver->owner);
}
EXPORT_SYMBOL_GPL(pci_epf_unbind);
/** * pci_epf_bind() - Notify the function driver that the EPF device has been * bound to a EPC device * @epf: the EPF device which has been bound to the EPC device * * Invoke to notify the function driver that it has been bound to a EPC device
*/ int pci_epf_bind(struct pci_epf *epf)
{ struct device *dev = &epf->dev; struct pci_epf *epf_vf;
u8 func_no, vfunc_no; struct pci_epc *epc; int ret;
if (!epf->driver) {
dev_WARN(dev, "epf device not bound to driver\n"); return -EINVAL;
}
if (!try_module_get(epf->driver->owner)) return -EAGAIN;
if (vfunc_no < 1) {
dev_err(dev, "Invalid virtual function number\n");
ret = -EINVAL; goto ret;
}
epc = epf->epc;
func_no = epf->func_no; if (!IS_ERR_OR_NULL(epc)) { if (!epc->max_vfs) {
dev_err(dev, "No support for virt function\n");
ret = -EINVAL; goto ret;
}
if (vfunc_no > epc->max_vfs[func_no]) {
dev_err(dev, "PF%d: Exceeds max vfunc number\n",
func_no);
ret = -EINVAL; goto ret;
}
}
epc = epf->sec_epc;
func_no = epf->sec_epc_func_no; if (!IS_ERR_OR_NULL(epc)) { if (!epc->max_vfs) {
dev_err(dev, "No support for virt function\n");
ret = -EINVAL; goto ret;
}
if (vfunc_no > epc->max_vfs[func_no]) {
dev_err(dev, "PF%d: Exceeds max vfunc number\n",
func_no);
ret = -EINVAL; goto ret;
}
}
/** * pci_epf_add_vepf() - associate virtual EP function to physical EP function * @epf_pf: the physical EP function to which the virtual EP function should be * associated * @epf_vf: the virtual EP function to be added * * A physical endpoint function can be associated with multiple virtual * endpoint functions. Invoke pci_epf_add_epf() to add a virtual PCI endpoint * function to a physical PCI endpoint function.
*/ int pci_epf_add_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
{
u32 vfunc_no;
if (IS_ERR_OR_NULL(epf_pf) || IS_ERR_OR_NULL(epf_vf)) return -EINVAL;
if (epf_pf->epc || epf_vf->epc || epf_vf->epf_pf) return -EBUSY;
if (epf_pf->sec_epc || epf_vf->sec_epc) return -EBUSY;
/** * pci_epf_remove_vepf() - remove virtual EP function from physical EP function * @epf_pf: the physical EP function from which the virtual EP function should * be removed * @epf_vf: the virtual EP function to be removed * * Invoke to remove a virtual endpoint function from the physical endpoint * function.
*/ void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
{ if (IS_ERR_OR_NULL(epf_pf) || IS_ERR_OR_NULL(epf_vf)) return;
/** * pci_epf_free_space() - free the allocated PCI EPF register space * @epf: the EPF device from whom to free the memory * @addr: the virtual address of the PCI EPF register space * @bar: the BAR number corresponding to the register space * @type: Identifies if the allocated space is for primary EPC or secondary EPC * * Invoke to free the allocated PCI EPF register space.
*/ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar, enum pci_epc_interface_type type)
{ struct device *dev; struct pci_epf_bar *epf_bar; struct pci_epc *epc;
/** * pci_epf_alloc_space() - allocate memory for the PCI EPF register space * @epf: the EPF device to whom allocate the memory * @size: the size of the memory that has to be allocated * @bar: the BAR number corresponding to the allocated register space * @epc_features: the features provided by the EPC specific to this EPF * @type: Identifies if the allocation is for primary EPC or secondary EPC * * Invoke to allocate memory for the PCI EPF register space. * Flag PCI_BASE_ADDRESS_MEM_TYPE_64 will automatically get set if the BAR * can only be a 64-bit BAR, or if the requested size is larger than 2 GB.
*/ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar, conststruct pci_epc_features *epc_features, enum pci_epc_interface_type type)
{
u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
size_t aligned_size, align = epc_features->align; struct pci_epf_bar *epf_bar;
dma_addr_t phys_addr; struct pci_epc *epc; struct device *dev; void *space;
if (size < 128)
size = 128;
/* According to PCIe base spec, min size for a resizable BAR is 1 MB. */ if (epc_features->bar[bar].type == BAR_RESIZABLE && size < SZ_1M)
size = SZ_1M;
if (epc_features->bar[bar].type == BAR_FIXED && bar_fixed_size) { if (size > bar_fixed_size) {
dev_err(&epf->dev, "requested BAR size is larger than fixed size\n"); return NULL;
}
size = bar_fixed_size;
} else { /* BAR size must be power of two */
size = roundup_pow_of_two(size);
}
/* * Allocate enough memory to accommodate the iATU alignment * requirement. In most cases, this will be the same as .size but * it might be different if, for example, the fixed size of a BAR * is smaller than align.
*/
aligned_size = align ? ALIGN(size, align) : size;
dev = epc->dev.parent;
space = dma_alloc_coherent(dev, aligned_size, &phys_addr, GFP_KERNEL); if (!space) {
dev_err(dev, "failed to allocate mem space\n"); return NULL;
}
/** * pci_epf_unregister_driver() - unregister the PCI EPF driver * @driver: the PCI EPF driver that has to be unregistered * * Invoke to unregister the PCI EPF driver.
*/ void pci_epf_unregister_driver(struct pci_epf_driver *driver)
{
pci_epf_remove_cfs(driver);
driver_unregister(&driver->driver);
}
EXPORT_SYMBOL_GPL(pci_epf_unregister_driver);
if (!IS_ENABLED(CONFIG_PCI_ENDPOINT_CONFIGFS)) return 0;
INIT_LIST_HEAD(&driver->epf_group);
id = driver->id_table; while (id->name[0]) {
group = pci_ep_cfs_add_epf_group(id->name); if (IS_ERR(group)) {
pci_epf_remove_cfs(driver); return PTR_ERR(group);
}
/** * __pci_epf_register_driver() - register a new PCI EPF driver * @driver: structure representing PCI EPF driver * @owner: the owner of the module that registers the PCI EPF driver * * Invoke to register a new PCI EPF driver.
*/ int __pci_epf_register_driver(struct pci_epf_driver *driver, struct module *owner)
{ int ret;
if (!driver->ops) return -EINVAL;
if (!driver->ops->bind || !driver->ops->unbind) return -EINVAL;
/** * pci_epf_destroy() - destroy the created PCI EPF device * @epf: the PCI EPF device that has to be destroyed. * * Invoke to destroy the PCI EPF device created by invoking pci_epf_create().
*/ void pci_epf_destroy(struct pci_epf *epf)
{
device_unregister(&epf->dev);
}
EXPORT_SYMBOL_GPL(pci_epf_destroy);
/** * pci_epf_create() - create a new PCI EPF device * @name: the name of the PCI EPF device. This name will be used to bind the * EPF device to a EPF driver * * Invoke to create a new PCI EPF device by providing the name of the function * device.
*/ struct pci_epf *pci_epf_create(constchar *name)
{ int ret; struct pci_epf *epf; struct device *dev; int len;
epf = kzalloc(sizeof(*epf), GFP_KERNEL); if (!epf) return ERR_PTR(-ENOMEM);
len = strchrnul(name, '.') - name;
epf->name = kstrndup(name, len, GFP_KERNEL); if (!epf->name) {
kfree(epf); return ERR_PTR(-ENOMEM);
}
/* VFs are numbered starting with 1. So set BIT(0) by default */
epf->vfunction_num_map = 1;
INIT_LIST_HEAD(&epf->pci_vepf);
ret = dev_set_name(dev, "%s", name); if (ret) {
put_device(dev); return ERR_PTR(ret);
}
ret = device_add(dev); if (ret) {
put_device(dev); return ERR_PTR(ret);
}
return epf;
}
EXPORT_SYMBOL_GPL(pci_epf_create);
/** * pci_epf_align_inbound_addr() - Align the given address based on the BAR * alignment requirement * @epf: the EPF device * @addr: inbound address to be aligned * @bar: the BAR number corresponding to the given addr * @base: base address matching the @bar alignment requirement * @off: offset to be added to the @base address * * Helper function to align input @addr based on BAR's alignment requirement. * The aligned base address and offset are returned via @base and @off. * * NOTE: The pci_epf_alloc_space() function already accounts for alignment. * This API is primarily intended for use with other memory regions not * allocated by pci_epf_alloc_space(), such as peripheral register spaces or * the message address of a platform MSI controller. * * Return: 0 on success, errno otherwise.
*/ int pci_epf_align_inbound_addr(struct pci_epf *epf, enum pci_barno bar,
u64 addr, dma_addr_t *base, size_t *off)
{ /* * Most EP controllers require the BAR start address to be aligned to * the BAR size, because they mask off the lower bits. * * Alignment to BAR size also works for controllers that support * unaligned addresses.
*/
u64 align = epf->bar[bar].size;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.