diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 40d1dd26e9fd..83da77f0982c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -2804,8 +2804,14 @@ begin: case IPAHAL_PKT_STATUS_OPCODE_PACKET: case IPAHAL_PKT_STATUS_OPCODE_SUSPENDED_PACKET: case IPAHAL_PKT_STATUS_OPCODE_PACKET_2ND_PASS: - case IPAHAL_PKT_STATUS_OPCODE_NEW_FRAG_RULE: break; + case IPAHAL_PKT_STATUS_OPCODE_NEW_FRAG_RULE: + IPAERR_RL("Frag packets received on lan consumer\n"); + IPAERR_RL("STATUS opcode=%d src=%d dst=%d src ip=%x\n", + status.status_opcode, status.endp_src_idx, + status.endp_dest_idx, status.src_ip_addr); + skb_pull(skb, pkt_status_sz); + continue; default: IPAERR_RL("unsupported opcode(%d)\n", status.status_opcode); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c index 1cb1417fef87..8758360e34ae 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c @@ -861,7 +861,8 @@ struct ipahal_imm_cmd_pyld *ipahal_construct_nop_imm_cmd( #define IPA_PKT_STATUS_SET_MSK(__hw_bit_msk, __shft) \ (status->status_mask |= \ - ((hw_status->status_mask & (__hw_bit_msk) ? 1 : 0) << (__shft))) + ((hw_status->ipa_pkt.status_mask & (__hw_bit_msk) ? 1 : 0) \ + << (__shft))) static enum ipahal_pkt_status_exception pkt_status_parse_exception( bool is_ipv6, u64 exception) @@ -905,46 +906,81 @@ static enum ipahal_pkt_status_exception pkt_status_parse_exception( return exception_type; } +static void __ipa_parse_gen_pkt(struct ipahal_pkt_status *status, + const void *unparsed_status) +{ + bool is_ipv6; + union ipa_pkt_status_hw *hw_status = + (union ipa_pkt_status_hw *)unparsed_status; + + is_ipv6 = (hw_status->ipa_pkt.status_mask & 0x80) ? false : true; + status->pkt_len = hw_status->ipa_pkt.pkt_len; + status->endp_src_idx = hw_status->ipa_pkt.endp_src_idx; + status->endp_dest_idx = hw_status->ipa_pkt.endp_dest_idx; + status->metadata = hw_status->ipa_pkt.metadata; + status->flt_local = hw_status->ipa_pkt.flt_local; + status->flt_hash = hw_status->ipa_pkt.flt_hash; + status->flt_global = hw_status->ipa_pkt.flt_hash; + status->flt_ret_hdr = hw_status->ipa_pkt.flt_ret_hdr; + status->flt_miss = (hw_status->ipa_pkt.rt_rule_id == + IPAHAL_PKT_STATUS_FLTRT_RULE_MISS_ID); + status->flt_rule_id = hw_status->ipa_pkt.flt_rule_id; + status->rt_local = hw_status->ipa_pkt.rt_local; + status->rt_hash = hw_status->ipa_pkt.rt_hash; + status->ucp = hw_status->ipa_pkt.ucp; + status->rt_tbl_idx = hw_status->ipa_pkt.rt_tbl_idx; + status->rt_miss = (hw_status->ipa_pkt.rt_rule_id == + IPAHAL_PKT_STATUS_FLTRT_RULE_MISS_ID); + status->rt_rule_id = hw_status->ipa_pkt.rt_rule_id; + status->nat_hit = hw_status->ipa_pkt.nat_hit; + status->nat_entry_idx = hw_status->ipa_pkt.nat_entry_idx; + status->tag_info = hw_status->ipa_pkt.tag_info; + status->seq_num = hw_status->ipa_pkt.seq_num; + status->time_of_day_ctr = hw_status->ipa_pkt.time_of_day_ctr; + status->hdr_local = hw_status->ipa_pkt.hdr_local; + status->hdr_offset = hw_status->ipa_pkt.hdr_offset; + status->frag_hit = hw_status->ipa_pkt.frag_hit; + status->frag_rule = hw_status->ipa_pkt.frag_rule; + status->nat_type = hw_status->ipa_pkt.nat_type; + + status->exception = pkt_status_parse_exception(is_ipv6, + hw_status->ipa_pkt.exception); +} + +static void __ipa_parse_frag_pkt(struct ipahal_pkt_status *status, + const void *unparsed_status) +{ + union ipa_pkt_status_hw *hw_status = + (union ipa_pkt_status_hw *)unparsed_status; + + status->frag_rule_idx = hw_status->frag_pkt.frag_rule_idx; + status->tbl_idx = hw_status->frag_pkt.tbl_idx; + status->src_ip_addr = hw_status->frag_pkt.src_ip_addr; + status->dest_ip_addr = hw_status->frag_pkt.dest_ip_addr; + status->protocol = hw_status->frag_pkt.protocol; + status->ip_id = hw_status->frag_pkt.ip_id; + status->tlated_ip_addr = hw_status->frag_pkt.tlated_ip_addr; + status->ip_cksum_diff = hw_status->frag_pkt.ip_cksum_diff; + status->endp_src_idx = hw_status->frag_pkt.endp_src_idx; + status->endp_dest_idx = hw_status->frag_pkt.endp_dest_idx; + status->metadata = hw_status->frag_pkt.metadata; + status->seq_num = hw_status->frag_pkt.seq_num; + status->hdr_local = hw_status->frag_pkt.hdr_local; + status->hdr_offset = hw_status->frag_pkt.hdr_offset; + status->exception = hw_status->frag_pkt.exception; + status->nat_type = hw_status->frag_pkt.nat_type; +} + static void ipa_pkt_status_parse( const void *unparsed_status, struct ipahal_pkt_status *status) { enum ipahal_pkt_status_opcode opcode = 0; - bool is_ipv6; - struct ipa_pkt_status_hw *hw_status = - (struct ipa_pkt_status_hw *)unparsed_status; + union ipa_pkt_status_hw *hw_status = + (union ipa_pkt_status_hw *)unparsed_status; - is_ipv6 = (hw_status->status_mask & 0x80) ? false : true; - status->pkt_len = hw_status->pkt_len; - status->endp_src_idx = hw_status->endp_src_idx; - status->endp_dest_idx = hw_status->endp_dest_idx; - status->metadata = hw_status->metadata; - status->flt_local = hw_status->flt_local; - status->flt_hash = hw_status->flt_hash; - status->flt_global = hw_status->flt_hash; - status->flt_ret_hdr = hw_status->flt_ret_hdr; - status->flt_miss = (hw_status->rt_rule_id == - IPAHAL_PKT_STATUS_FLTRT_RULE_MISS_ID); - status->flt_rule_id = hw_status->flt_rule_id; - status->rt_local = hw_status->rt_local; - status->rt_hash = hw_status->rt_hash; - status->ucp = hw_status->ucp; - status->rt_tbl_idx = hw_status->rt_tbl_idx; - status->rt_miss = (hw_status->rt_rule_id == - IPAHAL_PKT_STATUS_FLTRT_RULE_MISS_ID); - status->rt_rule_id = hw_status->rt_rule_id; - status->nat_hit = hw_status->nat_hit; - status->nat_entry_idx = hw_status->nat_entry_idx; - status->tag_info = hw_status->tag_info; - status->seq_num = hw_status->seq_num; - status->time_of_day_ctr = hw_status->time_of_day_ctr; - status->hdr_local = hw_status->hdr_local; - status->hdr_offset = hw_status->hdr_offset; - status->frag_hit = hw_status->frag_hit; - status->frag_rule = hw_status->frag_rule; - - switch (hw_status->status_opcode) { + switch (hw_status->ipa_pkt.status_opcode) { case 0x1: opcode = IPAHAL_PKT_STATUS_OPCODE_PACKET; break; @@ -968,11 +1004,17 @@ static void ipa_pkt_status_parse( break; default: IPAHAL_ERR_RL("unsupported Status Opcode 0x%x\n", - hw_status->status_opcode); + hw_status->ipa_pkt.status_opcode); } + status->status_opcode = opcode; - switch (hw_status->nat_type) { + if (status->status_opcode == IPAHAL_PKT_STATUS_OPCODE_NEW_FRAG_RULE) + __ipa_parse_frag_pkt(status, unparsed_status); + else + __ipa_parse_gen_pkt(status, unparsed_status); + + switch (status->nat_type) { case 0: status->nat_type = IPAHAL_PKT_STATUS_NAT_NONE; break; @@ -984,12 +1026,9 @@ static void ipa_pkt_status_parse( break; default: IPAHAL_ERR_RL("unsupported Status NAT type 0x%x\n", - hw_status->nat_type); + status->nat_type); } - status->exception = pkt_status_parse_exception(is_ipv6, - hw_status->exception); - IPA_PKT_STATUS_SET_MSK(0x1, IPAHAL_PKT_STATUS_MASK_FRAG_PROCESS_SHFT); IPA_PKT_STATUS_SET_MSK(0x2, IPAHAL_PKT_STATUS_MASK_FILT_PROCESS_SHFT); IPA_PKT_STATUS_SET_MSK(0x4, IPAHAL_PKT_STATUS_MASK_NAT_PROCESS_SHFT); @@ -1023,11 +1062,11 @@ static void ipa_pkt_status_parse( static void ipa_pkt_status_parse_thin(const void *unparsed_status, struct ipahal_pkt_status_thin *status) { - struct ipa_pkt_status_hw *hw_status = - (struct ipa_pkt_status_hw *)unparsed_status; + union ipa_pkt_status_hw *hw_status = + (union ipa_pkt_status_hw *)unparsed_status; bool is_ipv6; - is_ipv6 = (hw_status->status_mask & 0x80) ? false : true; + is_ipv6 = (hw_status->ipa_pkt.status_mask & 0x80) ? false : true; if (!unparsed_status || !status) { IPAHAL_ERR("Input Error: unparsed_status=%pK status=%pK\n", unparsed_status, status); @@ -1035,11 +1074,11 @@ static void ipa_pkt_status_parse_thin(const void *unparsed_status, } IPAHAL_DBG_LOW("Parse Thin Status Packet\n"); - status->metadata = hw_status->metadata; - status->endp_src_idx = hw_status->endp_src_idx; - status->ucp = hw_status->ucp; + status->metadata = hw_status->ipa_pkt.metadata; + status->endp_src_idx = hw_status->ipa_pkt.endp_src_idx; + status->ucp = hw_status->ipa_pkt.ucp; status->exception = pkt_status_parse_exception(is_ipv6, - hw_status->exception); + hw_status->ipa_pkt.exception); } /* @@ -1102,7 +1141,7 @@ static int ipahal_pkt_status_init(enum ipa_hw_type ipa_hw_type) * add a compile time validty check for it like below (as well as * the new defines and/or the new strucutre in the internal header). */ - BUILD_BUG_ON(sizeof(struct ipa_pkt_status_hw) != + BUILD_BUG_ON(sizeof(union ipa_pkt_status_hw) != IPA3_0_PKT_STATUS_SIZE); memset(&zero_obj, 0, sizeof(zero_obj)); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h index d30e68756552..440c57036f19 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h @@ -555,6 +555,14 @@ enum ipahal_pkt_status_nat_type { * @rt_tbl_idx: Index of rt tbl that contains the rule on which was a match * @seq_num: Per source endp unique packet sequence number * @frag_rule: Frag rule index in H/W frag table in case of frag hit + * @frag_rule_idx: Frag rule index value. + * @tbl_idx: Table index valid or not. + * @src_ip_addr: Source packet IP address. + * @dest_ip_addr: Destination packet IP address. + * @protocol: Protocal number. + * @ip_id: IP packet IP ID number. + * @tlated_ip_addr: IP address. + * @ip_cksum_diff: IP packet checksum difference. */ struct ipahal_pkt_status { u64 tag_info; @@ -586,6 +594,15 @@ struct ipahal_pkt_status { u8 rt_tbl_idx; u8 seq_num; u8 frag_rule; + u8 frag_rule_idx; + bool tbl_idx; + u32 src_ip_addr; + u32 dest_ip_addr; + u8 protocol; + u16 ip_id; + u32 tlated_ip_addr; + u16 ip_cksum_diff; + }; /* diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h index c49ab093afbc..8ab85cba79d2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h @@ -566,7 +566,7 @@ struct ipa_imm_cmd_hw_dma_task_32b_addr { * @frag_rule: Frag rule index in H/W frag table in case of frag hit * @hw_specific: H/W specific reserved value */ -struct ipa_pkt_status_hw { +struct ipa_gen_pkt_status_hw { u64 status_opcode:8; u64 exception:8; u64 status_mask:16; @@ -597,7 +597,68 @@ struct ipa_pkt_status_hw { u64 frag_hit:1; u64 frag_rule:4; u64 hw_specific:16; -}; +} __packed; + +/* + * struct ipa_frag_pkt_status_hw - IPA status packet payload in H/W format. + * This structure describes the frag status packet H/W structure for the + * following statuses: IPA_NEW_FRAG_RULE. + * @status_opcode: The Type of the status (Opcode). + * @frag_rule_idx: Frag rule index value. + * @rsvd1: reserved + * @tbl_idx: Table index valid or not. + * @endp_src_idx: Source end point index. + * @exception: (not bitmask) - the first exception that took place. + * In case of exception, src endp and pkt len are always valid. + * @rsvd2: reserved + * @seq_num: Packet sequence number. + * @src_ip_addr: Source packet IP address. + * @dest_ip_addr: Destination packet IP address. + * @rsvd3: reserved + * @nat_type: Defines the type of the NAT operation: + * 00: No NAT + * 01: Source NAT + * 10: Destination NAT + * 11: Reserved + * @protocol: Protocal number. + * @ip_id: IP packet IP ID number. + * @tlated_ip_addr: IP address. + * @hdr_local: Header table location flag: In header insertion, was the header + * taken from the table resides in local memory? (If no, then system mem) + * @hdr_offset: Offset of used header in the header table + * @endp_dest_idx: Destination end point index. + * @ip_cksum_diff: IP packet checksum difference. + * @metadata: meta data value used by packet + * @rsvd4: reserved + */ +struct ipa_frag_pkt_status_hw { + u64 status_opcode:8; + u64 frag_rule_idx:4; + u64 reserved_1:3; + u64 tbl_idx:1; + u64 endp_src_idx:5; + u64 exception:1; + u64 reserved_2:2; + u64 seq_num:8; + u64 src_ip_addr:32; + u64 dest_ip_addr:32; + u64 reserved_3:6; + u64 nat_type:2; + u64 protocol:8; + u64 ip_id:16; + u64 tlated_ip_addr:32; + u64 hdr_local:1; + u64 hdr_offset:10; + u64 endp_dest_idx:5; + u64 ip_cksum_diff:16; + u64 metadata:32; + u64 reserved_4:32; +} __packed; + +union ipa_pkt_status_hw { + struct ipa_gen_pkt_status_hw ipa_pkt; + struct ipa_frag_pkt_status_hw frag_pkt; +} __packed; /* Size of H/W Packet Status */ #define IPA3_0_PKT_STATUS_SIZE 32