Skip to content

Commit

Permalink
mlx4_core: Allocate and map sufficient ICM memory for EQ context
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Roland Dreier committed Sep 6, 2009
1 parent 338a8fa commit fa0681d
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 51 deletions.
42 changes: 0 additions & 42 deletions drivers/net/mlx4/eq.c
Expand Up @@ -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);
Expand Down
9 changes: 6 additions & 3 deletions drivers/net/mlx4/main.c
Expand Up @@ -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;
Expand Down Expand Up @@ -668,7 +671,7 @@ static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
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);
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 1 addition & 6 deletions drivers/net/mlx4/mlx4.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit fa0681d

Please sign in to comment.