svn commit: r216729 - in projects/ofed/head/sys/ofed:
drivers/infiniband/hw/mthca drivers/net/mlx4 include/linux
Jeff Roberson
jeff at FreeBSD.org
Mon Dec 27 05:47:25 UTC 2010
Author: jeff
Date: Mon Dec 27 05:47:24 2010
New Revision: 216729
URL: http://svn.freebsd.org/changeset/base/216729
Log:
- Implement Linux compatible support for msix, removing some diffs against
driver sources.
- Add plubming to find the device based on the irq to eliminate another
linux incompatibility in request_irq().
- Implement free_irq() which was previously empty.
Sponsored by: Isilon Systems, iX Systems, and Panasas.
Modified:
projects/ofed/head/sys/ofed/drivers/infiniband/hw/mthca/mthca_eq.c
projects/ofed/head/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c
projects/ofed/head/sys/ofed/drivers/net/mlx4/eq.c
projects/ofed/head/sys/ofed/drivers/net/mlx4/main.c
projects/ofed/head/sys/ofed/include/linux/device.h
projects/ofed/head/sys/ofed/include/linux/interrupt.h
projects/ofed/head/sys/ofed/include/linux/linux_compat.c
projects/ofed/head/sys/ofed/include/linux/pci.h
Modified: projects/ofed/head/sys/ofed/drivers/infiniband/hw/mthca/mthca_eq.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/infiniband/hw/mthca/mthca_eq.c Mon Dec 27 00:30:29 2010 (r216728)
+++ projects/ofed/head/sys/ofed/drivers/infiniband/hw/mthca/mthca_eq.c Mon Dec 27 05:47:24 2010 (r216729)
@@ -865,38 +865,21 @@ int mthca_init_eq_table(struct mthca_dev
};
for (i = 0; i < MTHCA_NUM_EQ; ++i) {
-#ifdef __linux__
err = request_irq(dev->eq_table.eq[i].msi_x_vector,
mthca_is_memfree(dev) ?
mthca_arbel_msi_x_interrupt :
mthca_tavor_msi_x_interrupt,
0, eq_name[i], dev->eq_table.eq + i);
-#else
- err = request_irq(dev->eq_table.eq[i].msi_x_vector,
- mthca_is_memfree(dev) ?
- mthca_arbel_msi_x_interrupt :
- mthca_tavor_msi_x_interrupt,
- 0, eq_name[i], dev->eq_table.eq + i,
- &dev->pdev->dev);
-#endif
if (err)
goto err_out_cmd;
dev->eq_table.eq[i].have_irq = 1;
}
} else {
-#ifdef __linux__
err = request_irq(dev->pdev->irq,
mthca_is_memfree(dev) ?
mthca_arbel_interrupt :
mthca_tavor_interrupt,
IRQF_SHARED, DRV_NAME, dev);
-#else
- err = request_irq(dev->pdev->irq,
- mthca_is_memfree(dev) ?
- mthca_arbel_interrupt :
- mthca_tavor_interrupt,
- IRQF_SHARED, DRV_NAME, dev, &dev->pdev->dev);
-#endif
if (err)
goto err_out_cmd;
dev->eq_table.have_irq = 1;
Modified: projects/ofed/head/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c Mon Dec 27 00:30:29 2010 (r216728)
+++ projects/ofed/head/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c Mon Dec 27 05:47:24 2010 (r216729)
@@ -932,7 +932,6 @@ err_uar_table_free:
static int mthca_enable_msi_x(struct mthca_dev *mdev)
{
-#ifdef __linux__
struct msix_entry entries[3];
int err;
@@ -953,9 +952,6 @@ static int mthca_enable_msi_x(struct mth
mdev->eq_table.eq[MTHCA_EQ_CMD ].msi_x_vector = entries[2].vector;
return 0;
-#else
- return -EINVAL;
-#endif
}
/* Types of supported HCA */
Modified: projects/ofed/head/sys/ofed/drivers/net/mlx4/eq.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/net/mlx4/eq.c Mon Dec 27 00:30:29 2010 (r216728)
+++ projects/ofed/head/sys/ofed/drivers/net/mlx4/eq.c Mon Dec 27 05:47:24 2010 (r216729)
@@ -611,28 +611,17 @@ int mlx4_init_eq_table(struct mlx4_dev *
} else
eq_name = async_eq_name;
-#ifdef __linux__
err = request_irq(priv->eq_table.eq[i].irq,
mlx4_msi_x_interrupt, 0, eq_name,
priv->eq_table.eq + i);
-#else
- err = request_irq(priv->eq_table.eq[i].irq,
- mlx4_msi_x_interrupt, 0, eq_name,
- priv->eq_table.eq + i, &dev->pdev->dev);
-#endif
if (err)
goto err_out_async;
priv->eq_table.eq[i].have_irq = 1;
}
} else {
-#ifdef __linux__
err = request_irq(dev->pdev->irq, mlx4_interrupt,
IRQF_SHARED, DRV_NAME, dev);
-#else
- err = request_irq(dev->pdev->irq, mlx4_interrupt,
- IRQF_SHARED, DRV_NAME, dev, &dev->pdev->dev);
-#endif
if (err)
goto err_out_async;
Modified: projects/ofed/head/sys/ofed/drivers/net/mlx4/main.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/net/mlx4/main.c Mon Dec 27 00:30:29 2010 (r216728)
+++ projects/ofed/head/sys/ofed/drivers/net/mlx4/main.c Mon Dec 27 05:47:24 2010 (r216729)
@@ -1208,7 +1208,6 @@ err_uar_table_free:
static void mlx4_enable_msi_x(struct mlx4_dev *dev)
{
-#ifdef __linux__
struct mlx4_priv *priv = mlx4_priv(dev);
struct msix_entry *entries;
int nreq;
@@ -1255,15 +1254,6 @@ no_msi:
for (i = 0; i < 2; ++i)
priv->eq_table.eq[i].irq = dev->pdev->irq;
-#else
- struct mlx4_priv *priv = mlx4_priv(dev);
- int i;
-
- dev->caps.num_comp_vectors = 1;
-
- for (i = 0; i < 2; ++i)
- priv->eq_table.eq[i].irq = dev->pdev->irq;
-#endif
}
static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
Modified: projects/ofed/head/sys/ofed/include/linux/device.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/device.h Mon Dec 27 00:30:29 2010 (r216728)
+++ projects/ofed/head/sys/ofed/include/linux/device.h Mon Dec 27 05:47:24 2010 (r216729)
@@ -55,17 +55,17 @@ struct class {
struct device {
struct device *parent;
+ struct list_head irqents;
device_t bsddev;
dev_t devt;
struct class *class;
void (*release)(struct device *dev);
- irqreturn_t (*irqhandler)(int, void *);
- void *irqarg;
- void *irqtag;
struct kobject kobj;
uint64_t *dma_mask;
void *driver_data;
-
+ unsigned int irq;
+ unsigned int msix;
+ unsigned int msix_max;
};
extern struct device linux_rootdev;
Modified: projects/ofed/head/sys/ofed/include/linux/interrupt.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/interrupt.h Mon Dec 27 00:30:29 2010 (r216728)
+++ projects/ofed/head/sys/ofed/include/linux/interrupt.h Mon Dec 27 05:47:24 2010 (r216729)
@@ -30,6 +30,7 @@
#define _LINUX_INTERRUPT_H_
#include <linux/device.h>
+#include <linux/pci.h>
#include <sys/bus.h>
#include <sys/rman.h>
@@ -40,34 +41,77 @@ typedef irqreturn_t (*irq_handler_t)(int
#define IRQF_SHARED RF_SHAREABLE
+struct irq_ent {
+ struct list_head links;
+ struct device *dev;
+ struct resource *res;
+ void *arg;
+ irqreturn_t (*handler)(int, void *);
+ void *tag;
+ int irq;
+};
+
+static inline int
+_irq_rid(struct device *dev, int irq)
+{
+ if (irq == dev->irq)
+ return (0);
+ return irq - dev->msix + 1;
+}
+
static void
-_irq_handler(void *device)
+_irq_handler(void *ent)
{
- struct device *dev;
+ struct irq_ent *irqe;
- dev = device;
- dev->irqhandler(0, dev->irqarg);
+ irqe = ent;
+ irqe->handler(irqe->irq, irqe->arg);
+}
+
+static inline struct irq_ent *
+_irq_ent(struct device *dev, int irq)
+{
+ struct irq_ent *irqe;
+
+ list_for_each_entry(irqe, &dev->irqents, links)
+ if (irqe->irq == irq)
+ return (irqe);
+
+ return (NULL);
}
static inline int
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
- const char *name, void *arg, struct device *dev)
+ const char *name, void *arg)
{
struct resource *res;
+ struct irq_ent *irqe;
+ struct device *dev;
int error;
int rid;
- rid = 0;
+ dev = _pci_find_irq_dev(irq);
+ if (dev == NULL)
+ return -ENXIO;
+ rid = _irq_rid(dev, irq);
res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid,
flags | RF_ACTIVE);
if (res == NULL)
return (-ENXIO);
+ irqe = kmalloc(sizeof(*irqe), GFP_KERNEL);
+ irqe->dev = dev;
+ irqe->res = res;
+ irqe->arg = arg;
+ irqe->handler = handler;
+ irqe->irq = irq;
error = bus_setup_intr(dev->bsddev, res, INTR_TYPE_NET | INTR_MPSAFE,
- NULL, _irq_handler, dev, &dev->irqtag);
- if (error)
+ NULL, _irq_handler, irqe, &irqe->tag);
+ if (error) {
+ bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
+ kfree(irqe);
return (-error);
- dev->irqhandler = handler;
- dev->irqarg = arg;
+ }
+ list_add(&irqe->links, &dev->irqents);
return 0;
}
@@ -75,7 +119,21 @@ request_irq(unsigned int irq, irq_handle
static inline void
free_irq(unsigned int irq, void *device)
{
- /* XXX */
+ struct irq_ent *irqe;
+ struct device *dev;
+ int rid;
+
+ dev = _pci_find_irq_dev(irq);
+ if (dev == NULL)
+ return;
+ rid = _irq_rid(dev, irq);
+ irqe = _irq_ent(dev, irq);
+ if (irqe == NULL)
+ return;
+ bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag);
+ bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
+ list_del(&irqe->links);
+ kfree(irqe);
}
#endif /* _LINUX_INTERRUPT_H_ */
Modified: projects/ofed/head/sys/ofed/include/linux/linux_compat.c
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/linux_compat.c Mon Dec 27 00:30:29 2010 (r216728)
+++ projects/ofed/head/sys/ofed/include/linux/linux_compat.c Mon Dec 27 05:47:24 2010 (r216729)
@@ -61,6 +61,8 @@ struct kobject class_root;
struct device linux_rootdev;
struct class miscclass;
struct list_head pci_drivers;
+struct list_head pci_devices;
+spinlock_t pci_lock;
int
panic_cmp(struct rb_node *one, struct rb_node *two)
@@ -528,6 +530,8 @@ linux_compat_init(void)
miscclass.name = "misc";
class_register(&miscclass);
INIT_LIST_HEAD(&pci_drivers);
+ INIT_LIST_HEAD(&pci_devices);
+ spin_lock_init(&pci_lock);
}
SYSINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_init, NULL);
Modified: projects/ofed/head/sys/ofed/include/linux/pci.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/pci.h Mon Dec 27 00:30:29 2010 (r216728)
+++ projects/ofed/head/sys/ofed/include/linux/pci.h Mon Dec 27 05:47:24 2010 (r216729)
@@ -29,6 +29,8 @@
#ifndef _LINUX_PCI_H_
#define _LINUX_PCI_H_
+#define CONFIG_PCI_MSI
+
#include <linux/types.h>
#include <sys/param.h>
@@ -100,11 +102,14 @@ struct pci_driver {
};
extern struct list_head pci_drivers;
+extern struct list_head pci_devices;
+extern spinlock_t pci_lock;
#define __devexit_p(x) x
struct pci_dev {
struct device dev;
+ struct list_head links;
struct pci_driver *pdrv;
uint64_t dma_mask;
uint16_t device;
@@ -134,6 +139,24 @@ _pci_get_bar(struct pci_dev *pdev, int b
return (rle);
}
+static inline struct device *
+_pci_find_irq_dev(unsigned int irq)
+{
+ struct pci_dev *pdev;
+
+ spin_lock(&pci_lock);
+ list_for_each_entry(pdev, &pci_devices, links) {
+ if (irq == pdev->dev.irq)
+ break;
+ if (irq >= pdev->dev.msix && irq < pdev->dev.msix_max)
+ break;
+ }
+ spin_unlock(&pci_lock);
+ if (pdev)
+ return &pdev->dev;
+ return (NULL);
+}
+
static inline unsigned long
pci_resource_start(struct pci_dev *pdev, int bar)
{
@@ -340,14 +363,17 @@ linux_pci_find(device_t dev, struct pci_
vendor = pci_get_vendor(dev);
device = pci_get_device(dev);
+ spin_lock(&pci_lock);
list_for_each_entry(pdrv, &pci_drivers, links) {
for (id = pdrv->id_table; id->vendor != 0; id++) {
if (vendor == id->vendor && device == id->device) {
*idp = id;
+ spin_unlock(&pci_lock);
return (pdrv);
}
}
}
+ spin_unlock(&pci_lock);
return (NULL);
}
@@ -378,6 +404,7 @@ linux_pci_attach(device_t dev)
pdev = device_get_softc(dev);
pdev->dev.parent = &linux_rootdev;
pdev->dev.bsddev = dev;
+ INIT_LIST_HEAD(&pdev->dev.irqents);
pdev->device = id->device;
pdev->vendor = id->vendor;
pdev->dev.dma_mask = &pdev->dma_mask;
@@ -388,12 +415,22 @@ linux_pci_attach(device_t dev)
kobject_name(&pdev->dev.kobj));
rle = _pci_get_rle(pdev, SYS_RES_IRQ, 0);
if (rle)
- pdev->irq = rle->start;
+ pdev->dev.irq = rle->start;
+ else
+ pdev->dev.irq = 0;
+ pdev->irq = pdev->dev.irq;
mtx_unlock(&Giant);
+ spin_lock(&pci_lock);
+ list_add(&pdev->links, &pci_devices);
+ spin_unlock(&pci_lock);
error = pdrv->probe(pdev, id);
mtx_lock(&Giant);
- if (error)
+ if (error) {
+ spin_lock(&pci_lock);
+ list_del(&pdev->links);
+ spin_unlock(&pci_lock);
return (-error);
+ }
return (0);
}
@@ -404,6 +441,9 @@ linux_pci_detach(device_t dev)
pdev = device_get_softc(dev);
pdev->pdrv->remove(pdev);
+ spin_lock(&pci_lock);
+ list_del(&pdev->links);
+ spin_unlock(&pci_lock);
return (0);
}
@@ -420,7 +460,9 @@ pci_register_driver(struct pci_driver *p
devclass_t bus;
int error;
+ spin_lock(&pci_lock);
list_add(&pdrv->links, &pci_drivers);
+ spin_unlock(&pci_lock);
bus = devclass_find("pci");
pdrv->driver.name = pdrv->name;
pdrv->driver.methods = pci_methods;
@@ -444,6 +486,40 @@ pci_unregister_driver(struct pci_driver
devclass_delete_driver(bus, &pdrv->driver);
}
+struct msix_entry {
+ int entry;
+ int vector;
+};
+
+/*
+ * Enable msix, positive errors indicate actual number of available
+ * vectors. Negative errors are failures.
+ */
+static inline int
+pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq)
+{
+ struct resource_list_entry *rle;
+ int error;
+ int avail;
+ int i;
+
+ avail = pci_msix_count(pdev->dev.bsddev);
+ if (avail < nreq) {
+ if (avail == 0)
+ return -EINVAL;
+ return avail;
+ }
+ avail = nreq;
+ if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0)
+ return error;
+ rle = _pci_get_rle(pdev, SYS_RES_IRQ, 1);
+ pdev->dev.msix = rle->start;
+ pdev->dev.msix_max = rle->start + avail;
+ for (i = 0; i < nreq; i++)
+ entries[i].vector = pdev->dev.msix + i;
+ return (0);
+}
+
/* XXX This should not be necessary. */
#define pcix_set_mmrbc(d, v) 0
#define pcix_get_max_mmrbc(d) 0
More information about the svn-src-projects
mailing list