net/cxgbe: add VF firmware mailbox
authorKumar Sanghvi <kumaras@chelsio.com>
Sat, 10 Mar 2018 22:48:20 +0000 (04:18 +0530)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 30 Mar 2018 12:08:44 +0000 (14:08 +0200)
Add firmware mailbox communication support for VF.  Add is_pf4()
to check if driver is attached to PF4.  Use is_pf4() to determine
whether to use PF or VF mailbox communication.

Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
drivers/net/cxgbe/Makefile
drivers/net/cxgbe/base/common.h
drivers/net/cxgbe/base/t4_hw.c
drivers/net/cxgbe/base/t4_regs.h
drivers/net/cxgbe/base/t4vf_hw.c [new file with mode: 0644]
drivers/net/cxgbe/base/t4vf_hw.h [new file with mode: 0644]

index 397977e..66c445e 100644 (file)
@@ -84,5 +84,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += cxgbevf_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += cxgbe_main.c
 SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += sge.c
 SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += t4_hw.c
+SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += t4vf_hw.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
index 365e9e6..b67cf0b 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "cxgbe_compat.h"
 #include "t4_hw.h"
+#include "t4vf_hw.h"
 #include "t4_chip_type.h"
 #include "t4fw_interface.h"
 
@@ -290,6 +291,11 @@ static inline int t4_wait_op_done(struct adapter *adapter, int reg, u32 mask,
                                   delay, NULL);
 }
 
+static inline int is_pf4(struct adapter *adap)
+{
+       return adap->pf == 4;
+}
+
 #define for_each_port(adapter, iter) \
        for (iter = 0; iter < (adapter)->params.nports; ++iter)
 
@@ -400,6 +406,21 @@ static inline int t4_wr_mbox_ns(struct adapter *adap, int mbox, const void *cmd,
        return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, false);
 }
 
+int t4vf_wr_mbox_core(struct adapter *, const void *, int, void *, bool);
+
+static inline int t4vf_wr_mbox(struct adapter *adapter, const void *cmd,
+                              int size, void *rpl)
+{
+       return t4vf_wr_mbox_core(adapter, cmd, size, rpl, true);
+}
+
+static inline int t4vf_wr_mbox_ns(struct adapter *adapter, const void *cmd,
+                                 int size, void *rpl)
+{
+       return t4vf_wr_mbox_core(adapter, cmd, size, rpl, false);
+}
+
+
 void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
                      unsigned int data_reg, u32 *vals, unsigned int nregs,
                      unsigned int start_idx);
index c66e2a6..8e2b8a7 100644 (file)
@@ -2342,7 +2342,11 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
                 * Send this portion of the RRS table update to the firmware;
                 * bail out on any errors.
                 */
-               ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL);
+               if (is_pf4(adapter))
+                       ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd),
+                                        NULL);
+               else
+                       ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
                if (ret)
                        return ret;
        }
@@ -2372,7 +2376,10 @@ int t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid,
        c.retval_len16 = cpu_to_be32(FW_LEN16(c));
        c.u.basicvirtual.defaultq_to_udpen = cpu_to_be32(flags |
                        V_FW_RSS_VI_CONFIG_CMD_DEFAULTQ(defq));
-       return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
+       if (is_pf4(adapter))
+               return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
+       else
+               return t4vf_wr_mbox(adapter, &c, sizeof(c), NULL);
 }
 
 /**
@@ -4082,12 +4089,17 @@ int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
 
        memset(&c, 0, sizeof(c));
        c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_VI_CMD) | F_FW_CMD_REQUEST |
-                                 F_FW_CMD_EXEC | V_FW_VI_CMD_PFN(pf) |
-                                 V_FW_VI_CMD_VFN(vf));
+                                 F_FW_CMD_EXEC);
+       if (is_pf4(adap))
+               c.op_to_vfn |= cpu_to_be32(V_FW_VI_CMD_PFN(pf) |
+                                          V_FW_VI_CMD_VFN(vf));
        c.alloc_to_len16 = cpu_to_be32(F_FW_VI_CMD_FREE | FW_LEN16(c));
        c.type_to_viid = cpu_to_be16(V_FW_VI_CMD_VIID(viid));
 
-       return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
+       if (is_pf4(adap))
+               return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
+       else
+               return t4vf_wr_mbox(adap, &c, sizeof(c), NULL);
 }
 
 /**
@@ -4133,7 +4145,11 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
                            V_FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) |
                            V_FW_VI_RXMODE_CMD_BROADCASTEN(bcast) |
                            V_FW_VI_RXMODE_CMD_VLANEXEN(vlanex));
-       return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
+       if (is_pf4(adap))
+               return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL,
+                                      sleep_ok);
+       else
+               return t4vf_wr_mbox(adap, &c, sizeof(c), NULL);
 }
 
 /**
@@ -4180,7 +4196,10 @@ int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
                                      V_FW_VI_MAC_CMD_IDX(idx));
        memcpy(p->macaddr, addr, sizeof(p->macaddr));
 
-       ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
+       if (is_pf4(adap))
+               ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
+       else
+               ret = t4vf_wr_mbox(adap, &c, sizeof(c), &c);
        if (ret == 0) {
                ret = G_FW_VI_MAC_CMD_IDX(be16_to_cpu(p->valid_to_idx));
                if (ret >= max_mac_addr)
@@ -4214,7 +4233,10 @@ int t4_enable_vi_params(struct adapter *adap, unsigned int mbox,
                                     V_FW_VI_ENABLE_CMD_EEN(tx_en) |
                                     V_FW_VI_ENABLE_CMD_DCB_INFO(dcb_en) |
                                     FW_LEN16(c));
-       return t4_wr_mbox_ns(adap, mbox, &c, sizeof(c), NULL);
+       if (is_pf4(adap))
+               return t4_wr_mbox_ns(adap, mbox, &c, sizeof(c), NULL);
+       else
+               return t4vf_wr_mbox_ns(adap, &c, sizeof(c), NULL);
 }
 
 /**
@@ -4255,15 +4277,20 @@ int t4_iq_start_stop(struct adapter *adap, unsigned int mbox, bool start,
 
        memset(&c, 0, sizeof(c));
        c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST |
-                                 F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) |
-                                 V_FW_IQ_CMD_VFN(vf));
+                                 F_FW_CMD_EXEC);
        c.alloc_to_len16 = cpu_to_be32(V_FW_IQ_CMD_IQSTART(start) |
                                       V_FW_IQ_CMD_IQSTOP(!start) |
                                       FW_LEN16(c));
        c.iqid = cpu_to_be16(iqid);
        c.fl0id = cpu_to_be16(fl0id);
        c.fl1id = cpu_to_be16(fl1id);
-       return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
+       if (is_pf4(adap)) {
+               c.op_to_vfn |= cpu_to_be32(V_FW_IQ_CMD_PFN(pf) |
+                                          V_FW_IQ_CMD_VFN(vf));
+               return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
+       } else {
+               return t4vf_wr_mbox(adap, &c, sizeof(c), NULL);
+       }
 }
 
 /**
@@ -4287,14 +4314,19 @@ int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
 
        memset(&c, 0, sizeof(c));
        c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST |
-                                 F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) |
-                                 V_FW_IQ_CMD_VFN(vf));
+                                 F_FW_CMD_EXEC);
+       if (is_pf4(adap))
+               c.op_to_vfn |= cpu_to_be32(V_FW_IQ_CMD_PFN(pf) |
+                                          V_FW_IQ_CMD_VFN(vf));
        c.alloc_to_len16 = cpu_to_be32(F_FW_IQ_CMD_FREE | FW_LEN16(c));
        c.type_to_iqandstindex = cpu_to_be32(V_FW_IQ_CMD_TYPE(iqtype));
        c.iqid = cpu_to_be16(iqid);
        c.fl0id = cpu_to_be16(fl0id);
        c.fl1id = cpu_to_be16(fl1id);
-       return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
+       if (is_pf4(adap))
+               return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
+       else
+               return t4vf_wr_mbox(adap, &c, sizeof(c), NULL);
 }
 
 /**
@@ -4314,12 +4346,16 @@ int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
 
        memset(&c, 0, sizeof(c));
        c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_EQ_ETH_CMD) |
-                                 F_FW_CMD_REQUEST | F_FW_CMD_EXEC |
-                                 V_FW_EQ_ETH_CMD_PFN(pf) |
-                                 V_FW_EQ_ETH_CMD_VFN(vf));
+                                 F_FW_CMD_REQUEST | F_FW_CMD_EXEC);
+       if (is_pf4(adap))
+               c.op_to_vfn |= cpu_to_be32(V_FW_IQ_CMD_PFN(pf) |
+                                          V_FW_IQ_CMD_VFN(vf));
        c.alloc_to_len16 = cpu_to_be32(F_FW_EQ_ETH_CMD_FREE | FW_LEN16(c));
        c.eqid_pkd = cpu_to_be32(V_FW_EQ_ETH_CMD_EQID(eqid));
-       return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
+       if (is_pf4(adap))
+               return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
+       else
+               return t4vf_wr_mbox(adap, &c, sizeof(c), NULL);
 }
 
 /**
index 0f0bca9..657d8a7 100644 (file)
 /* registers for module CIM */
 #define CIM_BASE_ADDR 0x7b00
 
+#define A_CIM_VF_EXT_MAILBOX_CTRL 0x0
+
 #define A_CIM_PF_MAILBOX_DATA 0x240
 #define A_CIM_PF_MAILBOX_CTRL 0x280
 
 #define V_UPCRST(x) ((x) << S_UPCRST)
 #define F_UPCRST    V_UPCRST(1U)
 
+#define NUM_CIM_PF_MAILBOX_DATA_INSTANCES 16
+
 /* registers for module TP */
 #define A_TP_OUT_CONFIG 0x7d04
 
diff --git a/drivers/net/cxgbe/base/t4vf_hw.c b/drivers/net/cxgbe/base/t4vf_hw.c
new file mode 100644 (file)
index 0000000..909659c
--- /dev/null
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Chelsio Communications.
+ * All rights reserved.
+ */
+
+#include <rte_ethdev_driver.h>
+#include <rte_ether.h>
+
+#include "common.h"
+#include "t4_regs.h"
+
+/*
+ * Get the reply to a mailbox command and store it in @rpl in big-endian order.
+ */
+static void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit,
+                        u32 mbox_addr)
+{
+       for ( ; nflit; nflit--, mbox_addr += 8)
+               *rpl++ = htobe64(t4_read_reg64(adap, mbox_addr));
+}
+
+/**
+ * t4vf_wr_mbox_core - send a command to FW through the mailbox
+ * @adapter: the adapter
+ * @cmd: the command to write
+ * @size: command length in bytes
+ * @rpl: where to optionally store the reply
+ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Sends the given command to FW through the mailbox and waits for the
+ * FW to execute the command.  If @rpl is not %NULL it is used to store
+ * the FW's reply to the command.  The command and its optional reply
+ * are of the same length.  FW can take up to 500 ms to respond.
+ * @sleep_ok determines whether we may sleep while awaiting the response.
+ * If sleeping is allowed we use progressive backoff otherwise we spin.
+ *
+ * The return value is 0 on success or a negative errno on failure.  A
+ * failure can happen either because we are not able to execute the
+ * command or FW executes it but signals an error.  In the latter case
+ * the return value is the error code indicated by FW (negated).
+ */
+int t4vf_wr_mbox_core(struct adapter *adapter,
+                     const void __attribute__((__may_alias__)) *cmd,
+                     int size, void *rpl, bool sleep_ok)
+{
+       /*
+        * We delay in small increments at first in an effort to maintain
+        * responsiveness for simple, fast executing commands but then back
+        * off to larger delays to a maximum retry delay.
+        */
+       static const int delay[] = {
+               1, 1, 3, 5, 10, 10, 20, 50, 100
+       };
+
+
+       u32 mbox_ctl = T4VF_CIM_BASE_ADDR + A_CIM_VF_EXT_MAILBOX_CTRL;
+       __be64 cmd_rpl[MBOX_LEN / 8];
+       struct mbox_entry entry;
+       unsigned int delay_idx;
+       u32 v, mbox_data;
+       const __be64 *p;
+       int i, ret;
+       int ms;
+
+       /* In T6, mailbox size is changed to 128 bytes to avoid
+        * invalidating the entire prefetch buffer.
+        */
+       if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
+               mbox_data = T4VF_MBDATA_BASE_ADDR;
+       else
+               mbox_data = T6VF_MBDATA_BASE_ADDR;
+
+       /*
+        * Commands must be multiples of 16 bytes in length and may not be
+        * larger than the size of the Mailbox Data register array.
+        */
+       if ((size % 16) != 0 ||
+                       size > NUM_CIM_VF_MAILBOX_DATA_INSTANCES * 4)
+               return -EINVAL;
+
+       /*
+        * Queue ourselves onto the mailbox access list.  When our entry is at
+        * the front of the list, we have rights to access the mailbox.  So we
+        * wait [for a while] till we're at the front [or bail out with an
+        * EBUSY] ...
+        */
+       t4_os_atomic_add_tail(&entry, &adapter->mbox_list, &adapter->mbox_lock);
+
+       delay_idx = 0;
+       ms = delay[0];
+
+       for (i = 0; ; i += ms) {
+               /*
+                * If we've waited too long, return a busy indication.  This
+                * really ought to be based on our initial position in the
+                * mailbox access list but this is a start.  We very rarely
+                * contend on access to the mailbox ...
+                */
+               if (i > (2 * FW_CMD_MAX_TIMEOUT)) {
+                       t4_os_atomic_list_del(&entry, &adapter->mbox_list,
+                                             &adapter->mbox_lock);
+                       ret = -EBUSY;
+                       return ret;
+               }
+
+               /*
+                * If we're at the head, break out and start the mailbox
+                * protocol.
+                */
+               if (t4_os_list_first_entry(&adapter->mbox_list) == &entry)
+                       break;
+
+               /*
+                * Delay for a bit before checking again ...
+                */
+               if (sleep_ok) {
+                       ms = delay[delay_idx];  /* last element may repeat */
+                       if (delay_idx < ARRAY_SIZE(delay) - 1)
+                               delay_idx++;
+                       msleep(ms);
+               } else {
+                       rte_delay_ms(ms);
+               }
+       }
+
+       /*
+        * Loop trying to get ownership of the mailbox.  Return an error
+        * if we can't gain ownership.
+        */
+       v = G_MBOWNER(t4_read_reg(adapter, mbox_ctl));
+       for (i = 0; v == X_MBOWNER_NONE && i < 3; i++)
+               v = G_MBOWNER(t4_read_reg(adapter, mbox_ctl));
+
+       if (v != X_MBOWNER_PL) {
+               t4_os_atomic_list_del(&entry, &adapter->mbox_list,
+                                     &adapter->mbox_lock);
+               ret = (v == X_MBOWNER_FW) ? -EBUSY : -ETIMEDOUT;
+               return ret;
+       }
+
+       /*
+        * Write the command array into the Mailbox Data register array and
+        * transfer ownership of the mailbox to the firmware.
+        */
+       for (i = 0, p = cmd; i < size; i += 8)
+               t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++));
+
+       t4_read_reg(adapter, mbox_data);          /* flush write */
+       t4_write_reg(adapter, mbox_ctl,
+                       F_MBMSGVALID | V_MBOWNER(X_MBOWNER_FW));
+       t4_read_reg(adapter, mbox_ctl);          /* flush write */
+       delay_idx = 0;
+       ms = delay[0];
+
+       /*
+        * Spin waiting for firmware to acknowledge processing our command.
+        */
+       for (i = 0; i < FW_CMD_MAX_TIMEOUT; i++) {
+               if (sleep_ok) {
+                       ms = delay[delay_idx];  /* last element may repeat */
+                       if (delay_idx < ARRAY_SIZE(delay) - 1)
+                               delay_idx++;
+                       msleep(ms);
+               } else {
+                       rte_delay_ms(ms);
+               }
+
+               /*
+                * If we're the owner, see if this is the reply we wanted.
+                */
+               v = t4_read_reg(adapter, mbox_ctl);
+               if (G_MBOWNER(v) == X_MBOWNER_PL) {
+                       /*
+                        * If the Message Valid bit isn't on, revoke ownership
+                        * of the mailbox and continue waiting for our reply.
+                        */
+                       if ((v & F_MBMSGVALID) == 0) {
+                               t4_write_reg(adapter, mbox_ctl,
+                                            V_MBOWNER(X_MBOWNER_NONE));
+                               continue;
+                       }
+
+                       /*
+                        * We now have our reply.  Extract the command return
+                        * value, copy the reply back to our caller's buffer
+                        * (if specified) and revoke ownership of the mailbox.
+                        * We return the (negated) firmware command return
+                        * code (this depends on FW_SUCCESS == 0).  (Again we
+                        * avoid clogging the log with FW_VI_STATS_CMD
+                        * reply results.)
+                        */
+
+                       /*
+                        * Retrieve the command reply and release the mailbox.
+                        */
+                       get_mbox_rpl(adapter, cmd_rpl, size / 8, mbox_data);
+                       t4_write_reg(adapter, mbox_ctl,
+                                    V_MBOWNER(X_MBOWNER_NONE));
+                       t4_os_atomic_list_del(&entry, &adapter->mbox_list,
+                                             &adapter->mbox_lock);
+
+                       /* return value in high-order host-endian word */
+                       v = be64_to_cpu(cmd_rpl[0]);
+
+                       if (rpl) {
+                               /* request bit in high-order BE word */
+                               WARN_ON((be32_to_cpu(*(const u32 *)cmd)
+                                        & F_FW_CMD_REQUEST) == 0);
+                               memcpy(rpl, cmd_rpl, size);
+                       }
+                       return -((int)G_FW_CMD_RETVAL(v));
+               }
+       }
+
+       /*
+        * We timed out.  Return the error ...
+        */
+       dev_err(adapter, "command %#x timed out\n",
+               *(const u8 *)cmd);
+       dev_err(adapter, "    Control = %#x\n", t4_read_reg(adapter, mbox_ctl));
+       t4_os_atomic_list_del(&entry, &adapter->mbox_list, &adapter->mbox_lock);
+       ret = -ETIMEDOUT;
+       return ret;
+}
diff --git a/drivers/net/cxgbe/base/t4vf_hw.h b/drivers/net/cxgbe/base/t4vf_hw.h
new file mode 100644 (file)
index 0000000..d16b452
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Chelsio Communications.
+ * All rights reserved.
+ */
+
+#ifndef __T4VF_HW_H
+#define __T4VF_HW_H
+
+#define T4VF_CIM_BASE_ADDR     0x0300
+#define T4VF_MBDATA_BASE_ADDR  0x0240
+#define T6VF_MBDATA_BASE_ADDR  0x0280
+
+#define NUM_CIM_VF_MAILBOX_DATA_INSTANCES NUM_CIM_PF_MAILBOX_DATA_INSTANCES
+#endif /* __T4VF_HW_H */