fpga: dfl: pci: enable SRIOV support.

This patch enables the standard sriov support. It allows user to
enable SRIOV (and VFs), then user could pass through accelerators
(VFs) into virtual machine or use VFs directly in host.

Signed-off-by: Zhang Yi Z <yi.z.zhang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@intel.com>
Signed-off-by: Wu Hao <hao.wu@intel.com>
Acked-by: Alan Tull <atull@kernel.org>
Acked-by: Moritz Fischer <mdf@kernel.org>
Signed-off-by: Moritz Fischer <mdf@kernel.org>
Link: https://lore.kernel.org/r/1564914022-3710-3-git-send-email-hao.wu@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Wu Hao 2019-08-04 18:20:12 +08:00 committed by Greg Kroah-Hartman
parent 69bb18ddfc
commit bdd4f30795
3 changed files with 120 additions and 1 deletions

View File

@ -223,8 +223,43 @@ int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid)
return ret;
}
static int cci_pci_sriov_configure(struct pci_dev *pcidev, int num_vfs)
{
struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
struct dfl_fpga_cdev *cdev = drvdata->cdev;
int ret = 0;
if (!num_vfs) {
/*
* disable SRIOV and then put released ports back to default
* PF access mode.
*/
pci_disable_sriov(pcidev);
dfl_fpga_cdev_config_ports_pf(cdev);
} else {
/*
* before enable SRIOV, put released ports into VF access mode
* first of all.
*/
ret = dfl_fpga_cdev_config_ports_vf(cdev, num_vfs);
if (ret)
return ret;
ret = pci_enable_sriov(pcidev, num_vfs);
if (ret)
dfl_fpga_cdev_config_ports_pf(cdev);
}
return ret;
}
static void cci_pci_remove(struct pci_dev *pcidev)
{
if (dev_is_pf(&pcidev->dev))
cci_pci_sriov_configure(pcidev, 0);
cci_remove_feature_devs(pcidev);
pci_disable_pcie_error_reporting(pcidev);
}
@ -234,6 +269,7 @@ static struct pci_driver cci_pci_driver = {
.id_table = cci_pcie_id_tbl,
.probe = cci_pci_probe,
.remove = cci_pci_remove,
.sriov_configure = cci_pci_sriov_configure,
};
module_pci_driver(cci_pci_driver);

View File

@ -1131,6 +1131,88 @@ int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id)
}
EXPORT_SYMBOL_GPL(dfl_fpga_cdev_assign_port);
static void config_port_access_mode(struct device *fme_dev, int port_id,
bool is_vf)
{
void __iomem *base;
u64 v;
base = dfl_get_feature_ioaddr_by_id(fme_dev, FME_FEATURE_ID_HEADER);
v = readq(base + FME_HDR_PORT_OFST(port_id));
v &= ~FME_PORT_OFST_ACC_CTRL;
v |= FIELD_PREP(FME_PORT_OFST_ACC_CTRL,
is_vf ? FME_PORT_OFST_ACC_VF : FME_PORT_OFST_ACC_PF);
writeq(v, base + FME_HDR_PORT_OFST(port_id));
}
#define config_port_vf_mode(dev, id) config_port_access_mode(dev, id, true)
#define config_port_pf_mode(dev, id) config_port_access_mode(dev, id, false)
/**
* dfl_fpga_cdev_config_ports_pf - configure ports to PF access mode
*
* @cdev: parent container device.
*
* This function is needed in sriov configuration routine. It could be used to
* configure the all released ports from VF access mode to PF.
*/
void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev)
{
struct dfl_feature_platform_data *pdata;
mutex_lock(&cdev->lock);
list_for_each_entry(pdata, &cdev->port_dev_list, node) {
if (device_is_registered(&pdata->dev->dev))
continue;
config_port_pf_mode(cdev->fme_dev, pdata->id);
}
mutex_unlock(&cdev->lock);
}
EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_pf);
/**
* dfl_fpga_cdev_config_ports_vf - configure ports to VF access mode
*
* @cdev: parent container device.
* @num_vfs: VF device number.
*
* This function is needed in sriov configuration routine. It could be used to
* configure the released ports from PF access mode to VF.
*
* Return: 0 on success, negative error code otherwise.
*/
int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs)
{
struct dfl_feature_platform_data *pdata;
int ret = 0;
mutex_lock(&cdev->lock);
/*
* can't turn multiple ports into 1 VF device, only 1 port for 1 VF
* device, so if released port number doesn't match VF device number,
* then reject the request with -EINVAL error code.
*/
if (cdev->released_port_num != num_vfs) {
ret = -EINVAL;
goto done;
}
list_for_each_entry(pdata, &cdev->port_dev_list, node) {
if (device_is_registered(&pdata->dev->dev))
continue;
config_port_vf_mode(cdev->fme_dev, pdata->id);
}
done:
mutex_unlock(&cdev->lock);
return ret;
}
EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_vf);
static void __exit dfl_fpga_exit(void)
{
dfl_chardev_uinit();

View File

@ -416,5 +416,6 @@ dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data,
int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id);
int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id);
void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev);
int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vf);
#endif /* __FPGA_DFL_H */