From 08e21af90d17f8736e01764c2da41d559608b9d9 Mon Sep 17 00:00:00 2001 From: Kumar Sanghvi Date: Wed, 28 Feb 2018 23:34:48 +0530 Subject: [PATCH] net/cxgbe: support updating RSS hash configuration and key Add firmware API for updating RSS hash configuration and key. Move RSS hash configuration from cxgb4_write_rss() to a separate function cxgbe_write_rss_conf(). Also, rename cxgb4_write_rss() to cxgbe_write_rss() for consistency. Original work by Surendra Mobiya Signed-off-by: Kumar Sanghvi Signed-off-by: Rahul Lakkireddy --- doc/guides/nics/cxgbe.rst | 2 + doc/guides/nics/features/cxgbe.ini | 1 + doc/guides/rel_notes/release_18_05.rst | 4 ++ drivers/net/cxgbe/base/adapter.h | 4 +- drivers/net/cxgbe/base/common.h | 3 + drivers/net/cxgbe/base/t4_hw.c | 73 ++++++++++++++++++++ drivers/net/cxgbe/base/t4_regs.h | 25 +++++++ drivers/net/cxgbe/base/t4fw_interface.h | 89 +++++++++++++++++++++++++ drivers/net/cxgbe/cxgbe.h | 7 ++ drivers/net/cxgbe/cxgbe_ethdev.c | 33 +++++++++ drivers/net/cxgbe/cxgbe_main.c | 83 ++++++++++++++++++----- 11 files changed, 306 insertions(+), 18 deletions(-) diff --git a/doc/guides/nics/cxgbe.rst b/doc/guides/nics/cxgbe.rst index 8651a7be60..6126167c57 100644 --- a/doc/guides/nics/cxgbe.rst +++ b/doc/guides/nics/cxgbe.rst @@ -45,6 +45,8 @@ CXGBE PMD has support for: - Multiple queues for TX and RX - Receiver Side Steering (RSS) + Receiver Side Steering (RSS) on IPv4, IPv6, IPv4-TCP/UDP, IPv6-TCP/UDP. + For 4-tuple, enabling 'RSS on TCP' and 'RSS on TCP + UDP' is supported. - VLAN filtering - Checksum offload - Promiscuous mode diff --git a/doc/guides/nics/features/cxgbe.ini b/doc/guides/nics/features/cxgbe.ini index 1b9d81ffb6..6cf5c13f5c 100644 --- a/doc/guides/nics/features/cxgbe.ini +++ b/doc/guides/nics/features/cxgbe.ini @@ -14,6 +14,7 @@ TSO = Y Promiscuous mode = Y Allmulticast mode = Y RSS hash = Y +RSS key update = Y Flow control = Y CRC offload = Y VLAN offload = Y diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index 22da4111e5..7a32d9360c 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -41,6 +41,10 @@ New Features Also, make sure to start the actual text at the margin. ========================================================= +* **Added RSS hash and key update to CXGBE PMD.** + + Support to update RSS hash and key has been added to CXGBE PMD. + API Changes ----------- diff --git a/drivers/net/cxgbe/base/adapter.h b/drivers/net/cxgbe/base/adapter.h index e93c1bf732..169402836e 100644 --- a/drivers/net/cxgbe/base/adapter.h +++ b/drivers/net/cxgbe/base/adapter.h @@ -77,6 +77,7 @@ struct port_info { u16 *rss; /* rss table */ u8 rss_mode; /* rss mode */ u16 rss_size; /* size of VI's RSS table slice */ + u64 rss_hf; /* RSS Hash Function */ }; /* Enable or disable autonegotiation. If this is set to enable, @@ -736,6 +737,7 @@ int cxgb4_set_rspq_intr_params(struct sge_rspq *q, unsigned int us, unsigned int cnt); int cxgbe_poll(struct sge_rspq *q, struct rte_mbuf **rx_pkts, unsigned int budget, unsigned int *work_done); -int cxgb4_write_rss(const struct port_info *pi, const u16 *queues); +int cxgbe_write_rss(const struct port_info *pi, const u16 *queues); +int cxgbe_write_rss_conf(const struct port_info *pi, uint64_t flags); #endif /* __T4_ADAPTER_H__ */ diff --git a/drivers/net/cxgbe/base/common.h b/drivers/net/cxgbe/base/common.h index 1eda57d093..5301f74743 100644 --- a/drivers/net/cxgbe/base/common.h +++ b/drivers/net/cxgbe/base/common.h @@ -410,6 +410,9 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, int start, int n, const u16 *rspq, unsigned int nrspq); int t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid, unsigned int flags, unsigned int defq); +void t4_fw_tp_pio_rw(struct adapter *adap, u32 *vals, unsigned int nregs, + unsigned int start_index, unsigned int rw); +void t4_write_rss_key(struct adapter *adap, u32 *key, int idx); enum t4_bar2_qtype { T4_BAR2_QTYPE_EGRESS, T4_BAR2_QTYPE_INGRESS }; int t4_bar2_sge_qregs(struct adapter *adapter, unsigned int qid, diff --git a/drivers/net/cxgbe/base/t4_hw.c b/drivers/net/cxgbe/base/t4_hw.c index 56f38c8389..9eb83fd5e8 100644 --- a/drivers/net/cxgbe/base/t4_hw.c +++ b/drivers/net/cxgbe/base/t4_hw.c @@ -2166,6 +2166,79 @@ int t4_seeprom_wp(struct adapter *adapter, int enable) return t4_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0); } +/** + * t4_fw_tp_pio_rw - Access TP PIO through LDST + * @adap: the adapter + * @vals: where the indirect register values are stored/written + * @nregs: how many indirect registers to read/write + * @start_idx: index of first indirect register to read/write + * @rw: Read (1) or Write (0) + * + * Access TP PIO registers through LDST + */ +void t4_fw_tp_pio_rw(struct adapter *adap, u32 *vals, unsigned int nregs, + unsigned int start_index, unsigned int rw) +{ + int cmd = FW_LDST_ADDRSPC_TP_PIO; + struct fw_ldst_cmd c; + unsigned int i; + int ret; + + for (i = 0 ; i < nregs; i++) { + memset(&c, 0, sizeof(c)); + c.op_to_addrspace = cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | + (rw ? F_FW_CMD_READ : + F_FW_CMD_WRITE) | + V_FW_LDST_CMD_ADDRSPACE(cmd)); + c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); + + c.u.addrval.addr = cpu_to_be32(start_index + i); + c.u.addrval.val = rw ? 0 : cpu_to_be32(vals[i]); + ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c); + if (ret == 0) { + if (rw) + vals[i] = be32_to_cpu(c.u.addrval.val); + } + } +} + +/** + * t4_write_rss_key - program one of the RSS keys + * @adap: the adapter + * @key: 10-entry array holding the 320-bit RSS key + * @idx: which RSS key to write + * + * Writes one of the RSS keys with the given 320-bit value. If @idx is + * 0..15 the corresponding entry in the RSS key table is written, + * otherwise the global RSS key is written. + */ +void t4_write_rss_key(struct adapter *adap, u32 *key, int idx) +{ + u32 vrt = t4_read_reg(adap, A_TP_RSS_CONFIG_VRT); + u8 rss_key_addr_cnt = 16; + + /* T6 and later: for KeyMode 3 (per-vf and per-vf scramble), + * allows access to key addresses 16-63 by using KeyWrAddrX + * as index[5:4](upper 2) into key table + */ + if ((CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) && + (vrt & F_KEYEXTEND) && (G_KEYMODE(vrt) == 3)) + rss_key_addr_cnt = 32; + + t4_fw_tp_pio_rw(adap, key, 10, A_TP_RSS_SECRET_KEY0, 0); + + if (idx >= 0 && idx < rss_key_addr_cnt) { + if (rss_key_addr_cnt > 16) + t4_write_reg(adap, A_TP_RSS_CONFIG_VRT, + V_KEYWRADDRX(idx >> 4) | + V_T6_VFWRADDR(idx) | F_KEYWREN); + else + t4_write_reg(adap, A_TP_RSS_CONFIG_VRT, + V_KEYWRADDR(idx) | F_KEYWREN); + } +} + /** * t4_config_rss_range - configure a portion of the RSS mapping table * @adapter: the adapter diff --git a/drivers/net/cxgbe/base/t4_regs.h b/drivers/net/cxgbe/base/t4_regs.h index 1100e16fe0..0f0bca910b 100644 --- a/drivers/net/cxgbe/base/t4_regs.h +++ b/drivers/net/cxgbe/base/t4_regs.h @@ -503,9 +503,34 @@ #define V_MTUVALUE(x) ((x) << S_MTUVALUE) #define G_MTUVALUE(x) (((x) >> S_MTUVALUE) & M_MTUVALUE) +#define A_TP_RSS_CONFIG_VRT 0x7e00 + +#define S_KEYMODE 6 +#define M_KEYMODE 0x3U +#define G_KEYMODE(x) (((x) >> S_KEYMODE) & M_KEYMODE) + +#define S_KEYWRADDR 0 +#define V_KEYWRADDR(x) ((x) << S_KEYWRADDR) + +#define S_KEYWREN 4 +#define V_KEYWREN(x) ((x) << S_KEYWREN) +#define F_KEYWREN V_KEYWREN(1U) + +#define S_KEYWRADDRX 30 +#define V_KEYWRADDRX(x) ((x) << S_KEYWRADDRX) + +#define S_KEYEXTEND 26 +#define V_KEYEXTEND(x) ((x) << S_KEYEXTEND) +#define F_KEYEXTEND V_KEYEXTEND(1U) + +#define S_T6_VFWRADDR 8 +#define V_T6_VFWRADDR(x) ((x) << S_T6_VFWRADDR) + #define A_TP_PIO_ADDR 0x7e40 #define A_TP_PIO_DATA 0x7e44 +#define A_TP_RSS_SECRET_KEY0 0x40 + #define A_TP_VLAN_PRI_MAP 0x140 #define S_FRAGMENTATION 9 diff --git a/drivers/net/cxgbe/base/t4fw_interface.h b/drivers/net/cxgbe/base/t4fw_interface.h index 6ca4f3188a..883a1c7f5d 100644 --- a/drivers/net/cxgbe/base/t4fw_interface.h +++ b/drivers/net/cxgbe/base/t4fw_interface.h @@ -171,6 +171,7 @@ struct fw_eth_tx_pkts_wr { #define FW_CMD_HELLO_RETRIES 3 enum fw_cmd_opcodes { + FW_LDST_CMD = 0x01, FW_RESET_CMD = 0x03, FW_HELLO_CMD = 0x04, FW_BYE_CMD = 0x05, @@ -238,6 +239,94 @@ struct fw_cmd_hdr { #define FW_LEN16(fw_struct) V_FW_CMD_LEN16(sizeof(fw_struct) / 16) +/* address spaces + */ +enum fw_ldst_addrspc { + FW_LDST_ADDRSPC_TP_PIO = 0x0010, +}; + +struct fw_ldst_cmd { + __be32 op_to_addrspace; + __be32 cycles_to_len16; + union fw_ldst { + struct fw_ldst_addrval { + __be32 addr; + __be32 val; + } addrval; + struct fw_ldst_idctxt { + __be32 physid; + __be32 msg_ctxtflush; + __be32 ctxt_data7; + __be32 ctxt_data6; + __be32 ctxt_data5; + __be32 ctxt_data4; + __be32 ctxt_data3; + __be32 ctxt_data2; + __be32 ctxt_data1; + __be32 ctxt_data0; + } idctxt; + struct fw_ldst_mdio { + __be16 paddr_mmd; + __be16 raddr; + __be16 vctl; + __be16 rval; + } mdio; + struct fw_ldst_mps { + __be16 fid_ctl; + __be16 rplcpf_pkd; + __be32 rplc127_96; + __be32 rplc95_64; + __be32 rplc63_32; + __be32 rplc31_0; + __be32 atrb; + __be16 vlan[16]; + } mps; + struct fw_ldst_func { + __u8 access_ctl; + __u8 mod_index; + __be16 ctl_id; + __be32 offset; + __be64 data0; + __be64 data1; + } func; + struct fw_ldst_pcie { + __u8 ctrl_to_fn; + __u8 bnum; + __u8 r; + __u8 ext_r; + __u8 select_naccess; + __u8 pcie_fn; + __be16 nset_pkd; + __be32 data[12]; + } pcie; + struct fw_ldst_i2c_deprecated { + __u8 pid_pkd; + __u8 base; + __u8 boffset; + __u8 data; + __be32 r9; + } i2c_deprecated; + struct fw_ldst_i2c { + __u8 pid; + __u8 did; + __u8 boffset; + __u8 blen; + __be32 r9; + __u8 data[48]; + } i2c; + struct fw_ldst_le { + __be32 index; + __be32 r9; + __u8 val[33]; + __u8 r11[7]; + } le; + } u; +}; + +#define S_FW_LDST_CMD_ADDRSPACE 0 +#define M_FW_LDST_CMD_ADDRSPACE 0xff +#define V_FW_LDST_CMD_ADDRSPACE(x) ((x) << S_FW_LDST_CMD_ADDRSPACE) + struct fw_reset_cmd { __be32 op_to_write; __be32 retval_len16; diff --git a/drivers/net/cxgbe/cxgbe.h b/drivers/net/cxgbe/cxgbe.h index f989154553..555ef26012 100644 --- a/drivers/net/cxgbe/cxgbe.h +++ b/drivers/net/cxgbe/cxgbe.h @@ -46,6 +46,13 @@ #define CXGBE_MIN_RX_BUFSIZE ETHER_MIN_MTU /* min buf size */ #define CXGBE_MAX_RX_PKTLEN (9000 + ETHER_HDR_LEN + ETHER_CRC_LEN) /* max pkt */ +#define CXGBE_DEFAULT_RSS_KEY_LEN 40 /* 320-bits */ +#define CXGBE_RSS_HF_ALL (ETH_RSS_IPV4 | ETH_RSS_IPV6 | \ + ETH_RSS_NONFRAG_IPV4_TCP | \ + ETH_RSS_NONFRAG_IPV4_UDP | \ + ETH_RSS_NONFRAG_IPV6_TCP | \ + ETH_RSS_NONFRAG_IPV6_UDP) + int cxgbe_probe(struct adapter *adapter); void cxgbe_get_speed_caps(struct port_info *pi, u32 *speed_caps); int cxgbe_up(struct adapter *adap); diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c index 423a6957b5..b67dcb7d80 100644 --- a/drivers/net/cxgbe/cxgbe_ethdev.c +++ b/drivers/net/cxgbe/cxgbe_ethdev.c @@ -171,6 +171,8 @@ static void cxgbe_dev_info_get(struct rte_eth_dev *eth_dev, DEV_TX_OFFLOAD_TCP_TSO; device_info->reta_size = pi->rss_size; + device_info->hash_key_size = CXGBE_DEFAULT_RSS_KEY_LEN; + device_info->flow_type_rss_offloads = CXGBE_RSS_HF_ALL; device_info->rx_desc_lim = cxgbe_desc_lim; device_info->tx_desc_lim = cxgbe_desc_lim; @@ -787,6 +789,36 @@ cxgbe_dev_supported_ptypes_get(struct rte_eth_dev *eth_dev) return NULL; } +/* Update RSS hash configuration + */ +static int cxgbe_dev_rss_hash_update(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf) +{ + struct port_info *pi = (struct port_info *)(dev->data->dev_private); + struct adapter *adapter = pi->adapter; + int err; + + err = cxgbe_write_rss_conf(pi, rss_conf->rss_hf); + if (err) + return err; + + pi->rss_hf = rss_conf->rss_hf; + + if (rss_conf->rss_key) { + u32 key[10], mod_key[10]; + int i, j; + + memcpy(key, rss_conf->rss_key, CXGBE_DEFAULT_RSS_KEY_LEN); + + for (i = 9, j = 0; i >= 0; i--, j++) + mod_key[j] = cpu_to_be32(key[i]); + + t4_write_rss_key(adapter, mod_key, -1); + } + + return 0; +} + static int cxgbe_get_eeprom_length(struct rte_eth_dev *dev) { RTE_SET_USED(dev); @@ -985,6 +1017,7 @@ static const struct eth_dev_ops cxgbe_eth_dev_ops = { .get_eeprom = cxgbe_get_eeprom, .set_eeprom = cxgbe_set_eeprom, .get_reg = cxgbe_get_regs, + .rss_hash_update = cxgbe_dev_rss_hash_update, }; /* diff --git a/drivers/net/cxgbe/cxgbe_main.c b/drivers/net/cxgbe/cxgbe_main.c index 143d224eb3..0c1dc8c8be 100644 --- a/drivers/net/cxgbe/cxgbe_main.c +++ b/drivers/net/cxgbe/cxgbe_main.c @@ -360,6 +360,8 @@ static int init_rss(struct adapter *adap) pi->rss = rte_zmalloc(NULL, pi->rss_size * sizeof(u16), 0); if (!pi->rss) return -ENOMEM; + + pi->rss_hf = CXGBE_RSS_HF_ALL; } return 0; } @@ -930,14 +932,71 @@ int link_start(struct port_info *pi) } /** - * cxgb4_write_rss - write the RSS table for a given port + * cxgbe_write_rss_conf - flash the RSS configuration for a given port + * @pi: the port + * @rss_hf: Hash configuration to apply + */ +int cxgbe_write_rss_conf(const struct port_info *pi, uint64_t rss_hf) +{ + struct adapter *adapter = pi->adapter; + const struct sge_eth_rxq *rxq; + u64 flags = 0; + u16 rss; + int err; + + /* Should never be called before setting up sge eth rx queues */ + if (!(adapter->flags & FULL_INIT_DONE)) { + dev_err(adap, "%s No RXQs available on port %d\n", + __func__, pi->port_id); + return -EINVAL; + } + + /* Don't allow unsupported hash functions */ + if (rss_hf & ~CXGBE_RSS_HF_ALL) + return -EINVAL; + + if (rss_hf & ETH_RSS_IPV4) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN; + + if (rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN; + + if (rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN | + F_FW_RSS_VI_CONFIG_CMD_UDPEN; + + if (rss_hf & ETH_RSS_IPV6) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN; + + if (rss_hf & ETH_RSS_NONFRAG_IPV6_TCP) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN; + + if (rss_hf & ETH_RSS_NONFRAG_IPV6_UDP) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN | + F_FW_RSS_VI_CONFIG_CMD_UDPEN; + + rxq = &adapter->sge.ethrxq[pi->first_qset]; + rss = rxq[0].rspq.abs_id; + + /* If Tunnel All Lookup isn't specified in the global RSS + * Configuration, then we need to specify a default Ingress + * Queue for any ingress packets which aren't hashed. We'll + * use our first ingress queue ... + */ + err = t4_config_vi_rss(adapter, adapter->mbox, pi->viid, + flags, rss); + return err; +} + +/** + * cxgbe_write_rss - write the RSS table for a given port * @pi: the port * @queues: array of queue indices for RSS * * Sets up the portion of the HW RSS table for the port's VI to distribute * packets to the Rx queues in @queues. */ -int cxgb4_write_rss(const struct port_info *pi, const u16 *queues) +int cxgbe_write_rss(const struct port_info *pi, const u16 *queues) { u16 *rss; int i, err; @@ -958,20 +1017,6 @@ int cxgb4_write_rss(const struct port_info *pi, const u16 *queues) err = t4_config_rss_range(adapter, adapter->pf, pi->viid, 0, pi->rss_size, rss, pi->rss_size); - /* - * If Tunnel All Lookup isn't specified in the global RSS - * Configuration, then we need to specify a default Ingress - * Queue for any ingress packets which aren't hashed. We'll - * use our first ingress queue ... - */ - if (!err) - err = t4_config_vi_rss(adapter, adapter->mbox, pi->viid, - F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN | - F_FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN | - F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN | - F_FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN | - F_FW_RSS_VI_CONFIG_CMD_UDPEN, - rss[0]); rte_free(rss); return err; } @@ -1001,7 +1046,11 @@ int setup_rss(struct port_info *pi) for (j = 0; j < pi->rss_size; j++) pi->rss[j] = j % pi->n_rx_qsets; - err = cxgb4_write_rss(pi, pi->rss); + err = cxgbe_write_rss(pi, pi->rss); + if (err) + return err; + + err = cxgbe_write_rss_conf(pi, pi->rss_hf); if (err) return err; pi->flags |= PORT_RSS_DONE; -- 2.20.1