This patch adds necessary APIs to interface with
qede aRFS support in successive patch.

It also reserves separate PTT entry for aRFS,
[as being in fastpath flow] for hardware access instead of
trying to acquire it at run time from the ptt pool.

Signed-off-by: Manish Chopra <manish.cho...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed.h              |   2 +
 drivers/net/ethernet/qlogic/qed/qed_cxt.c          |  13 +-
 drivers/net/ethernet/qlogic/qed/qed_hsi.h          | 187 +++++++++++++++++++++
 .../net/ethernet/qlogic/qed/qed_init_fw_funcs.c    | 129 ++++++++++++++
 drivers/net/ethernet/qlogic/qed/qed_l2.c           | 133 +++++++++++++++
 drivers/net/ethernet/qlogic/qed/qed_l2.h           |   8 +
 drivers/net/ethernet/qlogic/qed/qed_main.c         |  26 +++
 drivers/net/ethernet/qlogic/qed/qed_reg_addr.h     |   8 +
 drivers/net/ethernet/qlogic/qed/qed_sp.h           |   1 +
 include/linux/qed/qed_eth_if.h                     |   8 +
 include/linux/qed/qed_if.h                         |   7 +
 11 files changed, 519 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed.h 
b/drivers/net/ethernet/qlogic/qed/qed.h
index 4896ee0..c539ba1 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -504,6 +504,8 @@ struct qed_hwfn {
        u8 dcbx_no_edpm;
        u8 db_bar_no_edpm;
 
+       struct qed_ptt *p_arfs_ptt;
+
        /* p_ptp_ptt is valid for leading HWFN only */
        struct qed_ptt *p_ptp_ptt;
        struct qed_simd_fp_handler      simd_proto_handler[64];
diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c 
b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index 15ef6eb..b3aaa98 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -219,9 +219,6 @@ struct qed_cxt_mngr {
         */
        u32                             vf_count;
 
-       /* total number of SRQ's for this hwfn */
-       u32 srq_count;
-
        /* Acquired CIDs */
        struct qed_cid_acquired_map     acquired[MAX_CONN_TYPES];
 
@@ -237,6 +234,12 @@ struct qed_cxt_mngr {
        u32 t2_num_pages;
        u64 first_free;
        u64 last_free;
+
+       /* total number of SRQ's for this hwfn */
+       u32 srq_count;
+
+       /* Maximal number of L2 steering filters */
+       u32 arfs_count;
 };
 static bool src_proto(enum protocol_type type)
 {
@@ -291,6 +294,9 @@ static void qed_cxt_src_iids(struct qed_cxt_mngr *p_mngr,
                iids->pf_cids += p_mngr->conn_cfg[i].cid_count;
                iids->per_vf_cids += p_mngr->conn_cfg[i].cids_per_vf;
        }
+
+       /* Add L2 filtering filters in addition */
+       iids->pf_cids += p_mngr->arfs_count;
 }
 
 /* counts the iids for the Timers block configuration */
@@ -2007,6 +2013,7 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 
rdma_tasks)
 
                qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_ETH,
                                            p_params->num_cons, 1);
+               p_hwfn->p_cxt_mngr->arfs_count = p_params->num_arfs_filters;
                break;
        }
        case QED_PCI_FCOE:
diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h 
b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
index 815c4ec..858a57a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
@@ -3473,6 +3473,11 @@ void qed_set_geneve_dest_port(struct qed_hwfn *p_hwfn,
 void qed_set_geneve_enable(struct qed_hwfn *p_hwfn,
                           struct qed_ptt *p_ptt,
                           bool eth_geneve_enable, bool ip_geneve_enable);
+void qed_set_rfs_mode_disable(struct qed_hwfn *p_hwfn,
+                             struct qed_ptt *p_ptt, u16 pf_id);
+void qed_set_rfs_mode_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+                            u16 pf_id, bool tcp, bool udp,
+                            bool ipv4, bool ipv6);
 
 #define        YSTORM_FLOW_CONTROL_MODE_OFFSET                 (IRO[0].base)
 #define        YSTORM_FLOW_CONTROL_MODE_SIZE                   (IRO[0].size)
@@ -4862,6 +4867,18 @@ struct eth_vport_tx_mode {
        __le16 reserved2[3];
 };
 
+enum gft_filter_update_action {
+       GFT_ADD_FILTER,
+       GFT_DELETE_FILTER,
+       MAX_GFT_FILTER_UPDATE_ACTION
+};
+
+enum gft_logic_filter_type {
+       GFT_FILTER_TYPE,
+       RFS_FILTER_TYPE,
+       MAX_GFT_LOGIC_FILTER_TYPE
+};
+
 /* Ramrod data for rx queue start ramrod */
 struct rx_queue_start_ramrod_data {
        __le16 rx_queue_id;
@@ -4932,6 +4949,16 @@ struct rx_udp_filter_data {
        __le32 tenant_id;
 };
 
+struct rx_update_gft_filter_data {
+       struct regpair pkt_hdr_addr;
+       __le16 pkt_hdr_length;
+       __le16 rx_qid_or_action_icid;
+       u8 vport_id;
+       u8 filter_type;
+       u8 filter_action;
+       u8 reserved;
+};
+
 /* Ramrod data for rx queue start ramrod */
 struct tx_queue_start_ramrod_data {
        __le16 sb_id;
@@ -5075,6 +5102,166 @@ struct vport_update_ramrod_data {
        struct eth_vport_rss_config rss_config;
 };
 
+struct gft_cam_line {
+       __le32 camline;
+#define GFT_CAM_LINE_VALID_MASK                0x1
+#define GFT_CAM_LINE_VALID_SHIFT       0
+#define GFT_CAM_LINE_DATA_MASK         0x3FFF
+#define GFT_CAM_LINE_DATA_SHIFT                1
+#define GFT_CAM_LINE_MASK_BITS_MASK    0x3FFF
+#define GFT_CAM_LINE_MASK_BITS_SHIFT   15
+#define GFT_CAM_LINE_RESERVED1_MASK    0x7
+#define GFT_CAM_LINE_RESERVED1_SHIFT   29
+};
+
+struct gft_cam_line_mapped {
+       __le32 camline;
+#define GFT_CAM_LINE_MAPPED_VALID_MASK                         0x1
+#define GFT_CAM_LINE_MAPPED_VALID_SHIFT                                0
+#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK                    0x1
+#define GFT_CAM_LINE_MAPPED_IP_VERSION_SHIFT                   1
+#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK             0x1
+#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_SHIFT            2
+#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK           0xF
+#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_SHIFT          3
+#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK                   0xF
+#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_SHIFT                  7
+#define GFT_CAM_LINE_MAPPED_PF_ID_MASK                         0xF
+#define GFT_CAM_LINE_MAPPED_PF_ID_SHIFT                                11
+#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK_MASK               0x1
+#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK_SHIFT              15
+#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK_MASK                0x1
+#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK_SHIFT       16
+#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_MASK      0xF
+#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_SHIFT     17
+#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK_MASK              0xF
+#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK_SHIFT             21
+#define GFT_CAM_LINE_MAPPED_PF_ID_MASK_MASK                    0xF
+#define GFT_CAM_LINE_MAPPED_PF_ID_MASK_SHIFT                   25
+#define GFT_CAM_LINE_MAPPED_RESERVED1_MASK                     0x7
+#define GFT_CAM_LINE_MAPPED_RESERVED1_SHIFT                    29
+};
+
+union gft_cam_line_union {
+       struct gft_cam_line cam_line;
+       struct gft_cam_line_mapped cam_line_mapped;
+};
+
+enum gft_profile_ip_version {
+       GFT_PROFILE_IPV4 = 0,
+       GFT_PROFILE_IPV6 = 1,
+       MAX_GFT_PROFILE_IP_VERSION
+};
+
+enum gft_profile_upper_protocol_type {
+       GFT_PROFILE_ROCE_PROTOCOL = 0,
+       GFT_PROFILE_RROCE_PROTOCOL = 1,
+       GFT_PROFILE_FCOE_PROTOCOL = 2,
+       GFT_PROFILE_ICMP_PROTOCOL = 3,
+       GFT_PROFILE_ARP_PROTOCOL = 4,
+       GFT_PROFILE_USER_TCP_SRC_PORT_1_INNER = 5,
+       GFT_PROFILE_USER_TCP_DST_PORT_1_INNER = 6,
+       GFT_PROFILE_TCP_PROTOCOL = 7,
+       GFT_PROFILE_USER_UDP_DST_PORT_1_INNER = 8,
+       GFT_PROFILE_USER_UDP_DST_PORT_2_OUTER = 9,
+       GFT_PROFILE_UDP_PROTOCOL = 10,
+       GFT_PROFILE_USER_IP_1_INNER = 11,
+       GFT_PROFILE_USER_IP_2_OUTER = 12,
+       GFT_PROFILE_USER_ETH_1_INNER = 13,
+       GFT_PROFILE_USER_ETH_2_OUTER = 14,
+       GFT_PROFILE_RAW = 15,
+       MAX_GFT_PROFILE_UPPER_PROTOCOL_TYPE
+};
+
+struct gft_ram_line {
+       __le32 low32bits;
+#define GFT_RAM_LINE_VLAN_SELECT_MASK                  0x3
+#define GFT_RAM_LINE_VLAN_SELECT_SHIFT                 0
+#define GFT_RAM_LINE_TUNNEL_ENTROPHY_MASK              0x1
+#define GFT_RAM_LINE_TUNNEL_ENTROPHY_SHIFT             2
+#define GFT_RAM_LINE_TUNNEL_TTL_EQUAL_ONE_MASK         0x1
+#define GFT_RAM_LINE_TUNNEL_TTL_EQUAL_ONE_SHIFT                3
+#define GFT_RAM_LINE_TUNNEL_TTL_MASK                   0x1
+#define GFT_RAM_LINE_TUNNEL_TTL_SHIFT                  4
+#define GFT_RAM_LINE_TUNNEL_ETHERTYPE_MASK             0x1
+#define GFT_RAM_LINE_TUNNEL_ETHERTYPE_SHIFT            5
+#define GFT_RAM_LINE_TUNNEL_DST_PORT_MASK              0x1
+#define GFT_RAM_LINE_TUNNEL_DST_PORT_SHIFT             6
+#define GFT_RAM_LINE_TUNNEL_SRC_PORT_MASK              0x1
+#define GFT_RAM_LINE_TUNNEL_SRC_PORT_SHIFT             7
+#define GFT_RAM_LINE_TUNNEL_DSCP_MASK                  0x1
+#define GFT_RAM_LINE_TUNNEL_DSCP_SHIFT                 8
+#define GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL_MASK      0x1
+#define GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL_SHIFT     9
+#define GFT_RAM_LINE_TUNNEL_DST_IP_MASK                        0x1
+#define GFT_RAM_LINE_TUNNEL_DST_IP_SHIFT               10
+#define GFT_RAM_LINE_TUNNEL_SRC_IP_MASK                        0x1
+#define GFT_RAM_LINE_TUNNEL_SRC_IP_SHIFT               11
+#define GFT_RAM_LINE_TUNNEL_PRIORITY_MASK              0x1
+#define GFT_RAM_LINE_TUNNEL_PRIORITY_SHIFT             12
+#define GFT_RAM_LINE_TUNNEL_PROVIDER_VLAN_MASK         0x1
+#define GFT_RAM_LINE_TUNNEL_PROVIDER_VLAN_SHIFT                13
+#define GFT_RAM_LINE_TUNNEL_VLAN_MASK                  0x1
+#define GFT_RAM_LINE_TUNNEL_VLAN_SHIFT                 14
+#define GFT_RAM_LINE_TUNNEL_DST_MAC_MASK               0x1
+#define GFT_RAM_LINE_TUNNEL_DST_MAC_SHIFT              15
+#define GFT_RAM_LINE_TUNNEL_SRC_MAC_MASK               0x1
+#define GFT_RAM_LINE_TUNNEL_SRC_MAC_SHIFT              16
+#define GFT_RAM_LINE_TTL_EQUAL_ONE_MASK                        0x1
+#define GFT_RAM_LINE_TTL_EQUAL_ONE_SHIFT               17
+#define GFT_RAM_LINE_TTL_MASK                          0x1
+#define GFT_RAM_LINE_TTL_SHIFT                         18
+#define GFT_RAM_LINE_ETHERTYPE_MASK                    0x1
+#define GFT_RAM_LINE_ETHERTYPE_SHIFT                   19
+#define GFT_RAM_LINE_RESERVED0_MASK                    0x1
+#define GFT_RAM_LINE_RESERVED0_SHIFT                   20
+#define GFT_RAM_LINE_TCP_FLAG_FIN_MASK                 0x1
+#define GFT_RAM_LINE_TCP_FLAG_FIN_SHIFT                        21
+#define GFT_RAM_LINE_TCP_FLAG_SYN_MASK                 0x1
+#define GFT_RAM_LINE_TCP_FLAG_SYN_SHIFT                        22
+#define GFT_RAM_LINE_TCP_FLAG_RST_MASK                 0x1
+#define GFT_RAM_LINE_TCP_FLAG_RST_SHIFT                        23
+#define GFT_RAM_LINE_TCP_FLAG_PSH_MASK                 0x1
+#define GFT_RAM_LINE_TCP_FLAG_PSH_SHIFT                        24
+#define GFT_RAM_LINE_TCP_FLAG_ACK_MASK                 0x1
+#define GFT_RAM_LINE_TCP_FLAG_ACK_SHIFT                        25
+#define GFT_RAM_LINE_TCP_FLAG_URG_MASK                 0x1
+#define GFT_RAM_LINE_TCP_FLAG_URG_SHIFT                        26
+#define GFT_RAM_LINE_TCP_FLAG_ECE_MASK                 0x1
+#define GFT_RAM_LINE_TCP_FLAG_ECE_SHIFT                        27
+#define GFT_RAM_LINE_TCP_FLAG_CWR_MASK                 0x1
+#define GFT_RAM_LINE_TCP_FLAG_CWR_SHIFT                        28
+#define GFT_RAM_LINE_TCP_FLAG_NS_MASK                  0x1
+#define GFT_RAM_LINE_TCP_FLAG_NS_SHIFT                 29
+#define GFT_RAM_LINE_DST_PORT_MASK                     0x1
+#define GFT_RAM_LINE_DST_PORT_SHIFT                    30
+#define GFT_RAM_LINE_SRC_PORT_MASK                     0x1
+#define GFT_RAM_LINE_SRC_PORT_SHIFT                    31
+       __le32 high32bits;
+#define GFT_RAM_LINE_DSCP_MASK                         0x1
+#define GFT_RAM_LINE_DSCP_SHIFT                                0
+#define GFT_RAM_LINE_OVER_IP_PROTOCOL_MASK             0x1
+#define GFT_RAM_LINE_OVER_IP_PROTOCOL_SHIFT            1
+#define GFT_RAM_LINE_DST_IP_MASK                       0x1
+#define GFT_RAM_LINE_DST_IP_SHIFT                      2
+#define GFT_RAM_LINE_SRC_IP_MASK                       0x1
+#define GFT_RAM_LINE_SRC_IP_SHIFT                      3
+#define GFT_RAM_LINE_PRIORITY_MASK                     0x1
+#define GFT_RAM_LINE_PRIORITY_SHIFT                    4
+#define GFT_RAM_LINE_PROVIDER_VLAN_MASK                        0x1
+#define GFT_RAM_LINE_PROVIDER_VLAN_SHIFT               5
+#define GFT_RAM_LINE_VLAN_MASK                         0x1
+#define GFT_RAM_LINE_VLAN_SHIFT                                6
+#define GFT_RAM_LINE_DST_MAC_MASK                      0x1
+#define GFT_RAM_LINE_DST_MAC_SHIFT                     7
+#define GFT_RAM_LINE_SRC_MAC_MASK                      0x1
+#define GFT_RAM_LINE_SRC_MAC_SHIFT                     8
+#define GFT_RAM_LINE_TENANT_ID_MASK                    0x1
+#define GFT_RAM_LINE_TENANT_ID_SHIFT                   9
+#define GFT_RAM_LINE_RESERVED1_MASK                    0x3FFFFF
+#define GFT_RAM_LINE_RESERVED1_SHIFT                   10
+};
+
 struct mstorm_eth_conn_ag_ctx {
        u8 byte0;
        u8 byte1;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c 
b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c
index 2a50e2b..67200c5 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c
@@ -961,3 +961,132 @@ void qed_set_geneve_enable(struct qed_hwfn *p_hwfn,
        qed_wr(p_hwfn, p_ptt, DORQ_REG_L2_EDPM_TUNNEL_NGE_IP_EN,
               ip_geneve_enable ? 1 : 0);
 }
+
+#define T_ETH_PACKET_MATCH_RFS_EVENTID 25
+#define PARSER_ETH_CONN_CM_HDR (0x0)
+#define CAM_LINE_SIZE sizeof(u32)
+#define RAM_LINE_SIZE sizeof(u64)
+#define REG_SIZE sizeof(u32)
+
+void qed_set_rfs_mode_disable(struct qed_hwfn *p_hwfn,
+                             struct qed_ptt *p_ptt, u16 pf_id)
+{
+       union gft_cam_line_union camline;
+       struct gft_ram_line ramline;
+       u32 *p_ramline, i;
+
+       p_ramline = (u32 *)&ramline;
+
+       /*stop using gft logic */
+       qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_GFT, 0);
+       qed_wr(p_hwfn, p_ptt, PRS_REG_CM_HDR_GFT, 0x0);
+       memset(&camline, 0, sizeof(union gft_cam_line_union));
+       qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id,
+              camline.cam_line_mapped.camline);
+       memset(&ramline, 0, sizeof(union gft_cam_line_union));
+
+       for (i = 0; i < RAM_LINE_SIZE / REG_SIZE; i++) {
+               u32 hw_addr = PRS_REG_GFT_PROFILE_MASK_RAM;
+
+               hw_addr += (RAM_LINE_SIZE * pf_id + i * REG_SIZE);
+
+               qed_wr(p_hwfn, p_ptt, hw_addr, *(p_ramline + i));
+       }
+}
+
+void qed_set_rfs_mode_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+                            u16 pf_id, bool tcp, bool udp,
+                            bool ipv4, bool ipv6)
+{
+       u32 rfs_cm_hdr_event_id, *p_ramline;
+       union gft_cam_line_union camline;
+       struct gft_ram_line ramline;
+       int i;
+
+       rfs_cm_hdr_event_id = qed_rd(p_hwfn, p_ptt, PRS_REG_CM_HDR_GFT);
+       p_ramline = (u32 *)&ramline;
+
+       if (!ipv6 && !ipv4)
+               DP_NOTICE(p_hwfn,
+                         "set_rfs_mode_enable: must accept at least on of - 
ipv4 or ipv6");
+       if (!tcp && !udp)
+               DP_NOTICE(p_hwfn,
+                         "set_rfs_mode_enable: must accept at least on of - 
udp or tcp");
+
+       rfs_cm_hdr_event_id |= T_ETH_PACKET_MATCH_RFS_EVENTID <<
+                                       PRS_REG_CM_HDR_GFT_EVENT_ID_SHIFT;
+       rfs_cm_hdr_event_id |= PARSER_ETH_CONN_CM_HDR <<
+                                       PRS_REG_CM_HDR_GFT_CM_HDR_SHIFT;
+       qed_wr(p_hwfn, p_ptt, PRS_REG_CM_HDR_GFT, rfs_cm_hdr_event_id);
+
+       /* Configure Registers for RFS mode */
+       qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_GFT, 1);
+       qed_wr(p_hwfn, p_ptt, PRS_REG_LOAD_L2_FILTER, 0);
+       camline.cam_line_mapped.camline = 0;
+
+       /* cam line is now valid!! */
+       SET_FIELD(camline.cam_line_mapped.camline,
+                 GFT_CAM_LINE_MAPPED_VALID, 1);
+
+       /* filters are per PF!! */
+       SET_FIELD(camline.cam_line_mapped.camline,
+                 GFT_CAM_LINE_MAPPED_PF_ID_MASK, 1);
+       SET_FIELD(camline.cam_line_mapped.camline,
+                 GFT_CAM_LINE_MAPPED_PF_ID, pf_id);
+       if (!(tcp && udp)) {
+               SET_FIELD(camline.cam_line_mapped.camline,
+                         GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK, 1);
+               if (tcp)
+                       SET_FIELD(camline.cam_line_mapped.camline,
+                                 GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE,
+                                 GFT_PROFILE_TCP_PROTOCOL);
+               else
+                       SET_FIELD(camline.cam_line_mapped.camline,
+                                 GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE,
+                                 GFT_PROFILE_UDP_PROTOCOL);
+       }
+
+       if (!(ipv4 && ipv6)) {
+               SET_FIELD(camline.cam_line_mapped.camline,
+                         GFT_CAM_LINE_MAPPED_IP_VERSION_MASK, 1);
+               if (ipv4)
+                       SET_FIELD(camline.cam_line_mapped.camline,
+                                 GFT_CAM_LINE_MAPPED_IP_VERSION,
+                                 GFT_PROFILE_IPV4);
+               else
+                       SET_FIELD(camline.cam_line_mapped.camline,
+                                 GFT_CAM_LINE_MAPPED_IP_VERSION,
+                                 GFT_PROFILE_IPV6);
+       }
+
+       /* write characteristics to cam */
+       qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id,
+              camline.cam_line_mapped.camline);
+       camline.cam_line_mapped.camline = qed_rd(p_hwfn, p_ptt,
+                                                PRS_REG_GFT_CAM +
+                                                CAM_LINE_SIZE * pf_id);
+
+       /* write line to RAM - compare to filter 4 tuple */
+       ramline.low32bits = 0;
+       ramline.high32bits = 0;
+       SET_FIELD(ramline.high32bits, GFT_RAM_LINE_DST_IP, 1);
+       SET_FIELD(ramline.high32bits, GFT_RAM_LINE_SRC_IP, 1);
+       SET_FIELD(ramline.low32bits, GFT_RAM_LINE_SRC_PORT, 1);
+       SET_FIELD(ramline.low32bits, GFT_RAM_LINE_DST_PORT, 1);
+
+       /* each iteration write to reg */
+       for (i = 0; i < RAM_LINE_SIZE / REG_SIZE; i++)
+               qed_wr(p_hwfn, p_ptt,
+                      PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id +
+                      i * REG_SIZE, *(p_ramline + i));
+
+       /* set default profile so that no filter match will happen */
+       ramline.low32bits = 0xffff;
+       ramline.high32bits = 0xffff;
+
+       for (i = 0; i < RAM_LINE_SIZE / REG_SIZE; i++)
+               qed_wr(p_hwfn, p_ptt,
+                      PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE *
+                      PRS_GFT_CAM_LINES_NO_MATCH + i * REG_SIZE,
+                      *(p_ramline + i));
+}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c 
b/drivers/net/ethernet/qlogic/qed/qed_l2.c
index d56441d..eb5e280 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_l2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c
@@ -1799,6 +1799,84 @@ void qed_reset_vport_stats(struct qed_dev *cdev)
                _qed_get_vport_stats(cdev, cdev->reset_stats);
 }
 
+static void
+qed_arfs_mode_configure(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+                       struct qed_arfs_config_params *p_cfg_params)
+{
+       if (p_cfg_params->arfs_enable) {
+               qed_set_rfs_mode_enable(p_hwfn, p_ptt, p_hwfn->rel_pf_id,
+                                       p_cfg_params->tcp, p_cfg_params->udp,
+                                       p_cfg_params->ipv4, p_cfg_params->ipv6);
+               DP_VERBOSE(p_hwfn, QED_MSG_SP,
+                          "tcp = %s, udp = %s, ipv4 = %s, ipv6 =%s\n",
+                          p_cfg_params->tcp ? "Enable" : "Disable",
+                          p_cfg_params->udp ? "Enable" : "Disable",
+                          p_cfg_params->ipv4 ? "Enable" : "Disable",
+                          p_cfg_params->ipv6 ? "Enable" : "Disable");
+       } else {
+               qed_set_rfs_mode_disable(p_hwfn, p_ptt, p_hwfn->rel_pf_id);
+       }
+
+       DP_VERBOSE(p_hwfn, QED_MSG_SP, "Configured ARFS mode : %s\n",
+                  p_cfg_params->arfs_enable ? "Enable" : "Disable");
+}
+
+static int
+qed_configure_rfs_ntuple_filter(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+                               struct qed_spq_comp_cb *p_cb,
+                               dma_addr_t p_addr, u16 length, u16 qid,
+                               u8 vport_id, bool b_is_add)
+{
+       struct rx_update_gft_filter_data *p_ramrod = NULL;
+       struct qed_spq_entry *p_ent = NULL;
+       struct qed_sp_init_data init_data;
+       u16 abs_rx_q_id = 0;
+       u8 abs_vport_id = 0;
+       int rc = -EINVAL;
+
+       rc = qed_fw_vport(p_hwfn, vport_id, &abs_vport_id);
+       if (rc)
+               return rc;
+
+       rc = qed_fw_l2_queue(p_hwfn, qid, &abs_rx_q_id);
+       if (rc)
+               return rc;
+
+       /* Get SPQ entry */
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = qed_spq_get_cid(p_hwfn);
+
+       init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+
+       if (p_cb) {
+               init_data.comp_mode = QED_SPQ_MODE_CB;
+               init_data.p_comp_data = p_cb;
+       } else {
+               init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
+       }
+
+       rc = qed_sp_init_request(p_hwfn, &p_ent,
+                                ETH_RAMROD_GFT_UPDATE_FILTER,
+                                PROTOCOLID_ETH, &init_data);
+       if (rc)
+               return rc;
+
+       p_ramrod = &p_ent->ramrod.rx_update_gft;
+       DMA_REGPAIR_LE(p_ramrod->pkt_hdr_addr, p_addr);
+       p_ramrod->pkt_hdr_length = cpu_to_le16(length);
+       p_ramrod->rx_qid_or_action_icid = cpu_to_le16(abs_rx_q_id);
+       p_ramrod->vport_id = abs_vport_id;
+       p_ramrod->filter_type = RFS_FILTER_TYPE;
+       p_ramrod->filter_action = b_is_add ? GFT_ADD_FILTER : GFT_DELETE_FILTER;
+
+       DP_VERBOSE(p_hwfn, QED_MSG_SP,
+                  "V[%0x], Q[%04x] - %s filter from 0x%llx [length %04xb]\n",
+                  abs_vport_id, abs_rx_q_id,
+                  b_is_add ? "Adding" : "Removing", (u64)p_addr, length);
+
+       return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
 static int qed_fill_eth_dev_info(struct qed_dev *cdev,
                                 struct qed_dev_eth_info *info)
 {
@@ -2356,6 +2434,59 @@ static int qed_configure_filter(struct qed_dev *cdev,
        }
 }
 
+static int qed_configure_arfs_searcher(struct qed_dev *cdev, bool en_searcher)
+{
+       struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+       struct qed_arfs_config_params arfs_config_params;
+
+       memset(&arfs_config_params, 0, sizeof(arfs_config_params));
+       arfs_config_params.tcp = true;
+       arfs_config_params.udp = true;
+       arfs_config_params.ipv4 = true;
+       arfs_config_params.ipv6 = true;
+       arfs_config_params.arfs_enable = en_searcher;
+
+       qed_arfs_mode_configure(p_hwfn, p_hwfn->p_arfs_ptt,
+                               &arfs_config_params);
+       return 0;
+}
+
+static void
+qed_arfs_sp_response_handler(struct qed_hwfn *p_hwfn,
+                            void *cookie, union event_ring_data *data,
+                            u8 fw_return_code)
+{
+       struct qed_common_cb_ops *op = p_hwfn->cdev->protocol_ops.common;
+       void *dev = p_hwfn->cdev->ops_cookie;
+
+       op->arfs_filter_op(dev, cookie, fw_return_code);
+}
+
+static int qed_ntuple_arfs_filter_config(struct qed_dev *cdev, void *cookie,
+                                        dma_addr_t mapping, u16 length,
+                                        u16 vport_id, u16 rx_queue_id,
+                                        bool add_filter)
+{
+       struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+       struct qed_spq_comp_cb cb;
+       int rc = -EINVAL;
+
+       cb.function = qed_arfs_sp_response_handler;
+       cb.cookie = cookie;
+
+       rc = qed_configure_rfs_ntuple_filter(p_hwfn, p_hwfn->p_arfs_ptt,
+                                            &cb, mapping, length, rx_queue_id,
+                                            vport_id, add_filter);
+       if (rc)
+               DP_NOTICE(p_hwfn,
+                         "Failed to issue a-RFS filter configuration\n");
+       else
+               DP_VERBOSE(p_hwfn, NETIF_MSG_DRV,
+                          "Successfully issued a-RFS filter configuration\n");
+
+       return rc;
+}
+
 static int qed_fp_cqe_completion(struct qed_dev *dev,
                                 u8 rss_id, struct eth_slow_path_rx_cqe *cqe)
 {
@@ -2397,6 +2528,8 @@ static const struct qed_eth_ops qed_eth_ops_pass = {
        .eth_cqe_completion = &qed_fp_cqe_completion,
        .get_vport_stats = &qed_get_vport_stats,
        .tunn_config = &qed_tunn_configure,
+       .ntuple_filter_config = &qed_ntuple_arfs_filter_config,
+       .configure_arfs_searcher = &qed_configure_arfs_searcher,
 };
 
 const struct qed_eth_ops *qed_get_eth_ops(void)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.h 
b/drivers/net/ethernet/qlogic/qed/qed_l2.h
index e763abd..6f44229 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_l2.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_l2.h
@@ -185,6 +185,14 @@ struct qed_filter_accept_flags {
 #define QED_ACCEPT_BCAST                0x20
 };
 
+struct qed_arfs_config_params {
+       bool tcp;
+       bool udp;
+       bool ipv4;
+       bool ipv6;
+       bool arfs_enable;
+};
+
 struct qed_sp_vport_update_params {
        u16                             opaque_fid;
        u8                              vport_id;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c 
b/drivers/net/ethernet/qlogic/qed/qed_main.c
index 029f431..da562cf 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_main.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
@@ -883,6 +883,9 @@ static void qed_update_pf_params(struct qed_dev *cdev,
                params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX;
        }
 
+       if (cdev->num_hwfns > 1 || IS_VF(cdev))
+               params->eth_pf_params.num_arfs_filters = 0;
+
        /* In case we might support RDMA, don't allow qede to be greedy
         * with the L2 contexts. Allow for 64 queues [rx, tx, xdp] per hwfn.
         */
@@ -926,6 +929,18 @@ static int qed_slowpath_start(struct qed_dev *cdev,
                        goto err;
                }
 
+#ifdef CONFIG_RFS_ACCEL
+               if (cdev->num_hwfns == 1) {
+                       p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev));
+                       if (p_ptt) {
+                               QED_LEADING_HWFN(cdev)->p_arfs_ptt = p_ptt;
+                       } else {
+                               DP_NOTICE(cdev,
+                                         "Failed to acquire PTT for aRFS\n");
+                               goto err;
+                       }
+               }
+#endif
                p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev));
                if (p_ptt) {
                        QED_LEADING_HWFN(cdev)->p_ptp_ptt = p_ptt;
@@ -1032,6 +1047,12 @@ static int qed_slowpath_start(struct qed_dev *cdev,
        if (IS_PF(cdev))
                release_firmware(cdev->firmware);
 
+#ifdef CONFIG_RFS_ACCEL
+       if (IS_PF(cdev) && (cdev->num_hwfns == 1) &&
+           QED_LEADING_HWFN(cdev)->p_arfs_ptt)
+               qed_ptt_release(QED_LEADING_HWFN(cdev),
+                               QED_LEADING_HWFN(cdev)->p_arfs_ptt);
+#endif
        if (IS_PF(cdev) && QED_LEADING_HWFN(cdev)->p_ptp_ptt)
                qed_ptt_release(QED_LEADING_HWFN(cdev),
                                QED_LEADING_HWFN(cdev)->p_ptp_ptt);
@@ -1049,6 +1070,11 @@ static int qed_slowpath_stop(struct qed_dev *cdev)
        qed_ll2_dealloc_if(cdev);
 
        if (IS_PF(cdev)) {
+#ifdef CONFIG_RFS_ACCEL
+               if (cdev->num_hwfns == 1)
+                       qed_ptt_release(QED_LEADING_HWFN(cdev),
+                                       QED_LEADING_HWFN(cdev)->p_arfs_ptt);
+#endif
                qed_ptt_release(QED_LEADING_HWFN(cdev),
                                QED_LEADING_HWFN(cdev)->p_ptp_ptt);
                qed_free_stream_mem(cdev);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h 
b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
index e65397360..1ae73b2 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
@@ -1560,4 +1560,12 @@
 #define NIG_REG_TSGEN_FREECNT_UPDATE_K2 0x509008UL
 #define CNIG_REG_NIG_PORT0_CONF_K2 0x218200UL
 
+#define PRS_REG_SEARCH_GFT 0x1f11bcUL
+#define PRS_REG_CM_HDR_GFT 0x1f11c8UL
+#define PRS_REG_GFT_CAM 0x1f1100UL
+#define PRS_REG_GFT_PROFILE_MASK_RAM 0x1f1000UL
+#define PRS_REG_CM_HDR_GFT_EVENT_ID_SHIFT 0
+#define PRS_REG_CM_HDR_GFT_CM_HDR_SHIFT 8
+#define PRS_REG_LOAD_L2_FILTER 0x1f0198UL
+
 #endif
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h 
b/drivers/net/ethernet/qlogic/qed/qed_sp.h
index 30393ff..583c8d3 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h
@@ -84,6 +84,7 @@ union ramrod_data {
        struct tx_queue_stop_ramrod_data tx_queue_stop;
        struct vport_start_ramrod_data vport_start;
        struct vport_stop_ramrod_data vport_stop;
+       struct rx_update_gft_filter_data rx_update_gft;
        struct vport_update_ramrod_data vport_update;
        struct core_rx_start_ramrod_data core_rx_queue_start;
        struct core_rx_stop_ramrod_data core_rx_queue_stop;
diff --git a/include/linux/qed/qed_eth_if.h b/include/linux/qed/qed_eth_if.h
index 4cd1f0c..1eba803c 100644
--- a/include/linux/qed/qed_eth_if.h
+++ b/include/linux/qed/qed_eth_if.h
@@ -301,6 +301,14 @@ struct qed_eth_ops {
 
        int (*tunn_config)(struct qed_dev *cdev,
                           struct qed_tunn_params *params);
+
+       int (*ntuple_filter_config)(struct qed_dev *cdev, void *cookie,
+                                   dma_addr_t mapping, u16 length,
+                                   u16 vport_id, u16 rx_queue_id,
+                                   bool add_filter);
+
+       int (*configure_arfs_searcher)(struct qed_dev *cdev,
+                                      bool en_searcher);
 };
 
 const struct qed_eth_ops *qed_get_eth_ops(void);
diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h
index 625f80f..d44933a 100644
--- a/include/linux/qed/qed_if.h
+++ b/include/linux/qed/qed_if.h
@@ -178,6 +178,12 @@ struct qed_eth_pf_params {
         * to update_pf_params routine invoked before slowpath start
         */
        u16 num_cons;
+
+       /* To enable arfs, previous to HW-init a positive number needs to be
+        * set [as filters require allocated searcher ILT memory].
+        * This will set the maximal number of configured steering-filters.
+        */
+       u32 num_arfs_filters;
 };
 
 struct qed_fcoe_pf_params {
@@ -427,6 +433,7 @@ struct qed_int_info {
 };
 
 struct qed_common_cb_ops {
+       void (*arfs_filter_op)(void *dev, void *fltr, u8 fw_rc);
        void    (*link_update)(void                     *dev,
                               struct qed_link_output   *link);
        void    (*dcbx_aen)(void *dev, struct qed_dcbx_get *get, u32 mib_type);
-- 
2.7.2

Reply via email to