@@ -1104,9 +1104,29 @@ static int ppe_qm_init(struct ppe_device *ppe_dev)
return 0;
}
+static int ppe_servcode_init(struct ppe_device *ppe_dev)
+{
+ struct ppe_servcode_cfg servcode_cfg;
+
+ memset(&servcode_cfg, 0, sizeof(servcode_cfg));
+ servcode_cfg.bypass_bitmap[0] = (u32)(~(BIT(FAKE_MAC_HEADER_BYP) |
+ BIT(SERVICE_CODE_BYP) |
+ BIT(FAKE_L2_PROTO_BYP)));
+ servcode_cfg.bypass_bitmap[1] = (u32)(~(BIT(ACL_POST_ROUTING_CHECK_BYP)));
+
+ /* The default service code used by CPU port */
+ return ppe_servcode_config_set(ppe_dev, 1, servcode_cfg);
+}
+
static int ppe_dev_hw_init(struct ppe_device *ppe_dev)
{
- return ppe_qm_init(ppe_dev);
+ int ret;
+
+ ret = ppe_qm_init(ppe_dev);
+ if (ret)
+ return ret;
+
+ return ppe_servcode_init(ppe_dev);
}
static int qcom_ppe_probe(struct platform_device *pdev)
@@ -269,6 +269,48 @@ static int ppe_queue_ucast_hash_class_set(struct ppe_device *ppe_dev,
reg_val);
}
+int ppe_servcode_config_set(struct ppe_device *ppe_dev,
+ int servcode,
+ struct ppe_servcode_cfg cfg)
+{
+ union ppe_eg_service_cfg_u eg_service_cfg;
+ union ppe_service_cfg_u service_cfg;
+ int val;
+
+ memset(&service_cfg, 0, sizeof(service_cfg));
+ memset(&eg_service_cfg, 0, sizeof(eg_service_cfg));
+
+ val = FIELD_PREP(PPE_IN_L2_SERVICE_TBL_DST_PORT_ID_VALID, cfg.dest_port_valid) |
+ FIELD_PREP(PPE_IN_L2_SERVICE_TBL_DST_PORT_ID, cfg.dest_port) |
+ FIELD_PREP(PPE_IN_L2_SERVICE_TBL_DST_DIRECTION, cfg.is_src) |
+ FIELD_PREP(PPE_IN_L2_SERVICE_TBL_DST_BYPASS_BITMAP, cfg.bypass_bitmap[1]) |
+ FIELD_PREP(PPE_IN_L2_SERVICE_TBL_RX_CNT_EN,
+ cfg.bypass_bitmap[2] & BIT(1) ? 1 : 0) |
+ FIELD_PREP(PPE_IN_L2_SERVICE_TBL_TX_CNT_EN,
+ cfg.bypass_bitmap[2] & BIT(3) ? 1 : 0);
+ ppe_write(ppe_dev, PPE_IN_L2_SERVICE_TBL + PPE_IN_L2_SERVICE_TBL_INC * servcode, val);
+
+ ppe_read_tbl(ppe_dev, PPE_SERVICE_TBL + PPE_SERVICE_TBL_INC * servcode,
+ service_cfg.val, sizeof(service_cfg.val));
+ service_cfg.bf.bypass_bitmap = cfg.bypass_bitmap[0];
+ service_cfg.bf.rx_counting_en = cfg.bypass_bitmap[2] & BIT(0);
+ ppe_write_tbl(ppe_dev, PPE_SERVICE_TBL + PPE_SERVICE_TBL_INC * servcode,
+ service_cfg.val, sizeof(service_cfg.val));
+
+ ppe_read_tbl(ppe_dev, PPE_EG_SERVICE_TBL + PPE_EG_SERVICE_TBL_INC * servcode,
+ eg_service_cfg.val, sizeof(eg_service_cfg.val));
+ eg_service_cfg.bf.field_update_action = cfg.field_update_bitmap;
+ eg_service_cfg.bf.next_service_code = cfg.next_service_code;
+ eg_service_cfg.bf.hw_services = cfg.hw_service;
+ eg_service_cfg.bf.offset_sel = cfg.offset_sel;
+ eg_service_cfg.bf.tx_counting_en = cfg.bypass_bitmap[2] & BIT(2) ? 1 : 0;
+ ppe_write_tbl(ppe_dev, PPE_EG_SERVICE_TBL + PPE_EG_SERVICE_TBL_INC * servcode,
+ eg_service_cfg.val, sizeof(eg_service_cfg.val));
+
+ val = FIELD_PREP(PPE_TL_SERVICE_TBL_BYPASS_BITMAP, cfg.bypass_bitmap[3]);
+ return ppe_write(ppe_dev, PPE_TL_SERVICE_TBL + PPE_TL_SERVICE_TBL_INC * servcode, val);
+}
+
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,
@@ -45,6 +45,109 @@ struct ppe_queue_ucast_dest {
int dest_port;
};
+/* bypss_bitmap_0 */
+enum {
+ IN_VLAN_TAG_FMT_CHECK_BYP = 0,
+ IN_VLAN_MEMBER_CHECK_BYP,
+ IN_VLAN_XLT_BYP,
+ MY_MAC_CHECK_BYP,
+ DIP_LOOKUP_BYP,
+ FLOW_LOOKUP_BYP = 5,
+ FLOW_ACTION_BYP,
+ ACL_BYP,
+ FAKE_MAC_HEADER_BYP,
+ SERVICE_CODE_BYP,
+ WRONG_PKT_FMT_L2_BYP = 10,
+ WRONG_PKT_FMT_L3_IPV4_BYP,
+ WRONG_PKT_FMT_L3_IPV6_BYP,
+ WRONG_PKT_FMT_L4_BYP,
+ FLOW_SERVICE_CODE_BYP,
+ ACL_SERVICE_CODE_BYP = 15,
+ FAKE_L2_PROTO_BYP,
+ PPPOE_TERMINATION_BYP,
+ DEFAULT_VLAN_BYP,
+ DEFAULT_PCP_BYP,
+ VSI_ASSIGN_BYP,
+ IN_VLAN_ASSIGN_FAIL_BYP = 24,
+ SOURCE_GUARD_BYP,
+ MRU_MTU_CHECK_BYP,
+ FLOW_SRC_CHECK_BYP,
+ FLOW_QOS_BYP,
+};
+
+/* bypss_bitmap_1 */
+enum {
+ EG_VLAN_MEMBER_CHECK_BYP = 0,
+ EG_VLAN_XLT_BYP,
+ EG_VLAN_TAG_FMT_CTRL_BYP,
+ FDB_LEARN_BYP,
+ FDB_REFRESH_BYP,
+ L2_SOURCE_SEC_BYP = 5,
+ MANAGEMENT_FWD_BYP,
+ BRIDGING_FWD_BYP,
+ IN_STP_FLTR_BYP,
+ EG_STP_FLTR_BYP,
+ SOURCE_FLTR_BYP = 10,
+ POLICER_BYP,
+ L2_PKT_EDIT_BYP,
+ L3_PKT_EDIT_BYP,
+ ACL_POST_ROUTING_CHECK_BYP,
+ PORT_ISOLATION_BYP = 15,
+ PRE_ACL_QOS_BYP,
+ POST_ACL_QOS_BYP,
+ DSCP_QOS_BYP,
+ PCP_QOS_BYP,
+ PREHEADER_QOS_BYP = 20,
+ FAKE_MAC_DROP_BYP,
+ TUNL_CONTEXT_BYP,
+ FLOW_POLICER_BYP,
+};
+
+/* bypss_bitmap_2 */
+enum {
+ RX_VLAN_COUNTER_BYP = 0,
+ RX_COUNTER_BYP,
+ TX_VLAN_COUNTER_BYP,
+ TX_COUNTER_BYP,
+};
+
+/* bypass_bitmap_3 */
+enum {
+ TL_SERVICE_CODE_BYP = 0,
+ TL_BYP,
+ TL_L3_IF_CHECK_BYP,
+ TL_VLAN_CHECK_BYP,
+ TL_DMAC_CHECK_BYP,
+ TL_UDP_CSUM_0_CHECK_BYP = 5,
+ TL_TBL_DE_ACCE_CHECK_BYP,
+ TL_PPPOE_MC_TERM_CHECK_BYP,
+ TL_TTL_EXCEED_CHECK_BYP,
+ TL_MAP_SRC_CHECK_BYP,
+ TL_MAP_DST_CHECK_BYP = 10,
+ TL_LPM_DST_LOOKUP_BYP,
+ TL_LPM_LOOKUP_BYP,
+ TL_WRONG_PKT_FMT_L2_BYP,
+ TL_WRONG_PKT_FMT_L3_IPV4_BYP,
+ TL_WRONG_PKT_FMT_L3_IPV6_BYP = 15,
+ TL_WRONG_PKT_FMT_L4_BYP,
+ TL_WRONG_PKT_FMT_TUNNEL_BYP,
+ TL_PRE_IPO_BYP = 20,
+};
+
+/* PPE service code is used to bypass hardware handler when the packet pass
+ * through PPE, the supported service code number is 256.
+ */
+struct ppe_servcode_cfg {
+ bool dest_port_valid;
+ int dest_port;
+ u32 bypass_bitmap[4];
+ bool is_src;
+ int field_update_bitmap;
+ int next_service_code;
+ int hw_service;
+ int offset_sel;
+};
+
/* The operations are used to configure the PPE queue related resource */
struct ppe_queue_ops {
int (*queue_scheduler_set)(struct ppe_device *ppe_dev,
@@ -76,4 +179,8 @@ struct ppe_queue_ops {
};
const struct ppe_queue_ops *ppe_queue_config_ops_get(void);
+
+int ppe_servcode_config_set(struct ppe_device *ppe_dev,
+ int servcode,
+ struct ppe_servcode_cfg cfg);
#endif
@@ -23,9 +23,71 @@
#define PPE_BM_TDM_CFG_TBL_SECOND_PORT_VALID BIT(6)
#define PPE_BM_TDM_CFG_TBL_SECOND_PORT GENMASK(11, 8)
+#define PPE_SERVICE_TBL 0x15000
+#define PPE_SERVICE_TBL_NUM 256
+#define PPE_SERVICE_TBL_INC 0x10
+#define PPE_SERVICE_TBL_BYPASS_BITMAP GENMASK(31, 0)
+#define PPE_SERVICE_TBL_RX_COUNTING_EN BIT(32)
+
+/* service code for the ingress packet, the PPE features can be bypassed
+ * with service config.
+ */
+struct ppe_service_cfg {
+ u32 bypass_bitmap;
+ u32 rx_counting_en:1,
+ res0:31;
+};
+
+union ppe_service_cfg_u {
+ u32 val[2];
+ struct ppe_service_cfg bf;
+};
+
#define PPE_EG_BRIDGE_CONFIG 0x20044
#define PPE_EG_BRIDGE_CONFIG_QUEUE_CNT_EN BIT(2)
+#define PPE_EG_SERVICE_TBL 0x43000
+#define PPE_EG_SERVICE_TBL_NUM 256
+#define PPE_EG_SERVICE_TBL_INC 0x10
+
+/* service code config for the egress packet, the new service code can be
+ * generated and ath header can be configured.
+ */
+struct ppe_eg_service_cfg {
+ u32 field_update_action;
+ u32 next_service_code:8,
+ hw_services:6,
+ offset_sel:1,
+ tx_counting_en:1,
+ ip_length_update:1,
+ ath_hdr_insert_dis:1,
+ ath_hdr_type:3,
+ ath_from_cpu:1,
+ ath_disable_bit:1,
+ ath_port_bitmap:7,
+ res0:2;
+};
+
+union ppe_eg_service_cfg_u {
+ u32 val[2];
+ struct ppe_eg_service_cfg bf;
+};
+
+#define PPE_IN_L2_SERVICE_TBL 0x66000
+#define PPE_IN_L2_SERVICE_TBL_NUM 256
+#define PPE_IN_L2_SERVICE_TBL_INC 0x10
+#define PPE_IN_L2_SERVICE_TBL_DST_PORT_ID_VALID BIT(0)
+#define PPE_IN_L2_SERVICE_TBL_DST_PORT_ID GENMASK(4, 1)
+#define PPE_IN_L2_SERVICE_TBL_DST_DIRECTION BIT(5)
+#define PPE_IN_L2_SERVICE_TBL_DST_BYPASS_BITMAP GENMASK(29, 6)
+#define PPE_IN_L2_SERVICE_TBL_RX_CNT_EN BIT(30)
+#define PPE_IN_L2_SERVICE_TBL_TX_CNT_EN BIT(31)
+
+#define PPE_TL_SERVICE_TBL 0x306000
+#define PPE_TL_SERVICE_TBL_NUM 256
+#define PPE_TL_SERVICE_TBL_INC 4
+#define PPE_TL_SERVICE_TBL_BYPASS_BITMAP GENMASK(31, 0)
+
#define PPE_PSCH_TDM_DEPTH_CFG 0x400000
#define PPE_PSCH_TDM_DEPTH_CFG_NUM 1
#define PPE_PSCH_TDM_DEPTH_CFG_INC 4
The service code is used to bypass some PPE handlers when the packet is passed through PPE. Signed-off-by: Luo Jie <quic_luoj@quicinc.com> --- drivers/net/ethernet/qualcomm/ppe/ppe.c | 22 +++- drivers/net/ethernet/qualcomm/ppe/ppe_ops.c | 42 ++++++++ drivers/net/ethernet/qualcomm/ppe/ppe_ops.h | 107 +++++++++++++++++++ drivers/net/ethernet/qualcomm/ppe/ppe_regs.h | 62 +++++++++++ 4 files changed, 232 insertions(+), 1 deletion(-)