|
@@ -46,6 +46,7 @@
|
|
#include <linux/log2.h>
|
|
#include <linux/log2.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/seq_file.h>
|
|
|
|
+#include <linux/string.h>
|
|
|
|
|
|
#include "pci.h"
|
|
#include "pci.h"
|
|
#include "core.h"
|
|
#include "core.h"
|
|
@@ -174,6 +175,8 @@ struct mlxsw_pci {
|
|
struct mlxsw_pci_mem_item *items;
|
|
struct mlxsw_pci_mem_item *items;
|
|
} fw_area;
|
|
} fw_area;
|
|
struct {
|
|
struct {
|
|
|
|
+ struct mlxsw_pci_mem_item out_mbox;
|
|
|
|
+ struct mlxsw_pci_mem_item in_mbox;
|
|
struct mutex lock; /* Lock access to command registers */
|
|
struct mutex lock; /* Lock access to command registers */
|
|
bool nopoll;
|
|
bool nopoll;
|
|
wait_queue_head_t wait;
|
|
wait_queue_head_t wait;
|
|
@@ -1341,6 +1344,32 @@ static irqreturn_t mlxsw_pci_eq_irq_handler(int irq, void *dev_id)
|
|
return IRQ_HANDLED;
|
|
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,
|
|
static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
|
|
const struct mlxsw_config_profile *profile)
|
|
const struct mlxsw_config_profile *profile)
|
|
{
|
|
{
|
|
@@ -1358,6 +1387,15 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
|
|
mbox = mlxsw_cmd_mbox_alloc();
|
|
mbox = mlxsw_cmd_mbox_alloc();
|
|
if (!mbox)
|
|
if (!mbox)
|
|
return -ENOMEM;
|
|
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);
|
|
err = mlxsw_cmd_query_fw(mlxsw_core, mbox);
|
|
if (err)
|
|
if (err)
|
|
goto err_query_fw;
|
|
goto err_query_fw;
|
|
@@ -1420,6 +1458,9 @@ err_fw_area_init:
|
|
err_doorbell_page_bar:
|
|
err_doorbell_page_bar:
|
|
err_iface_rev:
|
|
err_iface_rev:
|
|
err_query_fw:
|
|
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:
|
|
mbox_put:
|
|
mlxsw_cmd_mbox_free(mbox);
|
|
mlxsw_cmd_mbox_free(mbox);
|
|
return err;
|
|
return err;
|
|
@@ -1432,6 +1473,8 @@ static void mlxsw_pci_fini(void *bus_priv)
|
|
free_irq(mlxsw_pci->msix_entry.vector, mlxsw_pci);
|
|
free_irq(mlxsw_pci->msix_entry.vector, mlxsw_pci);
|
|
mlxsw_pci_aqs_fini(mlxsw_pci);
|
|
mlxsw_pci_aqs_fini(mlxsw_pci);
|
|
mlxsw_pci_fw_area_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 *
|
|
static struct mlxsw_pci_queue *
|
|
@@ -1524,8 +1567,8 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
|
|
u8 *p_status)
|
|
u8 *p_status)
|
|
{
|
|
{
|
|
struct mlxsw_pci *mlxsw_pci = bus_priv;
|
|
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;
|
|
bool evreq = mlxsw_pci->cmd.nopoll;
|
|
unsigned long timeout = msecs_to_jiffies(MLXSW_PCI_CIR_TIMEOUT_MSECS);
|
|
unsigned long timeout = msecs_to_jiffies(MLXSW_PCI_CIR_TIMEOUT_MSECS);
|
|
bool *p_wait_done = &mlxsw_pci->cmd.wait_done;
|
|
bool *p_wait_done = &mlxsw_pci->cmd.wait_done;
|
|
@@ -1537,27 +1580,11 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
|
|
if (err)
|
|
if (err)
|
|
return 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_HI, in_mapaddr >> 32);
|
|
mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_LO, in_mapaddr);
|
|
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_HI, out_mapaddr >> 32);
|
|
mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_LO, out_mapaddr);
|
|
mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_LO, out_mapaddr);
|
|
|
|
|
|
@@ -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) {
|
|
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,
|
|
* but they store output directly into registers. In that case,
|
|
* copy registers into mbox buffer.
|
|
* copy registers into mbox buffer.
|
|
*/
|
|
*/
|
|
@@ -1615,19 +1642,9 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
|
|
CIR_OUT_PARAM_LO));
|
|
CIR_OUT_PARAM_LO));
|
|
memcpy(out_mbox + sizeof(tmp), &tmp, sizeof(tmp));
|
|
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);
|
|
mutex_unlock(&mlxsw_pci->cmd.lock);
|
|
|
|
|
|
return err;
|
|
return err;
|