octeontx2-af: Add mailbox support infra
authorAleksey Makarov <amakarov@marvell.com>
Wed, 10 Oct 2018 12:44:24 +0000 (18:14 +0530)
committerDavid S. Miller <davem@davemloft.net>
Wed, 10 Oct 2018 17:06:01 +0000 (10:06 -0700)
This patch adds mailbox support infrastructure APIs.
Each RVU device has a dedicated 64KB mailbox region
shared with it's peer for communication. RVU AF has
a separate mailbox region shared with each of RVU PFs
and a RVU PF has a separate region shared with each of
it's VF.

These set of APIs are used by this driver (RVU AF) and
other RVU PF/VF drivers eg netdev, crypto e.t.c.

Signed-off-by: Aleksey Makarov <amakarov@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
Signed-off-by: Lukasz Bartosik <lbartosik@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/octeontx2/Kconfig
drivers/net/ethernet/marvell/octeontx2/af/Makefile
drivers/net/ethernet/marvell/octeontx2/af/mbox.c [new file with mode: 0644]
drivers/net/ethernet/marvell/octeontx2/af/mbox.h [new file with mode: 0644]
drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h

index 8823152edabfe7550df091fec9f1a264fecb416f..35827bdf18782c90cb241f1aa1b8f7e56328596f 100644 (file)
@@ -2,8 +2,12 @@
 # Marvell OcteonTX2 drivers configuration
 #
 
+config OCTEONTX2_MBOX
+       tristate
+
 config OCTEONTX2_AF
        tristate "Marvell OcteonTX2 RVU Admin Function driver"
+       select OCTEONTX2_MBOX
        depends on (64BIT && COMPILE_TEST) || ARM64
        depends on PCI
        help
index dacbd167b3772bb391a69fe3fe82f16df3b89dc0..ac17cb9acb9bd5598997a31ca332be74969e4715 100644 (file)
@@ -3,6 +3,8 @@
 # Makefile for Marvell's OcteonTX2 RVU Admin Function driver
 #
 
+obj-$(CONFIG_OCTEONTX2_MBOX) += octeontx2_mbox.o
 obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o
 
+octeontx2_mbox-y := mbox.o
 octeontx2_af-y := rvu.o
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c
new file mode 100644 (file)
index 0000000..85ba24a
--- /dev/null
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+
+#include "rvu_reg.h"
+#include "mbox.h"
+
+static const u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
+
+void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
+{
+       struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+       struct mbox_hdr *tx_hdr, *rx_hdr;
+
+       tx_hdr = mdev->mbase + mbox->tx_start;
+       rx_hdr = mdev->mbase + mbox->rx_start;
+
+       spin_lock(&mdev->mbox_lock);
+       mdev->msg_size = 0;
+       mdev->rsp_size = 0;
+       tx_hdr->num_msgs = 0;
+       rx_hdr->num_msgs = 0;
+       spin_unlock(&mdev->mbox_lock);
+}
+EXPORT_SYMBOL(otx2_mbox_reset);
+
+void otx2_mbox_destroy(struct otx2_mbox *mbox)
+{
+       mbox->reg_base = NULL;
+       mbox->hwbase = NULL;
+
+       kfree(mbox->dev);
+       mbox->dev = NULL;
+}
+EXPORT_SYMBOL(otx2_mbox_destroy);
+
+int otx2_mbox_init(struct otx2_mbox *mbox, void *hwbase, struct pci_dev *pdev,
+                  void *reg_base, int direction, int ndevs)
+{
+       struct otx2_mbox_dev *mdev;
+       int devid;
+
+       switch (direction) {
+       case MBOX_DIR_AFPF:
+       case MBOX_DIR_PFVF:
+               mbox->tx_start = MBOX_DOWN_TX_START;
+               mbox->rx_start = MBOX_DOWN_RX_START;
+               mbox->tx_size  = MBOX_DOWN_TX_SIZE;
+               mbox->rx_size  = MBOX_DOWN_RX_SIZE;
+               break;
+       case MBOX_DIR_PFAF:
+       case MBOX_DIR_VFPF:
+               mbox->tx_start = MBOX_DOWN_RX_START;
+               mbox->rx_start = MBOX_DOWN_TX_START;
+               mbox->tx_size  = MBOX_DOWN_RX_SIZE;
+               mbox->rx_size  = MBOX_DOWN_TX_SIZE;
+               break;
+       case MBOX_DIR_AFPF_UP:
+       case MBOX_DIR_PFVF_UP:
+               mbox->tx_start = MBOX_UP_TX_START;
+               mbox->rx_start = MBOX_UP_RX_START;
+               mbox->tx_size  = MBOX_UP_TX_SIZE;
+               mbox->rx_size  = MBOX_UP_RX_SIZE;
+               break;
+       case MBOX_DIR_PFAF_UP:
+       case MBOX_DIR_VFPF_UP:
+               mbox->tx_start = MBOX_UP_RX_START;
+               mbox->rx_start = MBOX_UP_TX_START;
+               mbox->tx_size  = MBOX_UP_RX_SIZE;
+               mbox->rx_size  = MBOX_UP_TX_SIZE;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       switch (direction) {
+       case MBOX_DIR_AFPF:
+       case MBOX_DIR_AFPF_UP:
+               mbox->trigger = RVU_AF_AFPF_MBOX0;
+               mbox->tr_shift = 4;
+               break;
+       case MBOX_DIR_PFAF:
+       case MBOX_DIR_PFAF_UP:
+               mbox->trigger = RVU_PF_PFAF_MBOX1;
+               mbox->tr_shift = 0;
+               break;
+       case MBOX_DIR_PFVF:
+       case MBOX_DIR_PFVF_UP:
+               mbox->trigger = RVU_PF_VFX_PFVF_MBOX0;
+               mbox->tr_shift = 12;
+               break;
+       case MBOX_DIR_VFPF:
+       case MBOX_DIR_VFPF_UP:
+               mbox->trigger = RVU_VF_VFPF_MBOX1;
+               mbox->tr_shift = 0;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       mbox->reg_base = reg_base;
+       mbox->hwbase = hwbase;
+       mbox->pdev = pdev;
+
+       mbox->dev = kcalloc(ndevs, sizeof(struct otx2_mbox_dev), GFP_KERNEL);
+       if (!mbox->dev) {
+               otx2_mbox_destroy(mbox);
+               return -ENOMEM;
+       }
+
+       mbox->ndevs = ndevs;
+       for (devid = 0; devid < ndevs; devid++) {
+               mdev = &mbox->dev[devid];
+               mdev->mbase = mbox->hwbase + (devid * MBOX_SIZE);
+               spin_lock_init(&mdev->mbox_lock);
+               /* Init header to reset value */
+               otx2_mbox_reset(mbox, devid);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(otx2_mbox_init);
+
+int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid)
+{
+       struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+       int timeout = 0, sleep = 1;
+
+       while (mdev->num_msgs != mdev->msgs_acked) {
+               msleep(sleep);
+               timeout += sleep;
+               if (timeout >= MBOX_RSP_TIMEOUT)
+                       return -EIO;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(otx2_mbox_wait_for_rsp);
+
+int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid)
+{
+       struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+       unsigned long timeout = jiffies + 1 * HZ;
+
+       while (!time_after(jiffies, timeout)) {
+               if (mdev->num_msgs == mdev->msgs_acked)
+                       return 0;
+               cpu_relax();
+       }
+       return -EIO;
+}
+EXPORT_SYMBOL(otx2_mbox_busy_poll_for_rsp);
+
+void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
+{
+       struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+       struct mbox_hdr *tx_hdr, *rx_hdr;
+
+       tx_hdr = mdev->mbase + mbox->tx_start;
+       rx_hdr = mdev->mbase + mbox->rx_start;
+
+       spin_lock(&mdev->mbox_lock);
+       /* Reset header for next messages */
+       mdev->msg_size = 0;
+       mdev->rsp_size = 0;
+       mdev->msgs_acked = 0;
+
+       /* Sync mbox data into memory */
+       smp_wmb();
+
+       /* num_msgs != 0 signals to the peer that the buffer has a number of
+        * messages.  So this should be written after writing all the messages
+        * to the shared memory.
+        */
+       tx_hdr->num_msgs = mdev->num_msgs;
+       rx_hdr->num_msgs = 0;
+       spin_unlock(&mdev->mbox_lock);
+
+       /* The interrupt should be fired after num_msgs is written
+        * to the shared memory
+        */
+       writeq(1, (void __iomem *)mbox->reg_base +
+              (mbox->trigger | (devid << mbox->tr_shift)));
+}
+EXPORT_SYMBOL(otx2_mbox_msg_send);
+
+struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid,
+                                           int size, int size_rsp)
+{
+       struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+       struct mbox_msghdr *msghdr = NULL;
+
+       spin_lock(&mdev->mbox_lock);
+       size = ALIGN(size, MBOX_MSG_ALIGN);
+       size_rsp = ALIGN(size_rsp, MBOX_MSG_ALIGN);
+       /* Check if there is space in mailbox */
+       if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset)
+               goto exit;
+       if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset)
+               goto exit;
+
+       if (mdev->msg_size == 0)
+               mdev->num_msgs = 0;
+       mdev->num_msgs++;
+
+       msghdr = mdev->mbase + mbox->tx_start + msgs_offset + mdev->msg_size;
+
+       /* Clear the whole msg region */
+       memset(msghdr, 0, sizeof(*msghdr) + size);
+       /* Init message header with reset values */
+       msghdr->ver = OTX2_MBOX_VERSION;
+       mdev->msg_size += size;
+       mdev->rsp_size += size_rsp;
+       msghdr->next_msgoff = mdev->msg_size + msgs_offset;
+exit:
+       spin_unlock(&mdev->mbox_lock);
+
+       return msghdr;
+}
+EXPORT_SYMBOL(otx2_mbox_alloc_msg_rsp);
+
+struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid,
+                                     struct mbox_msghdr *msg)
+{
+       unsigned long imsg = mbox->tx_start + msgs_offset;
+       unsigned long irsp = mbox->rx_start + msgs_offset;
+       struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+       u16 msgs;
+
+       if (mdev->num_msgs != mdev->msgs_acked)
+               return ERR_PTR(-ENODEV);
+
+       for (msgs = 0; msgs < mdev->msgs_acked; msgs++) {
+               struct mbox_msghdr *pmsg = mdev->mbase + imsg;
+               struct mbox_msghdr *prsp = mdev->mbase + irsp;
+
+               if (msg == pmsg) {
+                       if (pmsg->id != prsp->id)
+                               return ERR_PTR(-ENODEV);
+                       return prsp;
+               }
+
+               imsg = pmsg->next_msgoff;
+               irsp = prsp->next_msgoff;
+       }
+
+       return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL(otx2_mbox_get_rsp);
+
+int
+otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, u16 pcifunc, u16 id)
+{
+       struct msg_rsp *rsp;
+
+       rsp = (struct msg_rsp *)
+              otx2_mbox_alloc_msg(mbox, devid, sizeof(*rsp));
+       if (!rsp)
+               return -ENOMEM;
+       rsp->hdr.id = id;
+       rsp->hdr.sig = OTX2_MBOX_RSP_SIG;
+       rsp->hdr.rc = MBOX_MSG_INVALID;
+       rsp->hdr.pcifunc = pcifunc;
+       return 0;
+}
+EXPORT_SYMBOL(otx2_reply_invalid_msg);
+
+bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid)
+{
+       struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+       bool ret;
+
+       spin_lock(&mdev->mbox_lock);
+       ret = mdev->num_msgs != 0;
+       spin_unlock(&mdev->mbox_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(otx2_mbox_nonempty);
+
+const char *otx2_mbox_id2name(u16 id)
+{
+       switch (id) {
+#define M(_name, _id, _1, _2) case _id: return # _name;
+       MBOX_MESSAGES
+#undef M
+       default:
+               return "INVALID ID";
+       }
+}
+EXPORT_SYMBOL(otx2_mbox_id2name);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
new file mode 100644 (file)
index 0000000..8e205fd
--- /dev/null
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MBOX_H
+#define MBOX_H
+
+#include <linux/etherdevice.h>
+#include <linux/sizes.h>
+
+#include "rvu_struct.h"
+
+#define MBOX_SIZE              SZ_64K
+
+/* AF/PF: PF initiated, PF/VF VF initiated */
+#define MBOX_DOWN_RX_START     0
+#define MBOX_DOWN_RX_SIZE      (46 * SZ_1K)
+#define MBOX_DOWN_TX_START     (MBOX_DOWN_RX_START + MBOX_DOWN_RX_SIZE)
+#define MBOX_DOWN_TX_SIZE      (16 * SZ_1K)
+/* AF/PF: AF initiated, PF/VF PF initiated */
+#define MBOX_UP_RX_START       (MBOX_DOWN_TX_START + MBOX_DOWN_TX_SIZE)
+#define MBOX_UP_RX_SIZE                SZ_1K
+#define MBOX_UP_TX_START       (MBOX_UP_RX_START + MBOX_UP_RX_SIZE)
+#define MBOX_UP_TX_SIZE                SZ_1K
+
+#if MBOX_UP_TX_SIZE + MBOX_UP_TX_START != MBOX_SIZE
+# error "incorrect mailbox area sizes"
+#endif
+
+#define MBOX_RSP_TIMEOUT       1000 /* in ms, Time to wait for mbox response */
+
+#define MBOX_MSG_ALIGN         16  /* Align mbox msg start to 16bytes */
+
+/* Mailbox directions */
+#define MBOX_DIR_AFPF          0  /* AF replies to PF */
+#define MBOX_DIR_PFAF          1  /* PF sends messages to AF */
+#define MBOX_DIR_PFVF          2  /* PF replies to VF */
+#define MBOX_DIR_VFPF          3  /* VF sends messages to PF */
+#define MBOX_DIR_AFPF_UP       4  /* AF sends messages to PF */
+#define MBOX_DIR_PFAF_UP       5  /* PF replies to AF */
+#define MBOX_DIR_PFVF_UP       6  /* PF sends messages to VF */
+#define MBOX_DIR_VFPF_UP       7  /* VF replies to PF */
+
+struct otx2_mbox_dev {
+       void        *mbase;   /* This dev's mbox region */
+       spinlock_t  mbox_lock;
+       u16         msg_size; /* Total msg size to be sent */
+       u16         rsp_size; /* Total rsp size to be sure the reply is ok */
+       u16         num_msgs; /* No of msgs sent or waiting for response */
+       u16         msgs_acked; /* No of msgs for which response is received */
+};
+
+struct otx2_mbox {
+       struct pci_dev *pdev;
+       void   *hwbase;  /* Mbox region advertised by HW */
+       void   *reg_base;/* CSR base for this dev */
+       u64    trigger;  /* Trigger mbox notification */
+       u16    tr_shift; /* Mbox trigger shift */
+       u64    rx_start; /* Offset of Rx region in mbox memory */
+       u64    tx_start; /* Offset of Tx region in mbox memory */
+       u16    rx_size;  /* Size of Rx region */
+       u16    tx_size;  /* Size of Tx region */
+       u16    ndevs;    /* The number of peers */
+       struct otx2_mbox_dev *dev;
+};
+
+/* Header which preceeds all mbox messages */
+struct mbox_hdr {
+       u16  num_msgs;   /* No of msgs embedded */
+};
+
+/* Header which preceeds every msg and is also part of it */
+struct mbox_msghdr {
+       u16 pcifunc;     /* Who's sending this msg */
+       u16 id;          /* Mbox message ID */
+#define OTX2_MBOX_REQ_SIG (0xdead)
+#define OTX2_MBOX_RSP_SIG (0xbeef)
+       u16 sig;         /* Signature, for validating corrupted msgs */
+#define OTX2_MBOX_VERSION (0x0001)
+       u16 ver;         /* Version of msg's structure for this ID */
+       u16 next_msgoff; /* Offset of next msg within mailbox region */
+       int rc;          /* Msg process'ed response code */
+};
+
+void otx2_mbox_reset(struct otx2_mbox *mbox, int devid);
+void otx2_mbox_destroy(struct otx2_mbox *mbox);
+int otx2_mbox_init(struct otx2_mbox *mbox, void *hwbase, struct pci_dev *pdev,
+                  void *reg_base, int direction, int ndevs);
+void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid);
+int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid);
+int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid);
+struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid,
+                                           int size, int size_rsp);
+struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid,
+                                     struct mbox_msghdr *msg);
+int otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid,
+                          u16 pcifunc, u16 id);
+bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid);
+const char *otx2_mbox_id2name(u16 id);
+static inline struct mbox_msghdr *otx2_mbox_alloc_msg(struct otx2_mbox *mbox,
+                                                     int devid, int size)
+{
+       return otx2_mbox_alloc_msg_rsp(mbox, devid, size, 0);
+}
+
+/* Mailbox message types */
+#define MBOX_MSG_MASK                          0xFFFF
+#define MBOX_MSG_INVALID                       0xFFFE
+#define MBOX_MSG_MAX                           0xFFFF
+
+#define MBOX_MESSAGES                                                  \
+M(READY,               0x001, msg_req, msg_rsp)
+
+enum {
+#define M(_name, _id, _1, _2) MBOX_MSG_ ## _name = _id,
+MBOX_MESSAGES
+#undef M
+};
+
+/* Mailbox message formats */
+
+/* Generic request msg used for those mbox messages which
+ * don't send any data in the request.
+ */
+struct msg_req {
+       struct mbox_msghdr hdr;
+};
+
+/* Generic rsponse msg used a ack or response for those mbox
+ * messages which doesn't have a specific rsp msg format.
+ */
+struct msg_rsp {
+       struct mbox_msghdr hdr;
+};
+
+#endif /* MBOX_H */
index bbeed77ea2fdc4b6b95387a2604dd6595f03b5ae..0d69ec0c03f00f024024e5e8b3158f7fc43665ea 100644 (file)
 #define RVU_PF_MSIX_VECX_CTL(a)             (0x008 | (a) << 4)
 #define RVU_PF_MSIX_PBAX(a)                 (0xF0000 | (a) << 3)
 
+/* RVU VF registers */
+#define        RVU_VF_VFPF_MBOX0                   (0x00000)
+#define        RVU_VF_VFPF_MBOX1                   (0x00008)
+
 /* NPA block's admin function registers */
 #define NPA_AF_BLK_RST                  (0x0000)
 #define NPA_AF_CONST                    (0x0010)