Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 Dec 2010 05:47:24 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r216729 - in projects/ofed/head/sys/ofed: drivers/infiniband/hw/mthca drivers/net/mlx4 include/linux
Message-ID:  <201012270547.oBR5lOhJ012472@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201012270547.oBR5lOhJ012472>