mlx4_core: Allocate and map sufficient ICM memory for EQ context
authorRoland Dreier <rolandd@cisco.com>
Sun, 6 Sep 2009 03:24:49 +0000 (20:24 -0700)
committerRoland Dreier <rolandd@cisco.com>
Sun, 6 Sep 2009 03:24:49 +0000 (20:24 -0700)
The current implementation allocates a single host page for EQ context
memory, which was OK when we only allocated a few EQs.  However, since
we now allocate an EQ for each CPU core, this patch removes the
hard-coded limit (which we exceed with 4 KB pages and 128 byte EQ
context entries with 32 CPUs) and uses the same ICM table code as all
other context tables, which ends up simplifying the code quite a bit
while fixing the problem.

This problem was actually hit in practice on a dual-socket Nehalem box
with 16 real hardware threads and sufficiently odd ACPI tables that it
shows on boot

    SMP: Allowing 32 CPUs, 16 hotplug CPUs

so num_possible_cpus() ends up 32, and mlx4 ends up creating 33 MSI-X
interrupts and 33 EQs.  This mlx4 bug means that mlx4 can't even
initialize at all on this quite mainstream system.

Cc: <stable@kernel.org>
Reported-by: Eli Cohen <eli@mellanox.co.il>
Tested-by: Christoph Lameter <cl@linux-foundation.org>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/net/mlx4/eq.c
drivers/net/mlx4/main.c
drivers/net/mlx4/mlx4.h

index c11a052..d7974a6 100644 (file)
@@ -525,48 +525,6 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev)
        iounmap(priv->clr_base);
 }
 
-int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
-{
-       struct mlx4_priv *priv = mlx4_priv(dev);
-       int ret;
-
-       /*
-        * We assume that mapping one page is enough for the whole EQ
-        * context table.  This is fine with all current HCAs, because
-        * we only use 32 EQs and each EQ uses 64 bytes of context
-        * memory, or 1 KB total.
-        */
-       priv->eq_table.icm_virt = icm_virt;
-       priv->eq_table.icm_page = alloc_page(GFP_HIGHUSER);
-       if (!priv->eq_table.icm_page)
-               return -ENOMEM;
-       priv->eq_table.icm_dma  = pci_map_page(dev->pdev, priv->eq_table.icm_page, 0,
-                                              PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-       if (pci_dma_mapping_error(dev->pdev, priv->eq_table.icm_dma)) {
-               __free_page(priv->eq_table.icm_page);
-               return -ENOMEM;
-       }
-
-       ret = mlx4_MAP_ICM_page(dev, priv->eq_table.icm_dma, icm_virt);
-       if (ret) {
-               pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE,
-                              PCI_DMA_BIDIRECTIONAL);
-               __free_page(priv->eq_table.icm_page);
-       }
-
-       return ret;
-}
-
-void mlx4_unmap_eq_icm(struct mlx4_dev *dev)
-{
-       struct mlx4_priv *priv = mlx4_priv(dev);
-
-       mlx4_UNMAP_ICM(dev, priv->eq_table.icm_virt, 1);
-       pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE,
-                      PCI_DMA_BIDIRECTIONAL);
-       __free_page(priv->eq_table.icm_page);
-}
-
 int mlx4_alloc_eq_table(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
index 5c1afe0..528f89b 100644 (file)
@@ -525,7 +525,10 @@ static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
                goto err_unmap_aux;
        }
 
-       err = mlx4_map_eq_icm(dev, init_hca->eqc_base);
+       err = mlx4_init_icm_table(dev, &priv->eq_table.table,
+                                 init_hca->eqc_base, dev_cap->eqc_entry_sz,
+                                 dev->caps.num_eqs, dev->caps.num_eqs,
+                                 0, 0);
        if (err) {
                mlx4_err(dev, "Failed to map EQ context memory, aborting.\n");
                goto err_unmap_cmpt;
@@ -668,7 +671,7 @@ err_unmap_mtt:
        mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table);
 
 err_unmap_eq:
-       mlx4_unmap_eq_icm(dev);
+       mlx4_cleanup_icm_table(dev, &priv->eq_table.table);
 
 err_unmap_cmpt:
        mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table);
@@ -698,11 +701,11 @@ static void mlx4_free_icms(struct mlx4_dev *dev)
        mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table);
        mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table);
        mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table);
+       mlx4_cleanup_icm_table(dev, &priv->eq_table.table);
        mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table);
        mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table);
        mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table);
        mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table);
-       mlx4_unmap_eq_icm(dev);
 
        mlx4_UNMAP_ICM_AUX(dev);
        mlx4_free_icm(dev, priv->fw.aux_icm, 0);
index 5bd79c2..bc72d6e 100644 (file)
@@ -205,9 +205,7 @@ struct mlx4_eq_table {
        void __iomem          **uar_map;
        u32                     clr_mask;
        struct mlx4_eq         *eq;
-       u64                     icm_virt;
-       struct page            *icm_page;
-       dma_addr_t              icm_dma;
+       struct mlx4_icm_table   table;
        struct mlx4_icm_table   cmpt_table;
        int                     have_irq;
        u8                      inta_pin;
@@ -373,9 +371,6 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
                      struct mlx4_dev_cap *dev_cap,
                      struct mlx4_init_hca_param *init_hca);
 
-int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt);
-void mlx4_unmap_eq_icm(struct mlx4_dev *dev);
-
 int mlx4_cmd_init(struct mlx4_dev *dev);
 void mlx4_cmd_cleanup(struct mlx4_dev *dev);
 void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param);