Skip to content

Commit

Permalink
fpga: manager: change api, don't use drvdata
Browse files Browse the repository at this point in the history
Change fpga_mgr_register to not set or use drvdata.  This supports
the case where a PCIe device has more than one manager.

Add fpga_mgr_create/free functions.  Change fpga_mgr_register and
fpga_mgr_unregister functions to take the mgr struct as their only
parameter.

  struct fpga_manager *fpga_mgr_create(struct device *dev,
                const char *name,
                const struct fpga_manager_ops *mops,
                void *priv);
  void fpga_mgr_free(struct fpga_manager *mgr);
  int fpga_mgr_register(struct fpga_manager *mgr);
  void fpga_mgr_unregister(struct fpga_manager *mgr);

Update the drivers that call fpga_mgr_register with the new API.

Signed-off-by: Alan Tull <atull@kernel.org>
[Moritz: Fixup whitespace issue]
Reported-by: Jiuyue Ma <majiuyue@huawei.com>
Signed-off-by: Moritz Fischer <mdf@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Alan Tull authored and Greg Kroah-Hartman committed May 25, 2018
1 parent bbaa9cd commit 7085e2a
Show file tree
Hide file tree
Showing 13 changed files with 237 additions and 71 deletions.
35 changes: 27 additions & 8 deletions Documentation/fpga/fpga-mgr.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,23 @@ The user should call fpga_mgr_lock and verify that it returns 0 before
attempting to program the FPGA. Likewise, the user should call
fpga_mgr_unlock when done programming the FPGA.

To alloc/free a FPGA manager struct:
------------------------------------

struct fpga_manager *fpga_mgr_create(struct device *dev,
const char *name,
const struct fpga_manager_ops *mops,
void *priv);
void fpga_mgr_free(struct fpga_manager *mgr);

To register or unregister the low level FPGA-specific driver:
-------------------------------------------------------------

int fpga_mgr_register(struct device *dev, const char *name,
const struct fpga_manager_ops *mops,
void *priv);
int fpga_mgr_register(struct fpga_manager *mgr);

void fpga_mgr_unregister(struct device *dev);
void fpga_mgr_unregister(struct fpga_manager *mgr);

Use of these two functions is described below in "How To Support a new FPGA
Use of these functions is described below in "How To Support a new FPGA
device."


Expand Down Expand Up @@ -148,6 +154,7 @@ static int socfpga_fpga_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct socfpga_fpga_priv *priv;
struct fpga_manager *mgr;
int ret;

priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
Expand All @@ -157,13 +164,25 @@ static int socfpga_fpga_probe(struct platform_device *pdev)
/* ... do ioremaps, get interrupts, etc. and save
them in priv... */

return fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager",
&socfpga_fpga_ops, priv);
mgr = fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager",
&socfpga_fpga_ops, priv);
if (!mgr)
return -ENOMEM;

platform_set_drvdata(pdev, mgr);

ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);

return ret;
}

static int socfpga_fpga_remove(struct platform_device *pdev)
{
fpga_mgr_unregister(&pdev->dev);
struct fpga_manager *mgr = platform_get_drvdata(pdev);

fpga_mgr_unregister(mgr);

return 0;
}
Expand Down
19 changes: 14 additions & 5 deletions drivers/fpga/altera-cvp.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ static int altera_cvp_probe(struct pci_dev *pdev,
const struct pci_device_id *dev_id)
{
struct altera_cvp_conf *conf;
struct fpga_manager *mgr;
u16 cmd, val;
int ret;

Expand Down Expand Up @@ -452,16 +453,24 @@ static int altera_cvp_probe(struct pci_dev *pdev,
snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s @%s",
ALTERA_CVP_MGR_NAME, pci_name(pdev));

ret = fpga_mgr_register(&pdev->dev, conf->mgr_name,
&altera_cvp_ops, conf);
if (ret)
mgr = fpga_mgr_create(&pdev->dev, conf->mgr_name,
&altera_cvp_ops, conf);
if (!mgr)
return -ENOMEM;

pci_set_drvdata(pdev, mgr);

ret = fpga_mgr_register(mgr);
if (ret) {
fpga_mgr_free(mgr);
goto err_unmap;
}

ret = driver_create_file(&altera_cvp_driver.driver,
&driver_attr_chkcfg);
if (ret) {
dev_err(&pdev->dev, "Can't create sysfs chkcfg file\n");
fpga_mgr_unregister(&pdev->dev);
fpga_mgr_unregister(mgr);
goto err_unmap;
}

Expand All @@ -483,7 +492,7 @@ static void altera_cvp_remove(struct pci_dev *pdev)
u16 cmd;

driver_remove_file(&altera_cvp_driver.driver, &driver_attr_chkcfg);
fpga_mgr_unregister(&pdev->dev);
fpga_mgr_unregister(mgr);
pci_iounmap(pdev, conf->map);
pci_release_region(pdev, CVP_BAR);
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
Expand Down
18 changes: 16 additions & 2 deletions drivers/fpga/altera-pr-ip-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ static const struct fpga_manager_ops alt_pr_ops = {
int alt_pr_register(struct device *dev, void __iomem *reg_base)
{
struct alt_pr_priv *priv;
struct fpga_manager *mgr;
int ret;
u32 val;

priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
Expand All @@ -201,15 +203,27 @@ int alt_pr_register(struct device *dev, void __iomem *reg_base)
(val & ALT_PR_CSR_STATUS_MSK) >> ALT_PR_CSR_STATUS_SFT,
(int)(val & ALT_PR_CSR_PR_START));

return fpga_mgr_register(dev, dev_name(dev), &alt_pr_ops, priv);
mgr = fpga_mgr_create(dev, dev_name(dev), &alt_pr_ops, priv);
if (!mgr)
return -ENOMEM;

dev_set_drvdata(dev, mgr);

ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);

return ret;
}
EXPORT_SYMBOL_GPL(alt_pr_register);

int alt_pr_unregister(struct device *dev)
{
struct fpga_manager *mgr = dev_get_drvdata(dev);

dev_dbg(dev, "%s\n", __func__);

fpga_mgr_unregister(dev);
fpga_mgr_unregister(mgr);

return 0;
}
Expand Down
20 changes: 17 additions & 3 deletions drivers/fpga/altera-ps-spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ static int altera_ps_probe(struct spi_device *spi)
{
struct altera_ps_conf *conf;
const struct of_device_id *of_id;
struct fpga_manager *mgr;
int ret;

conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
if (!conf)
Expand Down Expand Up @@ -273,13 +275,25 @@ static int altera_ps_probe(struct spi_device *spi)
snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s %s",
dev_driver_string(&spi->dev), dev_name(&spi->dev));

return fpga_mgr_register(&spi->dev, conf->mgr_name,
&altera_ps_ops, conf);
mgr = fpga_mgr_create(&spi->dev, conf->mgr_name,
&altera_ps_ops, conf);
if (!mgr)
return -ENOMEM;

spi_set_drvdata(spi, mgr);

ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);

return ret;
}

static int altera_ps_remove(struct spi_device *spi)
{
fpga_mgr_unregister(&spi->dev);
struct fpga_manager *mgr = spi_get_drvdata(spi);

fpga_mgr_unregister(mgr);

return 0;
}
Expand Down
78 changes: 52 additions & 26 deletions drivers/fpga/fpga-mgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -515,17 +515,17 @@ void fpga_mgr_unlock(struct fpga_manager *mgr)
EXPORT_SYMBOL_GPL(fpga_mgr_unlock);

/**
* fpga_mgr_register - register a low level fpga manager driver
* fpga_mgr_create - create and initialize a FPGA manager struct
* @dev: fpga manager device from pdev
* @name: fpga manager name
* @mops: pointer to structure of fpga manager ops
* @priv: fpga manager private data
*
* Return: 0 on success, negative error code otherwise.
* Return: pointer to struct fpga_manager or NULL
*/
int fpga_mgr_register(struct device *dev, const char *name,
const struct fpga_manager_ops *mops,
void *priv)
struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
const struct fpga_manager_ops *mops,
void *priv)
{
struct fpga_manager *mgr;
int id, ret;
Expand All @@ -534,17 +534,17 @@ int fpga_mgr_register(struct device *dev, const char *name,
!mops->write_init || (!mops->write && !mops->write_sg) ||
(mops->write && mops->write_sg)) {
dev_err(dev, "Attempt to register without fpga_manager_ops\n");
return -EINVAL;
return NULL;
}

if (!name || !strlen(name)) {
dev_err(dev, "Attempt to register with no name!\n");
return -EINVAL;
return NULL;
}

mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
if (!mgr)
return -ENOMEM;
return NULL;

id = ida_simple_get(&fpga_mgr_ida, 0, 0, GFP_KERNEL);
if (id < 0) {
Expand All @@ -558,25 +558,56 @@ int fpga_mgr_register(struct device *dev, const char *name,
mgr->mops = mops;
mgr->priv = priv;

/*
* Initialize framework state by requesting low level driver read state
* from device. FPGA may be in reset mode or may have been programmed
* by bootloader or EEPROM.
*/
mgr->state = mgr->mops->state(mgr);

device_initialize(&mgr->dev);
mgr->dev.class = fpga_mgr_class;
mgr->dev.groups = mops->groups;
mgr->dev.parent = dev;
mgr->dev.of_node = dev->of_node;
mgr->dev.id = id;
dev_set_drvdata(dev, mgr);

ret = dev_set_name(&mgr->dev, "fpga%d", id);
if (ret)
goto error_device;

return mgr;

error_device:
ida_simple_remove(&fpga_mgr_ida, id);
error_kfree:
kfree(mgr);

return NULL;
}
EXPORT_SYMBOL_GPL(fpga_mgr_create);

/**
* fpga_mgr_free - deallocate a FPGA manager
* @mgr: fpga manager struct created by fpga_mgr_create
*/
void fpga_mgr_free(struct fpga_manager *mgr)
{
ida_simple_remove(&fpga_mgr_ida, mgr->dev.id);
kfree(mgr);
}
EXPORT_SYMBOL_GPL(fpga_mgr_free);

/**
* fpga_mgr_register - register a FPGA manager
* @mgr: fpga manager struct created by fpga_mgr_create
*
* Return: 0 on success, negative error code otherwise.
*/
int fpga_mgr_register(struct fpga_manager *mgr)
{
int ret;

/*
* Initialize framework state by requesting low level driver read state
* from device. FPGA may be in reset mode or may have been programmed
* by bootloader or EEPROM.
*/
mgr->state = mgr->mops->state(mgr);

ret = device_add(&mgr->dev);
if (ret)
goto error_device;
Expand All @@ -586,22 +617,18 @@ int fpga_mgr_register(struct device *dev, const char *name,
return 0;

error_device:
ida_simple_remove(&fpga_mgr_ida, id);
error_kfree:
kfree(mgr);
ida_simple_remove(&fpga_mgr_ida, mgr->dev.id);

return ret;
}
EXPORT_SYMBOL_GPL(fpga_mgr_register);

/**
* fpga_mgr_unregister - unregister a low level fpga manager driver
* @dev: fpga manager device from pdev
* fpga_mgr_unregister - unregister a FPGA manager
* @mgr: fpga manager struct
*/
void fpga_mgr_unregister(struct device *dev)
void fpga_mgr_unregister(struct fpga_manager *mgr)
{
struct fpga_manager *mgr = dev_get_drvdata(dev);

dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name);

/*
Expand All @@ -619,8 +646,7 @@ static void fpga_mgr_dev_release(struct device *dev)
{
struct fpga_manager *mgr = to_fpga_manager(dev);

ida_simple_remove(&fpga_mgr_ida, mgr->dev.id);
kfree(mgr);
fpga_mgr_free(mgr);
}

static int __init fpga_mgr_class_init(void)
Expand Down
21 changes: 17 additions & 4 deletions drivers/fpga/ice40-spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ static int ice40_fpga_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct ice40_fpga_priv *priv;
struct fpga_manager *mgr;
int ret;

priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
Expand Down Expand Up @@ -174,14 +175,26 @@ static int ice40_fpga_probe(struct spi_device *spi)
return ret;
}

/* Register with the FPGA manager */
return fpga_mgr_register(dev, "Lattice iCE40 FPGA Manager",
&ice40_fpga_ops, priv);
mgr = fpga_mgr_create(dev, "Lattice iCE40 FPGA Manager",
&ice40_fpga_ops, priv);
if (!mgr)
return -ENOMEM;

spi_set_drvdata(spi, mgr);

ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);

return ret;
}

static int ice40_fpga_remove(struct spi_device *spi)
{
fpga_mgr_unregister(&spi->dev);
struct fpga_manager *mgr = spi_get_drvdata(spi);

fpga_mgr_unregister(mgr);

return 0;
}

Expand Down
Loading

0 comments on commit 7085e2a

Please sign in to comment.