From owner-svn-src-projects@FreeBSD.ORG Mon Dec 27 05:47:25 2010 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0DFEF106566C; Mon, 27 Dec 2010 05:47:25 +0000 (UTC) (envelope-from jeff@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id EF9D08FC13; Mon, 27 Dec 2010 05:47:24 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id oBR5lO0K012481; Mon, 27 Dec 2010 05:47:24 GMT (envelope-from jeff@svn.freebsd.org) Received: (from jeff@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id oBR5lOhJ012472; Mon, 27 Dec 2010 05:47:24 GMT (envelope-from jeff@svn.freebsd.org) Message-Id: <201012270547.oBR5lOhJ012472@svn.freebsd.org> From: Jeff Roberson Date: Mon, 27 Dec 2010 05:47:24 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r216729 - in projects/ofed/head/sys/ofed: drivers/infiniband/hw/mthca drivers/net/mlx4 include/linux X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 27 Dec 2010 05:47:25 -0000 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 +#include #include #include @@ -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 #include @@ -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