Commit e04e06e4 authored by Alessandro Rubini's avatar Alessandro Rubini

wr-nic: completed eth_init

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 0e7d41b5
......@@ -9,26 +9,19 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fmc.h>
#include <linux/fmc-sdb.h>
#include "spec-nic.h"
#include "spec.h"
#include "spec-nic.h"
#include "wr_nic/wr-nic.h"
static struct fmc_driver wrn_drv;
static char *wrn_filename = WRN_GATEWARE_DEFAULT_NAME;
module_param_named(file, wrn_filename, charp, 0444);
irqreturn_t wrn_handler(int irq, void *dev_id)
{
struct fmc_device *fmc = dev_id;
fmc->op->irq_ack(fmc);
printk("%s: irq %i\n", __func__, irq);
return IRQ_HANDLED;
}
int wrn_probe(struct fmc_device *fmc)
int wrn_fmc_probe(struct fmc_device *fmc)
{
int ret = 0;
struct device *dev = fmc->hwdev;
......@@ -56,7 +49,7 @@ int wrn_probe(struct fmc_device *fmc)
}
dev_info(dev, "Gateware successfully loaded\n");
if ( (ret = fmc_scan_sdb_tree(fmc, 0x63000)) < 0) {
if ( (ret = fmc_scan_sdb_tree(fmc, WRN_SDB_ADDR)) < 0) {
dev_err(dev, "scan fmc failed %i\n", ret);
goto out;
}
......@@ -72,37 +65,23 @@ int wrn_probe(struct fmc_device *fmc)
/* The netword device */
ret = wrn_eth_init(fmc);
if (ret < 0)
goto out_gpio;
/* The interrupt */
ret = fmc->op->irq_request(fmc, wrn_handler, "wr-nic", 0);
if (ret < 0) {
dev_err(dev, "Can't request interrupt\n");
goto out_nic;
}
return 0;
out_nic:
wrn_eth_exit(fmc);
out_gpio:
wrn_gpio_exit(fmc);
wrn_gpio_exit(fmc);
out:
return ret;
}
int wrn_remove(struct fmc_device *fmc)
int wrn_fmc_remove(struct fmc_device *fmc)
{
fmc->op->irq_free(fmc);
wrn_eth_exit(fmc);
wrn_gpio_exit(fmc);
fmc_free_sdb_tree(fmc);
return 0;
}
static struct fmc_driver wrn_drv = {
static struct fmc_driver wrn_fmc_drv = {
.driver.name = KBUILD_MODNAME,
.probe = wrn_probe,
.remove = wrn_remove,
.probe = wrn_fmc_probe,
.remove = wrn_fmc_remove,
/* no table, as the current match just matches everything */
};
......@@ -110,13 +89,18 @@ static int wrn_init(void)
{
int ret;
ret = fmc_driver_register(&wrn_drv);
ret = platform_driver_register(&wrn_driver); /* nic-device.c */
if (!ret)
ret = fmc_driver_register(&wrn_fmc_drv);
if (ret < 0)
platform_driver_unregister(&wrn_driver);
return ret;
}
static void wrn_exit(void)
{
fmc_driver_unregister(&wrn_drv);
fmc_driver_unregister(&wrn_fmc_drv);
platform_driver_unregister(&wrn_driver);
}
module_init(wrn_init);
......
......@@ -17,11 +17,118 @@
#include "wr_nic/wr-nic.h"
#include "spec.h"
/*
* nic-device.c defines a platform driver. We need to allocate
* a platform device each time this init function is called
* (part of the code is from wr_nic/module.c).
*/
static void wrn_release(struct device *dev)
{
/* nothing to do, but mandatory function */
pr_debug("%s\n", __func__);
}
static struct platform_device wrn_pdev = {
/* other fields filled after it's copied: see wrn_eth_init() */
.name = KBUILD_MODNAME,
.dev.release = &wrn_release,
};
irqreturn_t wrn_handler(int irq, void *dev_id)
{
struct fmc_device *fmc = dev_id;
fmc->op->irq_ack(fmc);
printk("%s: irq %i\n", __func__, irq);
return IRQ_HANDLED;
}
static struct wrn_core {
const char *name;
uint64_t vendor;
uint32_t device;
} wrn_cores[] = {
[WRN_FB_NIC] = {"NIC", SDB_CERN, WRN_SDB_NIC},
[WRN_FB_EP] = {"Endpoint", SDB_CERN, WRN_SDB_EP},
[WRN_FB_PPSG] = {"PPS-Gen", SDB_CERN, WRN_SDB_PPSG},
[WRN_FB_TS] = {"Tx-Stamp", SDB_CERN, WRN_SDB_TS},
};
int wrn_eth_init(struct fmc_device *fmc)
{
struct device *dev = fmc->hwdev;
struct resource *resarr;
struct platform_device *pdev;
struct wrn_drvdata *drvdata;
struct wrn_dev *wrn;
struct wrn_core *c;
int i, ret;
ret = fmc->op->irq_request(fmc, wrn_handler, "wr-nic", 0);
if (ret < 0) {
dev_err(dev, "Can't request interrupt\n");
return ret;
}
/* Make a copy of the platform device and register it */
ret = -ENOMEM;
pdev = kmemdup(&wrn_pdev, sizeof(wrn_pdev), GFP_KERNEL);
resarr = kzalloc(sizeof(*resarr) * ARRAY_SIZE(wrn_cores), GFP_KERNEL);
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
wrn = kzalloc(sizeof(*wrn), GFP_KERNEL);
if (!pdev || !resarr || !drvdata || !wrn)
goto out_mem;
for (i = 0, c = wrn_cores; i < ARRAY_SIZE(wrn_cores); i++, c++) {
signed long start;
unsigned long size;
start = fmc_find_sdb_device(fmc->sdb, c->vendor, c->device,
&size);
if (start < 0) {
dev_err(dev, "Can't find sdb core \"%s\"\n", c->name);
goto out_mem;
}
dev_info(dev, "core \"%s\": offset %08lx\n", c->name, start);
resarr[i].name = c->name;
resarr[i].flags = IORESOURCE_MEM;
resarr[i].start = (unsigned long)fmc->base + start;
resarr[i].end = resarr[i].start + size - 1;
}
pdev->resource = resarr;
pdev->num_resources = ARRAY_SIZE(wrn_cores);
drvdata->wrn = wrn;
drvdata->fmc = fmc;
/* FIXME: drvdata->gpio_base etc */
pdev->dev.platform_data = drvdata;
fmc->mezzanine_data = pdev;
platform_device_register(pdev);
wrn_pdev.id++; /* for the next one */
return 0;
out_mem:
kfree(wrn);
kfree(drvdata);
kfree(resarr);
kfree(pdev);
fmc->op->irq_free(fmc);
return ret;
}
void wrn_eth_exit(struct fmc_device *fmc)
{
struct platform_device *pdev = fmc->mezzanine_data;
struct wrn_drvdata *drvdata = pdev->dev.platform_data;
platform_device_unregister(pdev);
kfree(drvdata->wrn);
kfree(drvdata);
kfree(pdev->resource);
kfree(pdev);
fmc->mezzanine_data = NULL;
fmc->op->irq_free(fmc);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment