@@ -1172,6 +1172,53 @@ static int ppe_port_ctrl_init(struct ppe_device *ppe_dev)
return 0;
}
+static int ppe_rss_hash_init(struct ppe_device *ppe_dev)
+{
+ const struct ppe_queue_ops *ppe_queue_ops;
+ struct ppe_rss_hash_cfg hash_cfg;
+ int i, ret;
+ u16 fins[5] = {0x205, 0x264, 0x227, 0x245, 0x201};
+ u8 ips[4] = {0x13, 0xb, 0x13, 0xb};
+
+ ppe_queue_ops = ppe_queue_config_ops_get();
+ if (!ppe_queue_ops->rss_hash_config_set)
+ return -EINVAL;
+
+ hash_cfg.hash_seed = get_random_u32();
+ hash_cfg.hash_mask = 0xfff;
+ hash_cfg.hash_fragment_mode = false;
+
+ i = 0;
+ while (i < ARRAY_SIZE(fins)) {
+ hash_cfg.hash_fin_inner[i] = fins[i] & 0x1f;
+ hash_cfg.hash_fin_outer[i] = fins[i] >> 5;
+ i++;
+ }
+
+ hash_cfg.hash_protocol_mix = 0x13;
+ hash_cfg.hash_dport_mix = 0xb;
+ hash_cfg.hash_sport_mix = 0x13;
+ hash_cfg.hash_sip_mix[0] = 0x13;
+ hash_cfg.hash_dip_mix[0] = 0xb;
+
+ ret = ppe_queue_ops->rss_hash_config_set(ppe_dev,
+ PPE_RSS_HASH_MODE_IPV4,
+ hash_cfg);
+ if (ret)
+ return ret;
+
+ i = 0;
+ while (i < ARRAY_SIZE(ips)) {
+ hash_cfg.hash_sip_mix[i] = ips[i];
+ hash_cfg.hash_dip_mix[i] = ips[i];
+ i++;
+ }
+
+ return ppe_queue_ops->rss_hash_config_set(ppe_dev,
+ PPE_RSS_HASH_MODE_IPV6,
+ hash_cfg);
+}
+
static int ppe_dev_hw_init(struct ppe_device *ppe_dev)
{
int ret;
@@ -1184,7 +1231,11 @@ static int ppe_dev_hw_init(struct ppe_device *ppe_dev)
if (ret)
return ret;
- return ppe_port_ctrl_init(ppe_dev);
+ ret = ppe_port_ctrl_init(ppe_dev);
+ if (ret)
+ return ret;
+
+ return ppe_rss_hash_init(ppe_dev);
}
static int qcom_ppe_probe(struct platform_device *pdev)
@@ -333,6 +333,102 @@ int ppe_counter_set(struct ppe_device *ppe_dev, int port, bool enable)
FIELD_PREP(PPE_PORT_EG_VLAN_TX_COUNTING_EN, enable));
}
+static int ppe_rss_hash_config_set(struct ppe_device *ppe_dev,
+ int mode,
+ struct ppe_rss_hash_cfg cfg)
+{
+ u32 val;
+ int i;
+
+ if (mode & PPE_RSS_HASH_MODE_IPV4) {
+ val = FIELD_PREP(PPE_RSS_HASH_MASK_IPV4_HASH_MASK, cfg.hash_mask) |
+ FIELD_PREP(PPE_RSS_HASH_MASK_IPV4_FRAGMENT,
+ cfg.hash_fragment_mode);
+ ppe_write(ppe_dev, PPE_RSS_HASH_MASK_IPV4, val);
+
+ val = FIELD_PREP(PPE_RSS_HASH_SEED_IPV4_VAL, cfg.hash_seed);
+ ppe_write(ppe_dev, PPE_RSS_HASH_SEED_IPV4, val);
+
+ for (i = 0; i < PPE_RSS_HASH_MIX_IPV4_NUM; i++) {
+ switch (i) {
+ case 0:
+ val = FIELD_PREP(PPE_RSS_HASH_MIX_IPV4_VAL,
+ cfg.hash_sip_mix[0]);
+ break;
+ case 1:
+ val = FIELD_PREP(PPE_RSS_HASH_MIX_IPV4_VAL,
+ cfg.hash_dip_mix[0]);
+ break;
+ case 2:
+ val = FIELD_PREP(PPE_RSS_HASH_MIX_IPV4_VAL,
+ cfg.hash_protocol_mix);
+ break;
+ case 3:
+ val = FIELD_PREP(PPE_RSS_HASH_MIX_IPV4_VAL,
+ cfg.hash_dport_mix);
+ break;
+ case 4:
+ val = FIELD_PREP(PPE_RSS_HASH_MIX_IPV4_VAL,
+ cfg.hash_sport_mix);
+ break;
+ default:
+ break;
+ }
+ ppe_write(ppe_dev, PPE_RSS_HASH_MIX_IPV4 + i * PPE_RSS_HASH_MIX_IPV4_INC,
+ val);
+ }
+
+ for (i = 0; i < PPE_RSS_HASH_MIX_IPV4_NUM; i++) {
+ val = FIELD_PREP(PPE_RSS_HASH_FIN_IPV4_INNER, cfg.hash_fin_inner[i]) |
+ FIELD_PREP(PPE_RSS_HASH_FIN_IPV4_OUTER,
+ cfg.hash_fin_outer[i]);
+ ppe_write(ppe_dev, PPE_RSS_HASH_FIN_IPV4 + i * PPE_RSS_HASH_FIN_IPV4_INC,
+ val);
+ }
+ }
+
+ if (mode & PPE_RSS_HASH_MODE_IPV6) {
+ val = FIELD_PREP(PPE_RSS_HASH_MASK_HASH_MASK, cfg.hash_mask) |
+ FIELD_PREP(PPE_RSS_HASH_MASK_FRAGMENT, cfg.hash_fragment_mode);
+ ppe_write(ppe_dev, PPE_RSS_HASH_MASK, val);
+
+ val = FIELD_PREP(PPE_RSS_HASH_SEED_VAL, cfg.hash_seed);
+ ppe_write(ppe_dev, PPE_RSS_HASH_SEED, val);
+
+ for (i = 0; i < PPE_RSS_HASH_MIX_NUM; i++) {
+ switch (i) {
+ case 0 ... 3:
+ val = FIELD_PREP(PPE_RSS_HASH_MIX_VAL, cfg.hash_sip_mix[i]);
+ break;
+ case 4 ... 7:
+ val = FIELD_PREP(PPE_RSS_HASH_MIX_VAL, cfg.hash_dip_mix[i - 4]);
+ break;
+ case 8:
+ val = FIELD_PREP(PPE_RSS_HASH_MIX_VAL, cfg.hash_protocol_mix);
+ break;
+ case 9:
+ val = FIELD_PREP(PPE_RSS_HASH_MIX_VAL, cfg.hash_dport_mix);
+ break;
+ case 10:
+ val = FIELD_PREP(PPE_RSS_HASH_MIX_VAL, cfg.hash_sport_mix);
+ break;
+ default:
+ break;
+ }
+ ppe_write(ppe_dev, PPE_RSS_HASH_MIX + i * PPE_RSS_HASH_MIX_INC, val);
+ }
+
+ for (i = 0; i < PPE_RSS_HASH_FIN_NUM; i++) {
+ val = FIELD_PREP(PPE_RSS_HASH_FIN_INNER, cfg.hash_fin_inner[i]) |
+ FIELD_PREP(PPE_RSS_HASH_FIN_OUTER, cfg.hash_fin_outer[i]);
+
+ ppe_write(ppe_dev, PPE_RSS_HASH_FIN + i * PPE_RSS_HASH_FIN_INC, val);
+ }
+ }
+
+ return 0;
+}
+
static const struct ppe_queue_ops qcom_ppe_queue_config_ops = {
.queue_scheduler_set = ppe_queue_scheduler_set,
.queue_scheduler_get = ppe_queue_scheduler_get,
@@ -340,6 +436,7 @@ static const struct ppe_queue_ops qcom_ppe_queue_config_ops = {
.queue_ucast_base_get = ppe_queue_ucast_base_get,
.queue_ucast_pri_class_set = ppe_queue_ucast_pri_class_set,
.queue_ucast_hash_class_set = ppe_queue_ucast_hash_class_set,
+ .rss_hash_config_set = ppe_rss_hash_config_set,
};
const struct ppe_queue_ops *ppe_queue_config_ops_get(void)
@@ -12,6 +12,8 @@
#define PPE_QUEUE_PRI_MAX 16
#define PPE_QUEUE_HASH_MAX 256
+#define PPE_RSS_HASH_MODE_IPV4 BIT(0)
+#define PPE_RSS_HASH_MODE_IPV6 BIT(1)
/* PPE hardware QoS configurations used to dispatch the packet passed
* through PPE, the scheduler supports DRR(deficit round robin with the
@@ -148,6 +150,23 @@ struct ppe_servcode_cfg {
int offset_sel;
};
+/* PPE RSS hash can be configured to generate the hash value based on
+ * 5 tuples of packet, the generated hash value is used to decides the
+ * final queue ID.
+ */
+struct ppe_rss_hash_cfg {
+ u32 hash_mask;
+ bool hash_fragment_mode;
+ u32 hash_seed;
+ u8 hash_sip_mix[4];
+ u8 hash_dip_mix[4];
+ u8 hash_protocol_mix;
+ u8 hash_sport_mix;
+ u8 hash_dport_mix;
+ u8 hash_fin_inner[5];
+ u8 hash_fin_outer[5];
+};
+
/* The operations are used to configure the PPE queue related resource */
struct ppe_queue_ops {
int (*queue_scheduler_set)(struct ppe_device *ppe_dev,
@@ -176,6 +195,9 @@ struct ppe_queue_ops {
int profile_id,
int rss_hash,
int class_offset);
+ int (*rss_hash_config_set)(struct ppe_device *ppe_dev,
+ int mode,
+ struct ppe_rss_hash_cfg hash_cfg);
};
const struct ppe_queue_ops *ppe_queue_config_ops_get(void);
@@ -19,6 +19,50 @@
#define PPE_RX_FIFO_CFG_INC 4
#define PPE_RX_FIFO_CFG_THRSH GENMASK(2, 0)
+#define PPE_RSS_HASH_MASK 0xb4318
+#define PPE_RSS_HASH_MASK_NUM 1
+#define PPE_RSS_HASH_MASK_INC 4
+#define PPE_RSS_HASH_MASK_HASH_MASK GENMASK(20, 0)
+#define PPE_RSS_HASH_MASK_FRAGMENT BIT(28)
+
+#define PPE_RSS_HASH_SEED 0xb431c
+#define PPE_RSS_HASH_SEED_NUM 1
+#define PPE_RSS_HASH_SEED_INC 4
+#define PPE_RSS_HASH_SEED_VAL GENMASK(31, 0)
+
+#define PPE_RSS_HASH_MIX 0xb4320
+#define PPE_RSS_HASH_MIX_NUM 11
+#define PPE_RSS_HASH_MIX_INC 4
+#define PPE_RSS_HASH_MIX_VAL GENMASK(4, 0)
+
+#define PPE_RSS_HASH_FIN 0xb4350
+#define PPE_RSS_HASH_FIN_NUM 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 0xb4380
+#define PPE_RSS_HASH_MASK_IPV4_NUM 1
+#define PPE_RSS_HASH_MASK_IPV4_INC 4
+#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 0xb4384
+#define PPE_RSS_HASH_SEED_IPV4_NUM 1
+#define PPE_RSS_HASH_SEED_IPV4_INC 4
+#define PPE_RSS_HASH_SEED_IPV4_VAL GENMASK(31, 0)
+
+#define PPE_RSS_HASH_MIX_IPV4 0xb4390
+#define PPE_RSS_HASH_MIX_IPV4_NUM 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 0xb43b0
+#define PPE_RSS_HASH_FIN_IPV4_NUM 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_TDM_CFG_TBL 0xc000
#define PPE_BM_TDM_CFG_TBL_NUM 128
#define PPE_BM_TDM_CFG_TBL_INC 0x10