diff options
| -rw-r--r-- | drivers/net/ethernet/qualcomm/ppe/ppe_config.c | 198 | ||||
| -rw-r--r-- | drivers/net/ethernet/qualcomm/ppe/ppe_config.h | 39 | ||||
| -rw-r--r-- | drivers/net/ethernet/qualcomm/ppe/ppe_regs.h | 40 |
3 files changed, 276 insertions, 1 deletions
diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe_config.c b/drivers/net/ethernet/qualcomm/ppe/ppe_config.c index a02d3300bac0..a794ccd3b517 100644 --- a/drivers/net/ethernet/qualcomm/ppe/ppe_config.c +++ b/drivers/net/ethernet/qualcomm/ppe/ppe_config.c @@ -1216,6 +1216,147 @@ int ppe_counter_enable_set(struct ppe_device *ppe_dev, int port) return regmap_set_bits(ppe_dev->regmap, reg, PPE_PORT_EG_VLAN_TBL_TX_COUNTING_EN); } +static int ppe_rss_hash_ipv4_config(struct ppe_device *ppe_dev, int index, + struct ppe_rss_hash_cfg cfg) +{ + u32 reg, val; + + switch (index) { + case 0: + val = cfg.hash_sip_mix[0]; + break; + case 1: + val = cfg.hash_dip_mix[0]; + break; + case 2: + val = cfg.hash_protocol_mix; + break; + case 3: + val = cfg.hash_dport_mix; + break; + case 4: + val = cfg.hash_sport_mix; + break; + default: + return -EINVAL; + } + + reg = PPE_RSS_HASH_MIX_IPV4_ADDR + index * PPE_RSS_HASH_MIX_IPV4_INC; + + return regmap_update_bits(ppe_dev->regmap, reg, + PPE_RSS_HASH_MIX_IPV4_VAL, + FIELD_PREP(PPE_RSS_HASH_MIX_IPV4_VAL, val)); +} + +static int ppe_rss_hash_ipv6_config(struct ppe_device *ppe_dev, int index, + struct ppe_rss_hash_cfg cfg) +{ + u32 reg, val; + + switch (index) { + case 0 ... 3: + val = cfg.hash_sip_mix[index]; + break; + case 4 ... 7: + val = cfg.hash_dip_mix[index - 4]; + break; + case 8: + val = cfg.hash_protocol_mix; + break; + case 9: + val = cfg.hash_dport_mix; + break; + case 10: + val = cfg.hash_sport_mix; + break; + default: + return -EINVAL; + } + + reg = PPE_RSS_HASH_MIX_ADDR + index * PPE_RSS_HASH_MIX_INC; + + return regmap_update_bits(ppe_dev->regmap, reg, + PPE_RSS_HASH_MIX_VAL, + FIELD_PREP(PPE_RSS_HASH_MIX_VAL, val)); +} + +/** + * ppe_rss_hash_config_set - Configure the PPE hash settings for the packet received. + * @ppe_dev: PPE device. + * @mode: Configure RSS hash for the packet type IPv4 and IPv6. + * @cfg: RSS hash configuration. + * + * PPE RSS hash settings are configured for the packet type IPv4 and IPv6. + * + * Return: 0 on success, negative error code on failure. + */ +int ppe_rss_hash_config_set(struct ppe_device *ppe_dev, int mode, + struct ppe_rss_hash_cfg cfg) +{ + u32 val, reg; + int i, ret; + + if (mode & PPE_RSS_HASH_MODE_IPV4) { + val = FIELD_PREP(PPE_RSS_HASH_MASK_IPV4_HASH_MASK, cfg.hash_mask); + val |= FIELD_PREP(PPE_RSS_HASH_MASK_IPV4_FRAGMENT, cfg.hash_fragment_mode); + ret = regmap_write(ppe_dev->regmap, PPE_RSS_HASH_MASK_IPV4_ADDR, val); + if (ret) + return ret; + + val = FIELD_PREP(PPE_RSS_HASH_SEED_IPV4_VAL, cfg.hash_seed); + ret = regmap_write(ppe_dev->regmap, PPE_RSS_HASH_SEED_IPV4_ADDR, val); + if (ret) + return ret; + + for (i = 0; i < PPE_RSS_HASH_MIX_IPV4_ENTRIES; i++) { + ret = ppe_rss_hash_ipv4_config(ppe_dev, i, cfg); + if (ret) + return ret; + } + + for (i = 0; i < PPE_RSS_HASH_FIN_IPV4_ENTRIES; i++) { + val = FIELD_PREP(PPE_RSS_HASH_FIN_IPV4_INNER, cfg.hash_fin_inner[i]); + val |= FIELD_PREP(PPE_RSS_HASH_FIN_IPV4_OUTER, cfg.hash_fin_outer[i]); + reg = PPE_RSS_HASH_FIN_IPV4_ADDR + i * PPE_RSS_HASH_FIN_IPV4_INC; + + ret = regmap_write(ppe_dev->regmap, reg, val); + if (ret) + return ret; + } + } + + if (mode & PPE_RSS_HASH_MODE_IPV6) { + val = FIELD_PREP(PPE_RSS_HASH_MASK_HASH_MASK, cfg.hash_mask); + val |= FIELD_PREP(PPE_RSS_HASH_MASK_FRAGMENT, cfg.hash_fragment_mode); + ret = regmap_write(ppe_dev->regmap, PPE_RSS_HASH_MASK_ADDR, val); + if (ret) + return ret; + + val = FIELD_PREP(PPE_RSS_HASH_SEED_VAL, cfg.hash_seed); + ret = regmap_write(ppe_dev->regmap, PPE_RSS_HASH_SEED_ADDR, val); + if (ret) + return ret; + + for (i = 0; i < PPE_RSS_HASH_MIX_ENTRIES; i++) { + ret = ppe_rss_hash_ipv6_config(ppe_dev, i, cfg); + if (ret) + return ret; + } + + for (i = 0; i < PPE_RSS_HASH_FIN_ENTRIES; i++) { + val = FIELD_PREP(PPE_RSS_HASH_FIN_INNER, cfg.hash_fin_inner[i]); + val |= FIELD_PREP(PPE_RSS_HASH_FIN_OUTER, cfg.hash_fin_outer[i]); + reg = PPE_RSS_HASH_FIN_ADDR + i * PPE_RSS_HASH_FIN_INC; + + ret = regmap_write(ppe_dev->regmap, reg, val); + if (ret) + return ret; + } + } + + return 0; +} + static int ppe_config_bm_threshold(struct ppe_device *ppe_dev, int bm_port_id, const struct ppe_bm_port_config port_cfg) { @@ -1687,6 +1828,57 @@ static int ppe_port_config_init(struct ppe_device *ppe_dev) return ppe_counter_enable_set(ppe_dev, 0); } +/* Initialize the PPE RSS configuration for IPv4 and IPv6 packet receive. + * RSS settings are to calculate the random RSS hash value generated during + * packet receive. This hash is then used to generate the queue offset used + * to determine the queue used to transmit the packet. + */ +static int ppe_rss_hash_init(struct ppe_device *ppe_dev) +{ + u16 fins[PPE_RSS_HASH_TUPLES] = { 0x205, 0x264, 0x227, 0x245, 0x201 }; + u8 ips[PPE_RSS_HASH_IP_LENGTH] = { 0x13, 0xb, 0x13, 0xb }; + struct ppe_rss_hash_cfg hash_cfg; + int i, ret; + + hash_cfg.hash_seed = get_random_u32(); + hash_cfg.hash_mask = 0xfff; + + /* Use 5 tuple as RSS hash key for the first fragment of TCP, UDP + * and UDP-Lite packets. + */ + hash_cfg.hash_fragment_mode = false; + + /* The final common seed configs used to calculate the RSS has value, + * which is available for both IPv4 and IPv6 packet. + */ + for (i = 0; i < ARRAY_SIZE(fins); i++) { + hash_cfg.hash_fin_inner[i] = fins[i] & 0x1f; + hash_cfg.hash_fin_outer[i] = fins[i] >> 5; + } + + /* RSS seeds for IP protocol, L4 destination & source port and + * destination & source IP used to calculate the RSS hash value. + */ + hash_cfg.hash_protocol_mix = 0x13; + hash_cfg.hash_dport_mix = 0xb; + hash_cfg.hash_sport_mix = 0x13; + hash_cfg.hash_dip_mix[0] = 0xb; + hash_cfg.hash_sip_mix[0] = 0x13; + + /* Configure RSS seed configs for IPv4 packet. */ + ret = ppe_rss_hash_config_set(ppe_dev, PPE_RSS_HASH_MODE_IPV4, hash_cfg); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(ips); i++) { + hash_cfg.hash_sip_mix[i] = ips[i]; + hash_cfg.hash_dip_mix[i] = ips[i]; + } + + /* Configure RSS seed configs for IPv6 packet. */ + return ppe_rss_hash_config_set(ppe_dev, PPE_RSS_HASH_MODE_IPV6, hash_cfg); +} + int ppe_hw_config(struct ppe_device *ppe_dev) { int ret; @@ -1711,5 +1903,9 @@ int ppe_hw_config(struct ppe_device *ppe_dev) if (ret) return ret; - return ppe_port_config_init(ppe_dev); + ret = ppe_port_config_init(ppe_dev); + if (ret) + return ret; + + return ppe_rss_hash_init(ppe_dev); } diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe_config.h b/drivers/net/ethernet/qualcomm/ppe/ppe_config.h index 84fa447742e3..eb4a82375bb2 100644 --- a/drivers/net/ethernet/qualcomm/ppe/ppe_config.h +++ b/drivers/net/ethernet/qualcomm/ppe/ppe_config.h @@ -23,6 +23,12 @@ /* The service code is used by EDMA port to transmit packet to PPE. */ #define PPE_EDMA_SC_BYPASS_ID 1 +/* The PPE RSS hash configured for IPv4 and IPv6 packet separately. */ +#define PPE_RSS_HASH_MODE_IPV4 BIT(0) +#define PPE_RSS_HASH_MODE_IPV6 BIT(1) +#define PPE_RSS_HASH_IP_LENGTH 4 +#define PPE_RSS_HASH_TUPLES 5 + /** * enum ppe_scheduler_frame_mode - PPE scheduler frame mode. * @PPE_SCH_WITH_IPG_PREAMBLE_FRAME_CRC: The scheduled frame includes IPG, @@ -247,6 +253,37 @@ enum ppe_action_type { PPE_ACTION_REDIRECT_TO_CPU = 3, }; +/** + * struct ppe_rss_hash_cfg - PPE RSS hash configuration. + * @hash_mask: Mask of the generated hash value. + * @hash_fragment_mode: Hash generation mode for the first fragment of TCP, + * UDP and UDP-Lite packets, to use either 3 tuple or 5 tuple for RSS hash + * key computation. + * @hash_seed: Seed to generate RSS hash. + * @hash_sip_mix: Source IP selection. + * @hash_dip_mix: Destination IP selection. + * @hash_protocol_mix: Protocol selection. + * @hash_sport_mix: Source L4 port selection. + * @hash_dport_mix: Destination L4 port selection. + * @hash_fin_inner: RSS hash value first selection. + * @hash_fin_outer: RSS hash value second selection. + * + * PPE RSS hash value is generated for the packet based on the RSS hash + * configured. + */ +struct ppe_rss_hash_cfg { + u32 hash_mask; + bool hash_fragment_mode; + u32 hash_seed; + u8 hash_sip_mix[PPE_RSS_HASH_IP_LENGTH]; + u8 hash_dip_mix[PPE_RSS_HASH_IP_LENGTH]; + u8 hash_protocol_mix; + u8 hash_sport_mix; + u8 hash_dport_mix; + u8 hash_fin_inner[PPE_RSS_HASH_TUPLES]; + u8 hash_fin_outer[PPE_RSS_HASH_TUPLES]; +}; + int ppe_hw_config(struct ppe_device *ppe_dev); int ppe_queue_scheduler_set(struct ppe_device *ppe_dev, int node_id, bool flow_level, int port, @@ -269,4 +306,6 @@ int ppe_port_resource_get(struct ppe_device *ppe_dev, int port, int ppe_sc_config_set(struct ppe_device *ppe_dev, int sc, struct ppe_sc_cfg cfg); int ppe_counter_enable_set(struct ppe_device *ppe_dev, int port); +int ppe_rss_hash_config_set(struct ppe_device *ppe_dev, int mode, + struct ppe_rss_hash_cfg hash_cfg); #endif diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h b/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h index c26bee83252f..3e9cccedc6be 100644 --- a/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h +++ b/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h @@ -16,6 +16,46 @@ #define PPE_BM_SCH_CTRL_SCH_OFFSET GENMASK(14, 8) #define PPE_BM_SCH_CTRL_SCH_EN BIT(31) +/* RSS settings are to calculate the random RSS hash value generated during + * packet receive to ARM cores. This hash is then used to generate the queue + * offset used to determine the queue used to transmit the packet to ARM cores. + */ +#define PPE_RSS_HASH_MASK_ADDR 0xb4318 +#define PPE_RSS_HASH_MASK_HASH_MASK GENMASK(20, 0) +#define PPE_RSS_HASH_MASK_FRAGMENT BIT(28) + +#define PPE_RSS_HASH_SEED_ADDR 0xb431c +#define PPE_RSS_HASH_SEED_VAL GENMASK(31, 0) + +#define PPE_RSS_HASH_MIX_ADDR 0xb4320 +#define PPE_RSS_HASH_MIX_ENTRIES 11 +#define PPE_RSS_HASH_MIX_INC 4 +#define PPE_RSS_HASH_MIX_VAL GENMASK(4, 0) + +#define PPE_RSS_HASH_FIN_ADDR 0xb4350 +#define PPE_RSS_HASH_FIN_ENTRIES 5 +#define PPE_RSS_HASH_FIN_INC 4 +#define PPE_RSS_HASH_FIN_INNER GENMASK(4, 0) +#define PPE_RSS_HASH_FIN_OUTER GENMASK(9, 5) + +#define PPE_RSS_HASH_MASK_IPV4_ADDR 0xb4380 +#define PPE_RSS_HASH_MASK_IPV4_HASH_MASK GENMASK(20, 0) +#define PPE_RSS_HASH_MASK_IPV4_FRAGMENT BIT(28) + +#define PPE_RSS_HASH_SEED_IPV4_ADDR 0xb4384 +#define PPE_RSS_HASH_SEED_IPV4_VAL GENMASK(31, 0) + +#define PPE_RSS_HASH_MIX_IPV4_ADDR 0xb4390 +#define PPE_RSS_HASH_MIX_IPV4_ENTRIES 5 +#define PPE_RSS_HASH_MIX_IPV4_INC 4 +#define PPE_RSS_HASH_MIX_IPV4_VAL GENMASK(4, 0) + +#define PPE_RSS_HASH_FIN_IPV4_ADDR 0xb43b0 +#define PPE_RSS_HASH_FIN_IPV4_ENTRIES 5 +#define PPE_RSS_HASH_FIN_IPV4_INC 4 +#define PPE_RSS_HASH_FIN_IPV4_INNER GENMASK(4, 0) +#define PPE_RSS_HASH_FIN_IPV4_OUTER GENMASK(9, 5) + #define PPE_BM_SCH_CFG_TBL_ADDR 0xc000 #define PPE_BM_SCH_CFG_TBL_ENTRIES 128 #define PPE_BM_SCH_CFG_TBL_INC 0x10 |
