Skip to content

Commit

Permalink
mlxsw: Make mailboxes 4KB aligned
Browse files Browse the repository at this point in the history
The HW-SW contract requires mailboxes passed to the firmware to be 4KB
aligned. Previously, these mailboxes were mapped using streaming DMA
routines, which do not guarantee the bus addresses to be 4KB aligned.
Under certain conditions this constraint was indeed violated and errors
were observed.

By using consistent DMA mapping routines together with a mailbox size of
4KB we are guaranteed not to violate the constraint.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Ido Schimmel authored and David S. Miller committed Aug 27, 2015
1 parent 262df69 commit 1e81779
Showing 1 changed file with 50 additions and 33 deletions.
83 changes: 50 additions & 33 deletions drivers/net/ethernet/mellanox/mlxsw/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <linux/log2.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/string.h>

#include "pci.h"
#include "core.h"
Expand Down Expand Up @@ -174,6 +175,8 @@ struct mlxsw_pci {
struct mlxsw_pci_mem_item *items;
} fw_area;
struct {
struct mlxsw_pci_mem_item out_mbox;
struct mlxsw_pci_mem_item in_mbox;
struct mutex lock; /* Lock access to command registers */
bool nopoll;
wait_queue_head_t wait;
Expand Down Expand Up @@ -1341,6 +1344,32 @@ static irqreturn_t mlxsw_pci_eq_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}

static int mlxsw_pci_mbox_alloc(struct mlxsw_pci *mlxsw_pci,
struct mlxsw_pci_mem_item *mbox)
{
struct pci_dev *pdev = mlxsw_pci->pdev;
int err = 0;

mbox->size = MLXSW_CMD_MBOX_SIZE;
mbox->buf = pci_alloc_consistent(pdev, MLXSW_CMD_MBOX_SIZE,
&mbox->mapaddr);
if (!mbox->buf) {
dev_err(&pdev->dev, "Failed allocating memory for mailbox\n");
err = -ENOMEM;
}

return err;
}

static void mlxsw_pci_mbox_free(struct mlxsw_pci *mlxsw_pci,
struct mlxsw_pci_mem_item *mbox)
{
struct pci_dev *pdev = mlxsw_pci->pdev;

pci_free_consistent(pdev, MLXSW_CMD_MBOX_SIZE, mbox->buf,
mbox->mapaddr);
}

static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
const struct mlxsw_config_profile *profile)
{
Expand All @@ -1358,6 +1387,15 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
mbox = mlxsw_cmd_mbox_alloc();
if (!mbox)
return -ENOMEM;

err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.in_mbox);
if (err)
goto mbox_put;

err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.out_mbox);
if (err)
goto err_out_mbox_alloc;

err = mlxsw_cmd_query_fw(mlxsw_core, mbox);
if (err)
goto err_query_fw;
Expand Down Expand Up @@ -1420,6 +1458,9 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
err_doorbell_page_bar:
err_iface_rev:
err_query_fw:
mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox);
err_out_mbox_alloc:
mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox);
mbox_put:
mlxsw_cmd_mbox_free(mbox);
return err;
Expand All @@ -1432,6 +1473,8 @@ static void mlxsw_pci_fini(void *bus_priv)
free_irq(mlxsw_pci->msix_entry.vector, mlxsw_pci);
mlxsw_pci_aqs_fini(mlxsw_pci);
mlxsw_pci_fw_area_fini(mlxsw_pci);
mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox);
mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox);
}

static struct mlxsw_pci_queue *
Expand Down Expand Up @@ -1524,8 +1567,8 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
u8 *p_status)
{
struct mlxsw_pci *mlxsw_pci = bus_priv;
dma_addr_t in_mapaddr = 0;
dma_addr_t out_mapaddr = 0;
dma_addr_t in_mapaddr = mlxsw_pci->cmd.in_mbox.mapaddr;
dma_addr_t out_mapaddr = mlxsw_pci->cmd.out_mbox.mapaddr;
bool evreq = mlxsw_pci->cmd.nopoll;
unsigned long timeout = msecs_to_jiffies(MLXSW_PCI_CIR_TIMEOUT_MSECS);
bool *p_wait_done = &mlxsw_pci->cmd.wait_done;
Expand All @@ -1537,27 +1580,11 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
if (err)
return err;

if (in_mbox) {
in_mapaddr = pci_map_single(mlxsw_pci->pdev, in_mbox,
in_mbox_size, PCI_DMA_TODEVICE);
if (unlikely(pci_dma_mapping_error(mlxsw_pci->pdev,
in_mapaddr))) {
err = -EIO;
goto err_in_mbox_map;
}
}
if (in_mbox)
memcpy(mlxsw_pci->cmd.in_mbox.buf, in_mbox, in_mbox_size);
mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_HI, in_mapaddr >> 32);
mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_LO, in_mapaddr);

if (out_mbox) {
out_mapaddr = pci_map_single(mlxsw_pci->pdev, out_mbox,
out_mbox_size, PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(mlxsw_pci->pdev,
out_mapaddr))) {
err = -EIO;
goto err_out_mbox_map;
}
}
mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_HI, out_mapaddr >> 32);
mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_LO, out_mapaddr);

Expand Down Expand Up @@ -1601,7 +1628,7 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
}

if (!err && out_mbox && out_mbox_direct) {
/* Some commands does not use output param as address to mailbox
/* Some commands don't use output param as address to mailbox
* but they store output directly into registers. In that case,
* copy registers into mbox buffer.
*/
Expand All @@ -1615,19 +1642,9 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
CIR_OUT_PARAM_LO));
memcpy(out_mbox + sizeof(tmp), &tmp, sizeof(tmp));
}
}

if (out_mapaddr)
pci_unmap_single(mlxsw_pci->pdev, out_mapaddr, out_mbox_size,
PCI_DMA_FROMDEVICE);

/* fall through */
} else if (!err && out_mbox)
memcpy(out_mbox, mlxsw_pci->cmd.out_mbox.buf, out_mbox_size);

err_out_mbox_map:
if (in_mapaddr)
pci_unmap_single(mlxsw_pci->pdev, in_mapaddr, in_mbox_size,
PCI_DMA_TODEVICE);
err_in_mbox_map:
mutex_unlock(&mlxsw_pci->cmd.lock);

return err;
Expand Down

0 comments on commit 1e81779

Please sign in to comment.