mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
Merge branch 'char-misc-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc into fpga-dfl-for-5.4
This commit is contained in:
commit
af9ca4b0bd
1971 changed files with 22326 additions and 14084 deletions
|
|
@ -40,6 +40,7 @@ config ALTERA_PR_IP_CORE_PLAT
|
|||
config FPGA_MGR_ALTERA_PS_SPI
|
||||
tristate "Altera FPGA Passive Serial over SPI"
|
||||
depends on SPI
|
||||
select BITREVERSE
|
||||
help
|
||||
FPGA manager driver support for Altera Arria/Cyclone/Stratix
|
||||
using the passive serial interface over SPI.
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ static int altera_ps_write_complete(struct fpga_manager *mgr,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (!IS_ERR(conf->confd)) {
|
||||
if (conf->confd) {
|
||||
if (!gpiod_get_raw_value_cansleep(conf->confd)) {
|
||||
dev_err(&mgr->dev, "CONF_DONE is inactive!\n");
|
||||
return -EIO;
|
||||
|
|
@ -289,10 +289,13 @@ static int altera_ps_probe(struct spi_device *spi)
|
|||
return PTR_ERR(conf->status);
|
||||
}
|
||||
|
||||
conf->confd = devm_gpiod_get(&spi->dev, "confd", GPIOD_IN);
|
||||
conf->confd = devm_gpiod_get_optional(&spi->dev, "confd", GPIOD_IN);
|
||||
if (IS_ERR(conf->confd)) {
|
||||
dev_warn(&spi->dev, "Not using confd gpio: %ld\n",
|
||||
PTR_ERR(conf->confd));
|
||||
dev_err(&spi->dev, "Failed to get confd gpio: %ld\n",
|
||||
PTR_ERR(conf->confd));
|
||||
return PTR_ERR(conf->confd);
|
||||
} else if (!conf->confd) {
|
||||
dev_warn(&spi->dev, "Not using confd gpio");
|
||||
}
|
||||
|
||||
/* Register manager with unique name */
|
||||
|
|
|
|||
|
|
@ -141,10 +141,148 @@ id_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
}
|
||||
static DEVICE_ATTR_RO(id);
|
||||
|
||||
static const struct attribute *port_hdr_attrs[] = {
|
||||
static ssize_t
|
||||
ltr_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
|
||||
void __iomem *base;
|
||||
u64 v;
|
||||
|
||||
base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
|
||||
|
||||
mutex_lock(&pdata->lock);
|
||||
v = readq(base + PORT_HDR_CTRL);
|
||||
mutex_unlock(&pdata->lock);
|
||||
|
||||
return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ltr_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
|
||||
void __iomem *base;
|
||||
bool ltr;
|
||||
u64 v;
|
||||
|
||||
if (kstrtobool(buf, <r))
|
||||
return -EINVAL;
|
||||
|
||||
base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
|
||||
|
||||
mutex_lock(&pdata->lock);
|
||||
v = readq(base + PORT_HDR_CTRL);
|
||||
v &= ~PORT_CTRL_LATENCY;
|
||||
v |= FIELD_PREP(PORT_CTRL_LATENCY, ltr ? 1 : 0);
|
||||
writeq(v, base + PORT_HDR_CTRL);
|
||||
mutex_unlock(&pdata->lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(ltr);
|
||||
|
||||
static ssize_t
|
||||
ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
|
||||
void __iomem *base;
|
||||
u64 v;
|
||||
|
||||
base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
|
||||
|
||||
mutex_lock(&pdata->lock);
|
||||
v = readq(base + PORT_HDR_STS);
|
||||
mutex_unlock(&pdata->lock);
|
||||
|
||||
return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ap1_event_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
|
||||
void __iomem *base;
|
||||
bool clear;
|
||||
|
||||
if (kstrtobool(buf, &clear) || !clear)
|
||||
return -EINVAL;
|
||||
|
||||
base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
|
||||
|
||||
mutex_lock(&pdata->lock);
|
||||
writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS);
|
||||
mutex_unlock(&pdata->lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(ap1_event);
|
||||
|
||||
static ssize_t
|
||||
ap2_event_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
|
||||
void __iomem *base;
|
||||
u64 v;
|
||||
|
||||
base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
|
||||
|
||||
mutex_lock(&pdata->lock);
|
||||
v = readq(base + PORT_HDR_STS);
|
||||
mutex_unlock(&pdata->lock);
|
||||
|
||||
return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ap2_event_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
|
||||
void __iomem *base;
|
||||
bool clear;
|
||||
|
||||
if (kstrtobool(buf, &clear) || !clear)
|
||||
return -EINVAL;
|
||||
|
||||
base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
|
||||
|
||||
mutex_lock(&pdata->lock);
|
||||
writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS);
|
||||
mutex_unlock(&pdata->lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(ap2_event);
|
||||
|
||||
static ssize_t
|
||||
power_state_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
|
||||
void __iomem *base;
|
||||
u64 v;
|
||||
|
||||
base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
|
||||
|
||||
mutex_lock(&pdata->lock);
|
||||
v = readq(base + PORT_HDR_STS);
|
||||
mutex_unlock(&pdata->lock);
|
||||
|
||||
return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v));
|
||||
}
|
||||
static DEVICE_ATTR_RO(power_state);
|
||||
|
||||
static struct attribute *port_hdr_attrs[] = {
|
||||
&dev_attr_id.attr,
|
||||
&dev_attr_ltr.attr,
|
||||
&dev_attr_ap1_event.attr,
|
||||
&dev_attr_ap2_event.attr,
|
||||
&dev_attr_power_state.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(port_hdr);
|
||||
|
||||
static int port_hdr_init(struct platform_device *pdev,
|
||||
struct dfl_feature *feature)
|
||||
|
|
@ -153,7 +291,7 @@ static int port_hdr_init(struct platform_device *pdev,
|
|||
|
||||
port_reset(pdev);
|
||||
|
||||
return sysfs_create_files(&pdev->dev.kobj, port_hdr_attrs);
|
||||
return device_add_groups(&pdev->dev, port_hdr_groups);
|
||||
}
|
||||
|
||||
static void port_hdr_uinit(struct platform_device *pdev,
|
||||
|
|
@ -161,7 +299,7 @@ static void port_hdr_uinit(struct platform_device *pdev,
|
|||
{
|
||||
dev_dbg(&pdev->dev, "PORT HDR UInit.\n");
|
||||
|
||||
sysfs_remove_files(&pdev->dev.kobj, port_hdr_attrs);
|
||||
device_remove_groups(&pdev->dev, port_hdr_groups);
|
||||
}
|
||||
|
||||
static long
|
||||
|
|
@ -185,6 +323,11 @@ port_hdr_ioctl(struct platform_device *pdev, struct dfl_feature *feature,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct dfl_feature_id port_hdr_id_table[] = {
|
||||
{.id = PORT_FEATURE_ID_HEADER,},
|
||||
{0,}
|
||||
};
|
||||
|
||||
static const struct dfl_feature_ops port_hdr_ops = {
|
||||
.init = port_hdr_init,
|
||||
.uinit = port_hdr_uinit,
|
||||
|
|
@ -214,10 +357,11 @@ afu_id_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
}
|
||||
static DEVICE_ATTR_RO(afu_id);
|
||||
|
||||
static const struct attribute *port_afu_attrs[] = {
|
||||
static struct attribute *port_afu_attrs[] = {
|
||||
&dev_attr_afu_id.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(port_afu);
|
||||
|
||||
static int port_afu_init(struct platform_device *pdev,
|
||||
struct dfl_feature *feature)
|
||||
|
|
@ -234,7 +378,7 @@ static int port_afu_init(struct platform_device *pdev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_create_files(&pdev->dev.kobj, port_afu_attrs);
|
||||
return device_add_groups(&pdev->dev, port_afu_groups);
|
||||
}
|
||||
|
||||
static void port_afu_uinit(struct platform_device *pdev,
|
||||
|
|
@ -242,9 +386,14 @@ static void port_afu_uinit(struct platform_device *pdev,
|
|||
{
|
||||
dev_dbg(&pdev->dev, "PORT AFU UInit.\n");
|
||||
|
||||
sysfs_remove_files(&pdev->dev.kobj, port_afu_attrs);
|
||||
device_remove_groups(&pdev->dev, port_afu_groups);
|
||||
}
|
||||
|
||||
static const struct dfl_feature_id port_afu_id_table[] = {
|
||||
{.id = PORT_FEATURE_ID_AFU,},
|
||||
{0,}
|
||||
};
|
||||
|
||||
static const struct dfl_feature_ops port_afu_ops = {
|
||||
.init = port_afu_init,
|
||||
.uinit = port_afu_uinit,
|
||||
|
|
@ -252,11 +401,11 @@ static const struct dfl_feature_ops port_afu_ops = {
|
|||
|
||||
static struct dfl_feature_driver port_feature_drvs[] = {
|
||||
{
|
||||
.id = PORT_FEATURE_ID_HEADER,
|
||||
.id_table = port_hdr_id_table,
|
||||
.ops = &port_hdr_ops,
|
||||
},
|
||||
{
|
||||
.id = PORT_FEATURE_ID_AFU,
|
||||
.id_table = port_afu_id_table,
|
||||
.ops = &port_afu_ops,
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/fpga-dfl.h>
|
||||
|
||||
#include "dfl.h"
|
||||
|
|
@ -72,12 +73,61 @@ static ssize_t bitstream_metadata_show(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR_RO(bitstream_metadata);
|
||||
|
||||
static const struct attribute *fme_hdr_attrs[] = {
|
||||
static ssize_t cache_size_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
void __iomem *base;
|
||||
u64 v;
|
||||
|
||||
base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
|
||||
|
||||
v = readq(base + FME_HDR_CAP);
|
||||
|
||||
return sprintf(buf, "%u\n",
|
||||
(unsigned int)FIELD_GET(FME_CAP_CACHE_SIZE, v));
|
||||
}
|
||||
static DEVICE_ATTR_RO(cache_size);
|
||||
|
||||
static ssize_t fabric_version_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
void __iomem *base;
|
||||
u64 v;
|
||||
|
||||
base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
|
||||
|
||||
v = readq(base + FME_HDR_CAP);
|
||||
|
||||
return sprintf(buf, "%u\n",
|
||||
(unsigned int)FIELD_GET(FME_CAP_FABRIC_VERID, v));
|
||||
}
|
||||
static DEVICE_ATTR_RO(fabric_version);
|
||||
|
||||
static ssize_t socket_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
void __iomem *base;
|
||||
u64 v;
|
||||
|
||||
base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
|
||||
|
||||
v = readq(base + FME_HDR_CAP);
|
||||
|
||||
return sprintf(buf, "%u\n",
|
||||
(unsigned int)FIELD_GET(FME_CAP_SOCKET_ID, v));
|
||||
}
|
||||
static DEVICE_ATTR_RO(socket_id);
|
||||
|
||||
static struct attribute *fme_hdr_attrs[] = {
|
||||
&dev_attr_ports_num.attr,
|
||||
&dev_attr_bitstream_id.attr,
|
||||
&dev_attr_bitstream_metadata.attr,
|
||||
&dev_attr_cache_size.attr,
|
||||
&dev_attr_fabric_version.attr,
|
||||
&dev_attr_socket_id.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(fme_hdr);
|
||||
|
||||
static int fme_hdr_init(struct platform_device *pdev,
|
||||
struct dfl_feature *feature)
|
||||
|
|
@ -89,7 +139,7 @@ static int fme_hdr_init(struct platform_device *pdev,
|
|||
dev_dbg(&pdev->dev, "FME cap %llx.\n",
|
||||
(unsigned long long)readq(base + FME_HDR_CAP));
|
||||
|
||||
ret = sysfs_create_files(&pdev->dev.kobj, fme_hdr_attrs);
|
||||
ret = device_add_groups(&pdev->dev, fme_hdr_groups);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -100,22 +150,68 @@ static void fme_hdr_uinit(struct platform_device *pdev,
|
|||
struct dfl_feature *feature)
|
||||
{
|
||||
dev_dbg(&pdev->dev, "FME HDR UInit.\n");
|
||||
sysfs_remove_files(&pdev->dev.kobj, fme_hdr_attrs);
|
||||
device_remove_groups(&pdev->dev, fme_hdr_groups);
|
||||
}
|
||||
|
||||
static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct dfl_fpga_cdev *cdev = pdata->dfl_cdev;
|
||||
int port_id;
|
||||
|
||||
if (get_user(port_id, (int __user *)arg))
|
||||
return -EFAULT;
|
||||
|
||||
return dfl_fpga_cdev_release_port(cdev, port_id);
|
||||
}
|
||||
|
||||
static long fme_hdr_ioctl_assign_port(struct dfl_feature_platform_data *pdata,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct dfl_fpga_cdev *cdev = pdata->dfl_cdev;
|
||||
int port_id;
|
||||
|
||||
if (get_user(port_id, (int __user *)arg))
|
||||
return -EFAULT;
|
||||
|
||||
return dfl_fpga_cdev_assign_port(cdev, port_id);
|
||||
}
|
||||
|
||||
static long fme_hdr_ioctl(struct platform_device *pdev,
|
||||
struct dfl_feature *feature,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
switch (cmd) {
|
||||
case DFL_FPGA_FME_PORT_RELEASE:
|
||||
return fme_hdr_ioctl_release_port(pdata, arg);
|
||||
case DFL_FPGA_FME_PORT_ASSIGN:
|
||||
return fme_hdr_ioctl_assign_port(pdata, arg);
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static const struct dfl_feature_id fme_hdr_id_table[] = {
|
||||
{.id = FME_FEATURE_ID_HEADER,},
|
||||
{0,}
|
||||
};
|
||||
|
||||
static const struct dfl_feature_ops fme_hdr_ops = {
|
||||
.init = fme_hdr_init,
|
||||
.uinit = fme_hdr_uinit,
|
||||
.ioctl = fme_hdr_ioctl,
|
||||
};
|
||||
|
||||
static struct dfl_feature_driver fme_feature_drvs[] = {
|
||||
{
|
||||
.id = FME_FEATURE_ID_HEADER,
|
||||
.id_table = fme_hdr_id_table,
|
||||
.ops = &fme_hdr_ops,
|
||||
},
|
||||
{
|
||||
.id = FME_FEATURE_ID_PR_MGMT,
|
||||
.ops = &pr_mgmt_ops,
|
||||
.id_table = fme_pr_mgmt_id_table,
|
||||
.ops = &fme_pr_mgmt_ops,
|
||||
},
|
||||
{
|
||||
.ops = NULL,
|
||||
|
|
|
|||
|
|
@ -470,7 +470,12 @@ static long fme_pr_ioctl(struct platform_device *pdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
const struct dfl_feature_ops pr_mgmt_ops = {
|
||||
const struct dfl_feature_id fme_pr_mgmt_id_table[] = {
|
||||
{.id = FME_FEATURE_ID_PR_MGMT,},
|
||||
{0}
|
||||
};
|
||||
|
||||
const struct dfl_feature_ops fme_pr_mgmt_ops = {
|
||||
.init = pr_mgmt_init,
|
||||
.uinit = pr_mgmt_uinit,
|
||||
.ioctl = fme_pr_ioctl,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ struct dfl_fme {
|
|||
struct dfl_feature_platform_data *pdata;
|
||||
};
|
||||
|
||||
extern const struct dfl_feature_ops pr_mgmt_ops;
|
||||
extern const struct dfl_feature_ops fme_pr_mgmt_ops;
|
||||
extern const struct dfl_feature_id fme_pr_mgmt_id_table[];
|
||||
|
||||
#endif /* __DFL_FME_H */
|
||||
|
|
|
|||
|
|
@ -223,8 +223,43 @@ disable_error_report_exit:
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -231,16 +231,20 @@ EXPORT_SYMBOL_GPL(dfl_fpga_port_ops_del);
|
|||
*/
|
||||
int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id)
|
||||
{
|
||||
struct dfl_fpga_port_ops *port_ops = dfl_fpga_port_ops_get(pdev);
|
||||
int port_id;
|
||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct dfl_fpga_port_ops *port_ops;
|
||||
|
||||
if (pdata->id != FEATURE_DEV_ID_UNUSED)
|
||||
return pdata->id == *(int *)pport_id;
|
||||
|
||||
port_ops = dfl_fpga_port_ops_get(pdev);
|
||||
if (!port_ops || !port_ops->get_id)
|
||||
return 0;
|
||||
|
||||
port_id = port_ops->get_id(pdev);
|
||||
pdata->id = port_ops->get_id(pdev);
|
||||
dfl_fpga_port_ops_put(port_ops);
|
||||
|
||||
return port_id == *(int *)pport_id;
|
||||
return pdata->id == *(int *)pport_id;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id);
|
||||
|
||||
|
|
@ -255,7 +259,8 @@ void dfl_fpga_dev_feature_uinit(struct platform_device *pdev)
|
|||
|
||||
dfl_fpga_dev_for_each_feature(pdata, feature)
|
||||
if (feature->ops) {
|
||||
feature->ops->uinit(pdev, feature);
|
||||
if (feature->ops->uinit)
|
||||
feature->ops->uinit(pdev, feature);
|
||||
feature->ops = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -277,6 +282,21 @@ static int dfl_feature_instance_init(struct platform_device *pdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool dfl_feature_drv_match(struct dfl_feature *feature,
|
||||
struct dfl_feature_driver *driver)
|
||||
{
|
||||
const struct dfl_feature_id *ids = driver->id_table;
|
||||
|
||||
if (ids) {
|
||||
while (ids->id) {
|
||||
if (ids->id == feature->id)
|
||||
return true;
|
||||
ids++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfl_fpga_dev_feature_init - init for sub features of dfl feature device
|
||||
* @pdev: feature device.
|
||||
|
|
@ -297,8 +317,7 @@ int dfl_fpga_dev_feature_init(struct platform_device *pdev,
|
|||
|
||||
while (drv->ops) {
|
||||
dfl_fpga_dev_for_each_feature(pdata, feature) {
|
||||
/* match feature and drv using id */
|
||||
if (feature->id == drv->id) {
|
||||
if (dfl_feature_drv_match(feature, drv)) {
|
||||
ret = dfl_feature_instance_init(pdev, pdata,
|
||||
feature, drv);
|
||||
if (ret)
|
||||
|
|
@ -474,6 +493,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
|
|||
pdata->dev = fdev;
|
||||
pdata->num = binfo->feature_num;
|
||||
pdata->dfl_cdev = binfo->cdev;
|
||||
pdata->id = FEATURE_DEV_ID_UNUSED;
|
||||
mutex_init(&pdata->lock);
|
||||
lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type],
|
||||
dfl_pdata_key_strings[type]);
|
||||
|
|
@ -973,25 +993,27 @@ void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev)
|
|||
{
|
||||
struct dfl_feature_platform_data *pdata, *ptmp;
|
||||
|
||||
remove_feature_devs(cdev);
|
||||
|
||||
mutex_lock(&cdev->lock);
|
||||
if (cdev->fme_dev) {
|
||||
/* the fme should be unregistered. */
|
||||
WARN_ON(device_is_registered(cdev->fme_dev));
|
||||
if (cdev->fme_dev)
|
||||
put_device(cdev->fme_dev);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) {
|
||||
struct platform_device *port_dev = pdata->dev;
|
||||
|
||||
/* the port should be unregistered. */
|
||||
WARN_ON(device_is_registered(&port_dev->dev));
|
||||
/* remove released ports */
|
||||
if (!device_is_registered(&port_dev->dev)) {
|
||||
dfl_id_free(feature_dev_id_type(port_dev),
|
||||
port_dev->id);
|
||||
platform_device_put(port_dev);
|
||||
}
|
||||
|
||||
list_del(&pdata->node);
|
||||
put_device(&port_dev->dev);
|
||||
}
|
||||
mutex_unlock(&cdev->lock);
|
||||
|
||||
remove_feature_devs(cdev);
|
||||
|
||||
fpga_region_unregister(cdev->region);
|
||||
devm_kfree(cdev->parent, cdev);
|
||||
}
|
||||
|
|
@ -1042,6 +1064,170 @@ static int __init dfl_fpga_init(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfl_fpga_cdev_release_port - release a port platform device
|
||||
*
|
||||
* @cdev: parent container device.
|
||||
* @port_id: id of the port platform device.
|
||||
*
|
||||
* This function allows user to release a port platform device. This is a
|
||||
* mandatory step before turn a port from PF into VF for SRIOV support.
|
||||
*
|
||||
* Return: 0 on success, negative error code otherwise.
|
||||
*/
|
||||
int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id)
|
||||
{
|
||||
struct platform_device *port_pdev;
|
||||
int ret = -ENODEV;
|
||||
|
||||
mutex_lock(&cdev->lock);
|
||||
port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id,
|
||||
dfl_fpga_check_port_id);
|
||||
if (!port_pdev)
|
||||
goto unlock_exit;
|
||||
|
||||
if (!device_is_registered(&port_pdev->dev)) {
|
||||
ret = -EBUSY;
|
||||
goto put_dev_exit;
|
||||
}
|
||||
|
||||
ret = dfl_feature_dev_use_begin(dev_get_platdata(&port_pdev->dev));
|
||||
if (ret)
|
||||
goto put_dev_exit;
|
||||
|
||||
platform_device_del(port_pdev);
|
||||
cdev->released_port_num++;
|
||||
put_dev_exit:
|
||||
put_device(&port_pdev->dev);
|
||||
unlock_exit:
|
||||
mutex_unlock(&cdev->lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dfl_fpga_cdev_release_port);
|
||||
|
||||
/**
|
||||
* dfl_fpga_cdev_assign_port - assign a port platform device back
|
||||
*
|
||||
* @cdev: parent container device.
|
||||
* @port_id: id of the port platform device.
|
||||
*
|
||||
* This function allows user to assign a port platform device back. This is
|
||||
* a mandatory step after disable SRIOV support.
|
||||
*
|
||||
* Return: 0 on success, negative error code otherwise.
|
||||
*/
|
||||
int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id)
|
||||
{
|
||||
struct platform_device *port_pdev;
|
||||
int ret = -ENODEV;
|
||||
|
||||
mutex_lock(&cdev->lock);
|
||||
port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id,
|
||||
dfl_fpga_check_port_id);
|
||||
if (!port_pdev)
|
||||
goto unlock_exit;
|
||||
|
||||
if (device_is_registered(&port_pdev->dev)) {
|
||||
ret = -EBUSY;
|
||||
goto put_dev_exit;
|
||||
}
|
||||
|
||||
ret = platform_device_add(port_pdev);
|
||||
if (ret)
|
||||
goto put_dev_exit;
|
||||
|
||||
dfl_feature_dev_use_end(dev_get_platdata(&port_pdev->dev));
|
||||
cdev->released_port_num--;
|
||||
put_dev_exit:
|
||||
put_device(&port_pdev->dev);
|
||||
unlock_exit:
|
||||
mutex_unlock(&cdev->lock);
|
||||
return ret;
|
||||
}
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@
|
|||
/* plus one for fme device */
|
||||
#define MAX_DFL_FEATURE_DEV_NUM (MAX_DFL_FPGA_PORT_NUM + 1)
|
||||
|
||||
/* Reserved 0x0 for Header Group Register and 0xff for AFU */
|
||||
#define FEATURE_ID_FIU_HEADER 0x0
|
||||
/* Reserved 0xfe for Header Group Register and 0xff for AFU */
|
||||
#define FEATURE_ID_FIU_HEADER 0xfe
|
||||
#define FEATURE_ID_AFU 0xff
|
||||
|
||||
#define FME_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER
|
||||
|
|
@ -119,6 +119,7 @@
|
|||
#define PORT_HDR_NEXT_AFU NEXT_AFU
|
||||
#define PORT_HDR_CAP 0x30
|
||||
#define PORT_HDR_CTRL 0x38
|
||||
#define PORT_HDR_STS 0x40
|
||||
|
||||
/* Port Capability Register Bitfield */
|
||||
#define PORT_CAP_PORT_NUM GENMASK_ULL(1, 0) /* ID of this port */
|
||||
|
|
@ -130,6 +131,16 @@
|
|||
/* Latency tolerance reporting. '1' >= 40us, '0' < 40us.*/
|
||||
#define PORT_CTRL_LATENCY BIT_ULL(2)
|
||||
#define PORT_CTRL_SFTRST_ACK BIT_ULL(4) /* HW ack for reset */
|
||||
|
||||
/* Port Status Register Bitfield */
|
||||
#define PORT_STS_AP2_EVT BIT_ULL(13) /* AP2 event detected */
|
||||
#define PORT_STS_AP1_EVT BIT_ULL(12) /* AP1 event detected */
|
||||
#define PORT_STS_PWR_STATE GENMASK_ULL(11, 8) /* AFU power states */
|
||||
#define PORT_STS_PWR_STATE_NORM 0
|
||||
#define PORT_STS_PWR_STATE_AP1 1 /* 50% throttling */
|
||||
#define PORT_STS_PWR_STATE_AP2 2 /* 90% throttling */
|
||||
#define PORT_STS_PWR_STATE_AP6 6 /* 100% throttling */
|
||||
|
||||
/**
|
||||
* struct dfl_fpga_port_ops - port ops
|
||||
*
|
||||
|
|
@ -154,13 +165,22 @@ void dfl_fpga_port_ops_put(struct dfl_fpga_port_ops *ops);
|
|||
int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id);
|
||||
|
||||
/**
|
||||
* struct dfl_feature_driver - sub feature's driver
|
||||
* struct dfl_feature_id - dfl private feature id
|
||||
*
|
||||
* @id: sub feature id.
|
||||
* @ops: ops of this sub feature.
|
||||
* @id: unique dfl private feature id.
|
||||
*/
|
||||
struct dfl_feature_id {
|
||||
u64 id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dfl_feature_driver - dfl private feature driver
|
||||
*
|
||||
* @id_table: id_table for dfl private features supported by this driver.
|
||||
* @ops: ops of this dfl private feature driver.
|
||||
*/
|
||||
struct dfl_feature_driver {
|
||||
u64 id;
|
||||
const struct dfl_feature_id *id_table;
|
||||
const struct dfl_feature_ops *ops;
|
||||
};
|
||||
|
||||
|
|
@ -183,6 +203,8 @@ struct dfl_feature {
|
|||
|
||||
#define DEV_STATUS_IN_USE 0
|
||||
|
||||
#define FEATURE_DEV_ID_UNUSED (-1)
|
||||
|
||||
/**
|
||||
* struct dfl_feature_platform_data - platform data for feature devices
|
||||
*
|
||||
|
|
@ -191,6 +213,7 @@ struct dfl_feature {
|
|||
* @cdev: cdev of feature dev.
|
||||
* @dev: ptr to platform device linked with this platform data.
|
||||
* @dfl_cdev: ptr to container device.
|
||||
* @id: id used for this feature device.
|
||||
* @disable_count: count for port disable.
|
||||
* @num: number for sub features.
|
||||
* @dev_status: dev status (e.g. DEV_STATUS_IN_USE).
|
||||
|
|
@ -203,6 +226,7 @@ struct dfl_feature_platform_data {
|
|||
struct cdev cdev;
|
||||
struct platform_device *dev;
|
||||
struct dfl_fpga_cdev *dfl_cdev;
|
||||
int id;
|
||||
unsigned int disable_count;
|
||||
unsigned long dev_status;
|
||||
void *private;
|
||||
|
|
@ -373,6 +397,7 @@ void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info);
|
|||
* @fme_dev: FME feature device under this container device.
|
||||
* @lock: mutex lock to protect the port device list.
|
||||
* @port_dev_list: list of all port feature devices under this container device.
|
||||
* @released_port_num: released port number under this container device.
|
||||
*/
|
||||
struct dfl_fpga_cdev {
|
||||
struct device *parent;
|
||||
|
|
@ -380,6 +405,7 @@ struct dfl_fpga_cdev {
|
|||
struct device *fme_dev;
|
||||
struct mutex lock;
|
||||
struct list_head port_dev_list;
|
||||
int released_port_num;
|
||||
};
|
||||
|
||||
struct dfl_fpga_cdev *
|
||||
|
|
@ -407,4 +433,9 @@ dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data,
|
|||
|
||||
return pdev;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
|
|||
Loading…
Reference in a new issue