nfp: NSP backend for link configuration operations
authorJakub Kicinski <jakub.kicinski@netronome.com>
Tue, 4 Apr 2017 23:12:34 +0000 (16:12 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 5 Apr 2017 17:49:12 +0000 (10:49 -0700)
Add NSP backend for upcoming link configuration operations.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c

index 96bb5f6bd87b81e47781ce0b51de8897f58cbe00..4635f42e15b005dd66ff5503f7c369160c0827b0 100644 (file)
@@ -101,7 +101,11 @@ static const struct {
        int code;
        const char *msg;
 } nsp_errors[] = {
-       { 0, "success" } /* placeholder to avoid warnings */
+       { 6010, "could not map to phy for port" },
+       { 6011, "not an allowed rate/lanes for port" },
+       { 6012, "not an allowed rate/lanes for port" },
+       { 6013, "high/low error, change other port first" },
+       { 6014, "config not found in flash" },
 };
 
 struct nfp_nsp {
index c452ad3119930968bb69da88ef538f08eefc47b7..7d34ff145fd7c85ec45272e42c32af576076b98f 100644 (file)
@@ -134,10 +134,17 @@ struct nfp_eth_table {
 struct nfp_eth_table *nfp_eth_read_ports(struct nfp_cpp *cpp);
 struct nfp_eth_table *
 __nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp);
+
 int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable);
+int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx,
+                          bool configed);
 
 struct nfp_nsp *nfp_eth_config_start(struct nfp_cpp *cpp, unsigned int idx);
 int nfp_eth_config_commit_end(struct nfp_nsp *nsp);
 void nfp_eth_config_cleanup_end(struct nfp_nsp *nsp);
 
+int __nfp_eth_set_aneg(struct nfp_nsp *nsp, enum nfp_eth_aneg mode);
+int __nfp_eth_set_speed(struct nfp_nsp *nsp, unsigned int speed);
+int __nfp_eth_set_split(struct nfp_nsp *nsp, unsigned int lanes);
+
 #endif
index ca5c041e64a46aa6e72fbb554a55f8105cd4dfdc..639438d8313afc558d53233b6da7ab20c26417c0 100644 (file)
@@ -58,6 +58,7 @@
 
 #define NSP_ETH_PORT_LANES_MASK                cpu_to_le64(NSP_ETH_PORT_LANES)
 
+#define NSP_ETH_STATE_CONFIGURED       BIT_ULL(0)
 #define NSP_ETH_STATE_ENABLED          BIT_ULL(1)
 #define NSP_ETH_STATE_TX_ENABLED       BIT_ULL(2)
 #define NSP_ETH_STATE_RX_ENABLED       BIT_ULL(3)
 #define NSP_ETH_STATE_OVRD_CHNG                BIT_ULL(22)
 #define NSP_ETH_STATE_ANEG             GENMASK_ULL(25, 23)
 
+#define NSP_ETH_CTRL_CONFIGURED                BIT_ULL(0)
 #define NSP_ETH_CTRL_ENABLED           BIT_ULL(1)
 #define NSP_ETH_CTRL_TX_ENABLED                BIT_ULL(2)
 #define NSP_ETH_CTRL_RX_ENABLED                BIT_ULL(3)
+#define NSP_ETH_CTRL_SET_RATE          BIT_ULL(4)
+#define NSP_ETH_CTRL_SET_LANES         BIT_ULL(5)
+#define NSP_ETH_CTRL_SET_ANEG          BIT_ULL(6)
 
 enum nfp_eth_raw {
        NSP_ETH_RAW_PORT = 0,
@@ -100,21 +105,38 @@ union eth_table_entry {
        __le64 raw[NSP_ETH_NUM_RAW];
 };
 
-static unsigned int nfp_eth_rate(enum nfp_eth_rate rate)
+static const struct {
+       enum nfp_eth_rate rate;
+       unsigned int speed;
+} nsp_eth_rate_tbl[] = {
+       { RATE_INVALID, 0, },
+       { RATE_10M,     SPEED_10, },
+       { RATE_100M,    SPEED_100, },
+       { RATE_1G,      SPEED_1000, },
+       { RATE_10G,     SPEED_10000, },
+       { RATE_25G,     SPEED_25000, },
+};
+
+static unsigned int nfp_eth_rate2speed(enum nfp_eth_rate rate)
 {
-       unsigned int rate_xlate[] = {
-               [RATE_INVALID]          = 0,
-               [RATE_10M]              = SPEED_10,
-               [RATE_100M]             = SPEED_100,
-               [RATE_1G]               = SPEED_1000,
-               [RATE_10G]              = SPEED_10000,
-               [RATE_25G]              = SPEED_25000,
-       };
+       int i;
 
-       if (rate >= ARRAY_SIZE(rate_xlate))
-               return 0;
+       for (i = 0; i < ARRAY_SIZE(nsp_eth_rate_tbl); i++)
+               if (nsp_eth_rate_tbl[i].rate == rate)
+                       return nsp_eth_rate_tbl[i].speed;
+
+       return 0;
+}
+
+static unsigned int nfp_eth_speed2rate(unsigned int speed)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(nsp_eth_rate_tbl); i++)
+               if (nsp_eth_rate_tbl[i].speed == speed)
+                       return nsp_eth_rate_tbl[i].rate;
 
-       return rate_xlate[rate];
+       return RATE_INVALID;
 }
 
 static void nfp_eth_copy_mac_reverse(u8 *dst, const u8 *src)
@@ -145,7 +167,7 @@ nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src,
        dst->tx_enabled = FIELD_GET(NSP_ETH_STATE_TX_ENABLED, state);
        dst->rx_enabled = FIELD_GET(NSP_ETH_STATE_RX_ENABLED, state);
 
-       rate = nfp_eth_rate(FIELD_GET(NSP_ETH_STATE_RATE, state));
+       rate = nfp_eth_rate2speed(FIELD_GET(NSP_ETH_STATE_RATE, state));
        dst->speed = dst->lanes * rate;
 
        dst->interface = FIELD_GET(NSP_ETH_STATE_INTERFACE, state);
@@ -392,3 +414,135 @@ int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable)
 
        return nfp_eth_config_commit_end(nsp);
 }
+
+/**
+ * nfp_eth_set_configured() - set PHY module configured control bit
+ * @cpp:       NFP CPP handle
+ * @idx:       NFP chip-wide port index
+ * @configed:  Desired state
+ *
+ * Set the ifup/ifdown state on the PHY.
+ *
+ * Return: 0 or -ERRNO.
+ */
+int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx, bool configed)
+{
+       union eth_table_entry *entries;
+       struct nfp_nsp *nsp;
+       u64 reg;
+
+       nsp = nfp_eth_config_start(cpp, idx);
+       if (IS_ERR(nsp))
+               return PTR_ERR(nsp);
+
+       entries = nfp_nsp_config_entries(nsp);
+
+       /* Check if we are already in requested state */
+       reg = le64_to_cpu(entries[idx].state);
+       if (configed != FIELD_GET(NSP_ETH_STATE_CONFIGURED, reg)) {
+               reg = le64_to_cpu(entries[idx].control);
+               reg &= ~NSP_ETH_CTRL_CONFIGURED;
+               reg |= FIELD_PREP(NSP_ETH_CTRL_CONFIGURED, configed);
+               entries[idx].control = cpu_to_le64(reg);
+
+               nfp_nsp_config_set_modified(nsp, true);
+       }
+
+       return nfp_eth_config_commit_end(nsp);
+}
+
+/* Force inline, FIELD_* macroes require masks to be compilation-time known */
+static __always_inline int
+nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx,
+                      const u64 mask, unsigned int val, const u64 ctrl_bit)
+{
+       union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
+       unsigned int idx = nfp_nsp_config_idx(nsp);
+       u64 reg;
+
+       /* Note: set features were added in ABI 0.14 but the error
+        *       codes were initially not populated correctly.
+        */
+       if (nfp_nsp_get_abi_ver_minor(nsp) < 17) {
+               nfp_err(nfp_nsp_cpp(nsp),
+                       "set operations not supported, please update flash\n");
+               return -EOPNOTSUPP;
+       }
+
+       /* Check if we are already in requested state */
+       reg = le64_to_cpu(entries[idx].raw[raw_idx]);
+       if (val == FIELD_GET(mask, reg))
+               return 0;
+
+       reg &= ~mask;
+       reg |= FIELD_PREP(mask, val);
+       entries[idx].raw[raw_idx] = cpu_to_le64(reg);
+
+       entries[idx].control |= cpu_to_le64(ctrl_bit);
+
+       nfp_nsp_config_set_modified(nsp, true);
+
+       return 0;
+}
+
+/**
+ * __nfp_eth_set_aneg() - set PHY autonegotiation control bit
+ * @nsp:       NFP NSP handle returned from nfp_eth_config_start()
+ * @mode:      Desired autonegotiation mode
+ *
+ * Allow/disallow PHY module to advertise/perform autonegotiation.
+ * Will write to hwinfo overrides in the flash (persistent config).
+ *
+ * Return: 0 or -ERRNO.
+ */
+int __nfp_eth_set_aneg(struct nfp_nsp *nsp, enum nfp_eth_aneg mode)
+{
+       return nfp_eth_set_bit_config(nsp, NSP_ETH_RAW_STATE,
+                                     NSP_ETH_STATE_ANEG, mode,
+                                     NSP_ETH_CTRL_SET_ANEG);
+}
+
+/**
+ * __nfp_eth_set_speed() - set interface speed/rate
+ * @nsp:       NFP NSP handle returned from nfp_eth_config_start()
+ * @speed:     Desired speed (per lane)
+ *
+ * Set lane speed.  Provided @speed value should be subport speed divided
+ * by number of lanes this subport is spanning (i.e. 10000 for 40G, 25000 for
+ * 50G, etc.)
+ * Will write to hwinfo overrides in the flash (persistent config).
+ *
+ * Return: 0 or -ERRNO.
+ */
+int __nfp_eth_set_speed(struct nfp_nsp *nsp, unsigned int speed)
+{
+       enum nfp_eth_rate rate;
+
+       rate = nfp_eth_speed2rate(speed);
+       if (rate == RATE_INVALID) {
+               nfp_warn(nfp_nsp_cpp(nsp),
+                        "could not find matching lane rate for speed %u\n",
+                        speed);
+               return -EINVAL;
+       }
+
+       return nfp_eth_set_bit_config(nsp, NSP_ETH_RAW_STATE,
+                                     NSP_ETH_STATE_RATE, rate,
+                                     NSP_ETH_CTRL_SET_RATE);
+}
+
+/**
+ * __nfp_eth_set_split() - set interface lane split
+ * @nsp:       NFP NSP handle returned from nfp_eth_config_start()
+ * @lanes:     Desired lanes per port
+ *
+ * Set number of lanes in the port.
+ * Will write to hwinfo overrides in the flash (persistent config).
+ *
+ * Return: 0 or -ERRNO.
+ */
+int __nfp_eth_set_split(struct nfp_nsp *nsp, unsigned int lanes)
+{
+       return nfp_eth_set_bit_config(nsp, NSP_ETH_RAW_PORT, NSP_ETH_PORT_LANES,
+                                     lanes, NSP_ETH_CTRL_SET_LANES);
+}