Commit 25bb45df authored by Jens Korinth's avatar Jens Korinth
Browse files

WIP: PCIe driver fully buildable, but untested

* insmod/rmmod'ing works fine
* all interrupts are gotten etc.
* all basic functionality should be available
parent 58ae2f5c
......@@ -53,7 +53,7 @@ long tlkm_device_ioctl(struct file *fp, unsigned int ioctl, unsigned long data)
if (ioctl == TLKM_DEV_IOCTL_INFO) {
return tlkm_device_ioctl_info(fp, ioctl, (struct tlkm_device_info __user *)data);
} else {
tlkm_device_ioctl_f ioctl_f = device_from_file(fp)->ioctl;
tlkm_device_ioctl_f ioctl_f = device_from_file(fp)->cls->ioctl;
BUG_ON(!ioctl_f);
return ioctl_f(device_from_file(fp), ioctl, data);
}
......
......@@ -14,7 +14,7 @@ struct tlkm_device *device_from_file(struct file *fp)
int tlkm_device_mmap(struct file *fp, struct vm_area_struct *vm)
{
struct tlkm_device *d = device_from_file(fp);
tlkm_device_mmap_f mmap_f = d->mmap;
tlkm_device_mmap_f mmap_f = d->cls->mmap;
if (! mmap_f) {
DEVWRN(d->dev_id, "device has no mmap() implementation, register accesses are likely slow!");
}
......
......@@ -94,6 +94,7 @@ void tlkm_perfc_miscdev_exit(struct tlkm_device *dev)
{
kfree(dev->perfc_dev.name);
misc_deregister(&dev->perfc_dev);
memset(&dev->perfc_dev, 0, sizeof(dev->perfc_dev));
DEVLOG(dev->dev_id, TLKM_LF_PERFC, "removed performance counter miscdev");
}
#endif /* NPERFC */
......@@ -6,6 +6,7 @@
#include "pcie/pcie_irq.h"
#define TLKM_PCI_NAME "tlkm"
#define TLKM_CLS_NAME "pcie"
#define XILINX_VENDOR_ID 0x10EE
#define XILINX_DEVICE_ID 0x7038
......@@ -14,7 +15,7 @@ void pcie_exit(struct tlkm_class *cls);
static const
struct tlkm_class pcie_cls = {
.name = TLKM_PCI_NAME,
.name = TLKM_CLS_NAME,
.create = pcie_device_create,
.destroy = pcie_device_destroy,
.probe = pcie_init,
......
......@@ -15,9 +15,6 @@
#define TLKM_DEV_ID(pdev) \
(((struct tlkm_pcie_device *)dev_get_drvdata(&(pdev)->dev))->parent->dev_id)
static size_t num_devices = 0;
ssize_t pcie_enumerate(void) { return num_devices; }
/**
* @brief Enables pcie-device and claims/remaps neccessary bar resources
* @param pdev Pointer to pci-device, which should be allocated
......@@ -69,10 +66,6 @@ static int claim_device(struct tlkm_pcie_device *pdev)
DEVLOG(did, TLKM_LF_PCIE, "status core base: 0x%08llx => 0x%08llx",
(u64)pcie_cls.status_base, (u64)pcie_cls.status_base + pdev->parent->base_offset);
tlkm_perfc_link_speed_set(did, pdev->link_speed);
tlkm_perfc_link_width_set(did, pdev->link_width);
num_devices++;
return 0;
iounmap(pdev->kvirt_addr_bar0);
......@@ -174,7 +167,6 @@ static void release_msi(struct tlkm_pcie_device *pdev)
static void report_link_status(struct tlkm_pcie_device *pdev)
{
struct pci_dev *dev = pdev->pdev;
dev_id_t did = pdev->parent->dev_id;
u16 ctrl_reg = 0;
int gts = 0;
......@@ -190,8 +182,11 @@ static void report_link_status(struct tlkm_pcie_device *pdev)
default: gts = 0; break;
}
DEVLOG(did, TLKM_LF_PCIE, "PCIe link width: x%d", pdev->link_width);
DEVLOG(did, TLKM_LF_PCIE, "PCIe link speed: %d.%d GT/s", gts / 10, gts % 10);
DEVLOG(pdev->parent->dev_id, TLKM_LF_PCIE, "PCIe link width: x%d", pdev->link_width);
DEVLOG(pdev->parent->dev_id, TLKM_LF_PCIE, "PCIe link speed: %d.%d GT/s", gts / 10, gts % 10);
tlkm_perfc_link_speed_set(pdev->parent->dev_id, pdev->link_speed);
tlkm_perfc_link_width_set(pdev->parent->dev_id, pdev->link_width);
}
int tlkm_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
......@@ -199,7 +194,6 @@ int tlkm_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct tlkm_device *dev;
LOG(TLKM_LF_PCIE, "found TaPaSCo PCIe device, registering ...");
dev = tlkm_bus_new_device((struct tlkm_class *)&pcie_cls,
TLKM_PCI_NAME,
XILINX_VENDOR_ID,
XILINX_DEVICE_ID,
pdev);
......@@ -212,13 +206,8 @@ int tlkm_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
void tlkm_pcie_remove(struct pci_dev *pdev)
{
struct tlkm_pcie_device *dev = (struct tlkm_pcie_device *)dev_get_drvdata(&pdev->dev);
BUG_ON(! dev);
DEVLOG(TLKM_DEV_ID(pdev), TLKM_LF_PCIE, "unload PCIedevice");
tlkm_bus_delete_device(dev->parent);
}
int pcie_device_create(struct tlkm_device *dev, void *data)
{
int ret = 0;
......
......@@ -124,6 +124,6 @@ void pcie_irqs_release_platform_irq(struct tlkm_device *dev, int irq_no)
return;
}
DEVLOG(dev->dev_id, TLKM_LF_IRQ, "freeing platform interrupt #%d with mapping %d", irq_no, pdev->irq_mapping[irq_no]);
free_irq(pdev->irq_mapping[irq_no], pdev);
free_irq(pdev->irq_mapping[irq_no], pdev->pdev);
pdev->irq_mapping[irq_no] = -1;
}
......@@ -139,7 +139,7 @@
int pcie_irqs_init(struct tlkm_device *dev);
void pcie_irqs_exit(struct tlkm_device *dev);
int pcie_irqs_request_platform_irq(struct tlkm_device *dev, int irq_no, intr_handler_f);
int pcie_irqs_request_platform_irq(struct tlkm_device *dev, int irq_no, irq_handler_t);
void pcie_irqs_release_platform_irq(struct tlkm_device *dev, int irq_no);
#define _INTR(nr) \
......
CFLAGS+=-Wall -Werror -I$(TAPASCO_HOME)/module/user
CFLAGS+=-Wall -Werror -I$(TAPASCO_HOME)/tlkm/user
LDFLAGS+=-lc
%.o: %.c
......
......@@ -8,6 +8,7 @@
static struct {
struct miscdevice miscdev;
int is_setup;
} _tlkm;
static const struct file_operations _tlkm_fops = {
......@@ -21,11 +22,13 @@ int tlkm_init(void)
_tlkm.miscdev.minor = MISC_DYNAMIC_MINOR;
_tlkm.miscdev.name = TLKM_IOCTL_FN;
_tlkm.miscdev.fops = &_tlkm_fops;
_tlkm.is_setup = 1;
return misc_register(&_tlkm.miscdev);
}
void tlkm_exit(void)
{
misc_deregister(&_tlkm.miscdev);
if (_tlkm.is_setup)
misc_deregister(&_tlkm.miscdev);
LOG(TLKM_LF_MODULE, "removed ioctl file " TLKM_IOCTL_FN);
}
......@@ -20,7 +20,6 @@ struct tlkm_bus {
struct list_head devices;
size_t num_devs;
} _tlkm_bus = {
.devices = LIST_HEAD_INIT(_tlkm_bus.devices),
.num_devs = 0,
};
......@@ -33,28 +32,27 @@ static
void tlkm_bus_add_device(struct tlkm_device *pdev)
{
mutex_lock(&_tlkm_bus_mtx);
list_add(&pdev->device, &_tlkm_bus.devices);
list_add_tail(&pdev->device, &_tlkm_bus.devices);
pdev->dev_id = _tlkm_bus.num_devs++;
mutex_unlock(&_tlkm_bus_mtx);
LOG(TLKM_LF_BUS, "added device '%s' to bus", pdev->name);
LOG(TLKM_LF_BUS, "added '%s' device to bus", pdev->cls->name);
}
static
void tlkm_bus_del_device(struct tlkm_device *pdev)
{
mutex_lock(&_tlkm_bus_mtx);
list_del(&_tlkm_bus.devices);
list_del(&pdev->device);
--_tlkm_bus.num_devs;
mutex_unlock(&_tlkm_bus_mtx);
LOG(TLKM_LF_BUS, "removed device '%s' from bus", pdev->name);
LOG(TLKM_LF_BUS, "removed '%s' device from bus", pdev->cls->name);
}
struct tlkm_device *tlkm_bus_new_device(struct tlkm_class *cls, const char *name, int vendor_id, int product_id, void *data)
struct tlkm_device *tlkm_bus_new_device(struct tlkm_class *cls, int vendor_id, int product_id, void *data)
{
int ret = 0;
struct tlkm_device *dev = (struct tlkm_device *)kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev) {
strncpy(dev->name, name, sizeof(dev->name));
dev->vendor_id = vendor_id;
dev->product_id = product_id;
dev->cls = cls;
......@@ -65,6 +63,7 @@ struct tlkm_device *tlkm_bus_new_device(struct tlkm_class *cls, const char *name
kfree(dev);
return NULL;
}
snprintf(dev->name, TLKM_DEVICE_NAME_LEN, "%s_%03u", cls->name, dev->dev_id);
mutex_init(&dev->mtx);
return dev;
} else {
......@@ -82,30 +81,23 @@ void tlkm_bus_delete_device(struct tlkm_device *dev)
}
}
ssize_t tlkm_bus_enumerate(void)
void tlkm_bus_enumerate(void)
{
int i;
ssize_t ret = 0;
int i, r;
for (i = 0; i < sizeof(_tlkm_class)/sizeof(*_tlkm_class); ++i) {
ssize_t r = _tlkm_class[i]->probe(_tlkm_class[i]);
if (r < 0)
ERR("error occurred while probing class '%s': %zd", _tlkm_class[i]->name, r);
else
ret += r;
if ((r = _tlkm_class[i]->probe(_tlkm_class[i])))
ERR("error occurred while probing class '%s': %d", _tlkm_class[i]->name, r);
}
return ret;
}
int tlkm_bus_init(void)
{
int ret = 0;
ssize_t n;
INIT_LIST_HEAD(&_tlkm_bus.devices);
LOG(TLKM_LF_BUS, "detecting TaPaSCo devices ...");
n = tlkm_bus_enumerate();
if (n < 0) {
ERR("could not detect devices, error: %zd", n);
return n;
}
tlkm_bus_enumerate();
n = tlkm_bus_num_devices();
if (! n) {
ERR("did not find any TaPaSCo devices, cannot proceed");
ret = -ENXIO;
......@@ -128,16 +120,19 @@ void tlkm_bus_exit(void)
struct list_head *lh;
struct list_head *tmp;
int i;
LOG(TLKM_LF_BUS, "removing ioctl file ...");
tlkm_exit();
LOG(TLKM_LF_BUS, "removing devices ...");
list_for_each_safe(lh, tmp, &_tlkm_bus.devices) {
struct tlkm_device *d = container_of(lh, struct tlkm_device, device);
LOG(TLKM_LF_BUS, "TaPaSCo device '%s' (%04x:%04x)", d->name,
d->vendor_id, d->product_id);
if (d->cls->destroy)
d->cls->destroy(d);
struct tlkm_device *d = list_entry(lh, struct tlkm_device, device);
LOG(TLKM_LF_BUS, "TaPaSCo device #%03u '%s' (%04x:%04x)", d->dev_id, d->name, d->vendor_id, d->product_id);
tlkm_bus_delete_device(d);
}
for (i = 0; i < sizeof(_tlkm_class)/sizeof(*_tlkm_class); ++i)
LOG(TLKM_LF_BUS, "removing classes ...");
for (i = 0; i < sizeof(_tlkm_class)/sizeof(*_tlkm_class); ++i) {
LOG(TLKM_LF_BUS, "removing class %s", _tlkm_class[i]->name);
_tlkm_class[i]->remove(_tlkm_class[i]);
tlkm_exit();
}
LOG(TLKM_LF_BUS, "removed TaPaSCo interfaces, bye");
}
......
......@@ -10,13 +10,12 @@ int tlkm_bus_init(void);
void tlkm_bus_exit(void);
struct tlkm_device *tlkm_bus_new_device(struct tlkm_class *cls,
const char *name,
int vendor_id,
int product_id,
void *data);
void tlkm_bus_delete_device(struct tlkm_device *dev);
ssize_t tlkm_bus_enumerate(void);
void tlkm_bus_enumerate(void);
size_t tlkm_bus_num_devices(void);
struct tlkm_device *tlkm_bus_get_device(size_t idx);
......
......@@ -2,16 +2,18 @@
#define TLKM_CLASS_H__
#include <linux/interrupt.h>
#include "tlkm_device.h"
#include "tlkm_types.h"
#define TLKM_CLASS_NAME_LEN 32
struct tlkm_device;
struct tlkm_class;
typedef int (*tlkm_class_create_f)(struct tlkm_device *, void *data);
typedef void(*tlkm_class_destroy_f)(struct tlkm_device *);
typedef int (*tlkm_class_probe_f)(struct tlkm_class *);
typedef void(*tlkm_class_remove_f)(struct tlkm_class *);
struct tlkm_device;
typedef long (*tlkm_device_ioctl_f)(struct tlkm_device *, unsigned int ioctl, unsigned long data);
typedef int (*tlkm_device_mmap_f) (struct tlkm_device *, struct vm_area_struct *vm);
......
......@@ -56,25 +56,44 @@ int dma_engines_init(struct tlkm_device *dev)
return ret;
err_dma_engine:
for (; i >= 0; --i)
for (; i >= 0; --i) {
if (dev->dma[i].ops.intr_write && dev->dma[i].ops.intr_write != dev->dma[i].ops.intr_read)
tlkm_device_release_platform_irq(dev, --irqn);
if (dev->dma[i].ops.intr_read)
tlkm_device_release_platform_irq(dev, --irqn);
tlkm_dma_exit(&dev->dma[i]);
}
BUG_ON(irqn);
return ret;
}
static
void dma_engines_exit(struct tlkm_device *dev)
{
int i;
int i, irqn = 0;
DEVLOG(dev->dev_id, TLKM_LF_DEVICE, "releasing DMA engines ...");
for (i = 0; i < TLKM_DEVICE_MAX_DMA_ENGINES; ++i) {
DEVLOG(dev->dev_id, TLKM_LF_DEVICE, "DMA #%d @ 0x%08llx", i, (u64)dev->dma[i].base);
if (dev->dma[i].base) {
if (dev->dma[i].ops.intr_read)
tlkm_device_release_platform_irq(dev, irqn++);
if (dev->dma[i].ops.intr_write && dev->dma[i].ops.intr_write != dev->dma[i].ops.intr_read)
tlkm_device_release_platform_irq(dev, irqn++);
tlkm_dma_exit(&dev->dma[i]);
}
}
DEVLOG(dev->dev_id, TLKM_LF_DEVICE, "DMA engines destroyed");
}
int tlkm_device_init(struct tlkm_device *dev, void *data)
{
int ret = 0;
DEVLOG(dev->dev_id, TLKM_LF_DEVICE, "setup performance counter file ...");
if ((ret = tlkm_perfc_miscdev_init(dev))) {
DEVERR(dev->dev_id, "could not setup performance counter device file: %d", ret);
goto err_nperfc;
}
DEVLOG(dev->dev_id, TLKM_LF_DEVICE, "initializing device ...");
if ((ret = dev->cls->create(dev, data))) {
DEVERR(dev->dev_id, "failed to initialize private data struct: %d", ret);
......@@ -87,12 +106,6 @@ int tlkm_device_init(struct tlkm_device *dev, void *data)
goto err_control;
}
DEVLOG(dev->dev_id, TLKM_LF_DEVICE, "setup performance counter file ...");
if ((ret = tlkm_perfc_miscdev_init(dev))) {
DEVERR(dev->dev_id, "could not setup performance counter device file: %d", ret);
goto err_nperfc;
}
DEVLOG(dev->dev_id, TLKM_LF_DEVICE, "reading address map ...");
if ((ret = tlkm_status_init(&dev->status, dev, dev->base_offset + dev->cls->status_base))) {
DEVERR(dev->dev_id, "coudl not initialize address map: %d", ret);
......@@ -112,12 +125,12 @@ int tlkm_device_init(struct tlkm_device *dev, void *data)
err_dma:
tlkm_status_exit(&dev->status, dev);
err_status:
tlkm_perfc_miscdev_exit(dev);
err_nperfc:
tlkm_control_exit(dev->ctrl);
err_control:
dev->cls->destroy(dev);
err_priv:
tlkm_perfc_miscdev_exit(dev);
err_nperfc:
return ret;
}
......@@ -126,9 +139,9 @@ void tlkm_device_exit(struct tlkm_device *dev)
if (dev) {
dma_engines_exit(dev);
tlkm_status_exit(&dev->status, dev);
tlkm_perfc_miscdev_exit(dev);
tlkm_control_exit(dev->ctrl);
dev->cls->destroy(dev);
tlkm_perfc_miscdev_exit(dev);
DEVLOG(dev->dev_id, TLKM_LF_DEVICE, "destroyed");
}
}
......
......@@ -11,6 +11,8 @@
#include "tlkm_access.h"
#include "tlkm_status.h"
#include "dma/tlkm_dma.h"
#include "tlkm_class.h"
#define TLKM_DEVICE_NAME_LEN 30
#define TLKM_DEVICE_MAX_DMA_ENGINES 4
......@@ -21,10 +23,10 @@ struct tlkm_device {
struct tlkm_class *cls; /* class of the device */
dev_id_t dev_id; /* id of the device in tlkm_bus */
char name[TLKM_DEVICE_NAME_LEN];
size_t ref_cnt[TLKM_ACCESS_TYPES];
int vendor_id;
int product_id;
dev_addr_t base_offset; /* physical base offset of bitstream */
size_t ref_cnt[TLKM_ACCESS_TYPES];
struct tlkm_status status; /* address map information */
struct tlkm_control *ctrl; /* main device file */
struct dma_engine dma[TLKM_DEVICE_MAX_DMA_ENGINES];
......@@ -38,7 +40,6 @@ int tlkm_device_init(struct tlkm_device *pdev, void *data);
void tlkm_device_exit(struct tlkm_device *pdev);
int tlkm_device_acquire(struct tlkm_device *pdev, tlkm_access_t access);
void tlkm_device_release(struct tlkm_device *pdev, tlkm_access_t access);
void tlkm_device_remove_all(struct tlkm_device *pdev);
static inline
int tlkm_device_request_platform_irq(struct tlkm_device *dev, int irq_no, irq_handler_t h)
......
......@@ -56,7 +56,6 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("J. Korinth <jk@esa.cs.tu-darmstadt.de>");
MODULE_AUTHOR("J. Hofmann <jah@esa.cs.tu-darmstadt.de>");
MODULE_AUTHOR("D. de la Chevallerie <dc@esa.cs.tu-darmstadt.de>");
MODULE_DESCRIPTION("Unified device driver for TaPaSCo - the Task Parallel "
"System Composer.");
MODULE_DESCRIPTION("Unified device driver for TaPaSCo - the Task Parallel System Composer.");
MODULE_VERSION(TLKM_VERSION);
MODULE_ALIAS("tapasco");
......@@ -6,13 +6,15 @@
#define ZYNQ_CLASS_NAME "zynq"
static inline void zynq_remove(struct tlkm_class *cls) {}
static const
struct tlkm_class zynq_cls = {
.name = ZYNQ_CLASS_NAME,
.create = zynq_device_init,
.destroy = zynq_device_exit,
.probe = zynq_device_probe,
.remove = NULL,
.remove = zynq_remove,
.status_base = 0x77770000ULL,
.npirqs = 0,
.private_data = NULL,
......
......@@ -144,9 +144,8 @@ int zynq_device_probe(struct tlkm_class *cls)
LOG(TLKM_LF_DEVICE, "searching for Xilinx Zynq-7000 series devices ...");
if (of_find_matching_node(NULL, zynq_ids)) {
LOG(TLKM_LF_DEVICE, "found Xilinx Zynq-7000");
inst = tlkm_bus_new_device(cls, ZYNQ_CLASS_NAME, 0, 0, NULL);
inst = tlkm_bus_new_device(cls, 0, 0, NULL);
BUG_ON(! inst);
return 1;
}
LOG(TLKM_LF_DEVICE, "no Xilinx Zynq-7000 series device found");
return 0;
......
Supports Markdown
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