Commit e29f91d3 authored by Alessandro Rubini's avatar Alessandro Rubini

kernel: more work on spec.ko

parent 60980dbe
......@@ -8,6 +8,7 @@ obj-m += spec.o
obj-m += wr-nic.o
spec-objs = spec-pci.o
spec-objs += spec-fmc.o
spec-objs += spec-i2c.o
spec-objs += loader-ll.o
......
......@@ -16,9 +16,9 @@
static int fmc_match(struct device *dev, struct device_driver *drv)
{
struct fmc_driver *fdrv = to_fmc_driver(drv);
struct fmc_device *fdev = to_fmc_device(dev);
const struct fmc_device_id *t = fdrv->id_table;
//struct fmc_driver *fdrv = to_fmc_driver(drv);
//struct fmc_device *fdev = to_fmc_device(dev);
//const struct fmc_device_id *t = fdrv->id_table;
/* Currently, return 1 every time, until we define policies */
return 1;
......@@ -26,7 +26,7 @@ static int fmc_match(struct device *dev, struct device_driver *drv)
static int fmc_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct fmc_device *fdev = to_fmc_device(dev);
//struct fmc_device *fdev = to_fmc_device(dev);
/* FIXME: The MODALIAS */
add_uevent_var(env, "MODALIAS=%s", "fmc");
......
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <linux/slab.h>
#include <linux/fmc.h>
#include "spec.h"
int spec_fmc_create(struct spec_dev *spec)
{
struct fmc_device *fmc;
int ret;
fmc = kzalloc(sizeof(*fmc), GFP_KERNEL);
if (!fmc)
return -ENOMEM;
/* FIXME: many fields of the device are still NULL */
fmc->carrier_name = "SPEC";
fmc->carrier_data = spec;
fmc->base = spec->remap[0];
fmc->irq = spec->pdev->irq;
ret = spec_i2c_init(fmc);
if (ret) {
kfree(fmc);
return ret;
}
spec->fmc = fmc;
ret = fmc_device_register(fmc);
if (ret) {
spec->fmc = NULL;
kfree(fmc);
}
return ret;
}
void spec_fmc_destroy(struct spec_dev *spec)
{
fmc_device_unregister(spec->fmc);
spec_i2c_exit(spec->fmc);
spec->fmc = NULL;
}
......@@ -19,7 +19,6 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/fmc.h>
#include <asm/unaligned.h>
#include "spec.h"
......@@ -38,8 +37,10 @@ static int spec_load_fpga(struct spec_dev *spec)
char *name = spec_fw_name; /* FIXME: temporary hack */
err = request_firmware(&fw, name, dev);
if (err < 0)
if (err < 0) {
dev_err(dev, "request firmware \"%s\": error %i\n", name, err);
return err;
}
dev_info(dev, "got file \"%s\", %i (0x%x) bytes\n",
spec_fw_name, fw->size, fw->size);
......@@ -74,7 +75,8 @@ out:
return err;
}
static int spec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
static int __devinit spec_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct spec_dev *spec;
int i, ret;
......@@ -91,40 +93,64 @@ static int spec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENOMEM;
spec->pdev = pdev;
if ( (i = pci_enable_msi_block(pdev, 1)) < 0)
pr_err("%s: enable ms block: %i\n", __func__, i);
if ( (ret = pci_enable_msi_block(pdev, 1)) < 0)
dev_err(&pdev->dev, "enable msi block: error %i\n", ret);
/* Remap our 3 bars */
for (i = 0; i < 3; i++) {
for (i = ret = 0; i < 3; i++) {
struct resource *r = pdev->resource + (2 * i);
if (!r->start)
continue;
spec->area[i] = r;
if (r->flags & IORESOURCE_MEM)
if (r->flags & IORESOURCE_MEM) {
spec->remap[i] = ioremap(r->start,
r->end + 1 - r->start);
if (!spec->remap[i])
ret = -ENOMEM;
}
}
if (ret)
goto out_unmap;
pci_set_drvdata(pdev, spec);
/* Load the golden FPGA binary to read the eeprom */
spec_load_fpga(spec);
ret = spec_load_fpga(spec);
if (ret)
goto out_unmap;
/* FIXME: eeprom */
ret = spec_fmc_create(spec);
if (ret)
goto out_unmap;
/* Done */
pci_set_drvdata(pdev, spec);
return 0;
out_unmap:
for (i = 0; i < 3; i++) {
if (spec->remap[i])
iounmap(spec->remap[i]);
spec->remap[i] = NULL;
spec->area[i] = NULL;
}
pci_set_drvdata(pdev, NULL);
pci_disable_msi(pdev);
pci_disable_device(pdev);
kfree(spec);
return ret;
}
static void spec_remove(struct pci_dev *pdev)
static void __devexit spec_remove(struct pci_dev *pdev)
{
struct spec_dev *spec = pci_get_drvdata(pdev);
int i;
dev_info(&pdev->dev, "remove\n");
spec_fmc_destroy(spec);
for (i = 0; i < 3; i++) {
iounmap(spec->remap[i]);
if (spec->remap[i])
iounmap(spec->remap[i]);
spec->remap[i] = NULL;
spec->area[i] = NULL;
}
......@@ -149,13 +175,12 @@ static struct pci_driver spec_driver = {
.remove = spec_remove,
};
static int spec_init(void)
static int __init spec_init(void)
{
INIT_LIST_HEAD(&spec_list);
return pci_register_driver(&spec_driver);
}
static void spec_exit(void)
static void __exit spec_exit(void)
{
pci_unregister_driver(&spec_driver);
......
......@@ -14,6 +14,7 @@
#include <linux/firmware.h>
#include <linux/atomic.h>
#include <linux/list.h>
#include <linux/fmc.h>
#define PCI_VENDOR_ID_CERN 0x10dc
#define PCI_DEVICE_ID_SPEC 0x018d
......@@ -22,21 +23,11 @@
#define SPEC_DEFAULT_LM32_ADDR 0x80000 /* used if "1" is passed */
#define SPEC_MAX_BOARDS 8
enum spec_names {
SPEC_NAME_FW,
SPEC_NAME_PROG,
SPEC_NAME_SUBMOD,
SPEC_NAMES,
};
/* Our device structure */
struct spec_dev {
struct pci_dev *pdev;
struct resource *area[3]; /* bar 0, 2, 4 */
void *remap[3]; /* ioremap of bar 0, 2, 4 */
char *names[SPEC_NAMES];
char *submod_name;
struct work_struct work;
const struct firmware *fw;
......@@ -44,12 +35,9 @@ struct spec_dev {
unsigned long irqcount;
atomic_t has_submod;
void *sub_priv;
struct fmc_device *fmc;
};
/* Used by sub-modules */
extern struct list_head spec_list;
/* Registers from the gennum header files */
enum {
GNGPIO_BASE = 0xA00,
......@@ -77,4 +65,13 @@ enum {
PCI_SYS_CFG_SYSTEM = 0x800
};
/* Functions in spec-fmc.c, used by spec-pci.c */
extern int spec_fmc_create(struct spec_dev *spec);
extern void spec_fmc_destroy(struct spec_dev *spec);
/* Function in spec-i2c.c, used by spec-fmc.c */
extern int spec_i2c_init(struct fmc_device *fmc);
extern void spec_i2c_exit(struct fmc_device *fmc);
#endif /* __SPEC_H__ */
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