diff options
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c')
| -rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 441 | 
1 files changed, 279 insertions, 162 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 11b4bb83b93..e45bf09af0c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -13,16 +13,19 @@  #include "qlcnic.h" -#define TX_ETHER_PKT	0x01 -#define TX_TCP_PKT	0x02 -#define TX_UDP_PKT	0x03 -#define TX_IP_PKT	0x04 -#define TX_TCP_LSO	0x05 -#define TX_TCP_LSO6	0x06 -#define TX_TCPV6_PKT	0x0b -#define TX_UDPV6_PKT	0x0c -#define FLAGS_VLAN_TAGGED	0x10 -#define FLAGS_VLAN_OOB		0x40 +#define QLCNIC_TX_ETHER_PKT		0x01 +#define QLCNIC_TX_TCP_PKT		0x02 +#define QLCNIC_TX_UDP_PKT		0x03 +#define QLCNIC_TX_IP_PKT		0x04 +#define QLCNIC_TX_TCP_LSO		0x05 +#define QLCNIC_TX_TCP_LSO6		0x06 +#define QLCNIC_TX_ENCAP_PKT		0x07 +#define QLCNIC_TX_ENCAP_LSO		0x08 +#define QLCNIC_TX_TCPV6_PKT		0x0b +#define QLCNIC_TX_UDPV6_PKT		0x0c + +#define QLCNIC_FLAGS_VLAN_TAGGED	0x10 +#define QLCNIC_FLAGS_VLAN_OOB		0x40  #define qlcnic_set_tx_vlan_tci(cmd_desc, v)	\  	(cmd_desc)->vlan_TCI = cpu_to_le16(v); @@ -124,41 +127,16 @@  #define qlcnic_83xx_is_ip_align(sts)	(((sts) >> 46) & 1)  #define qlcnic_83xx_has_vlan_tag(sts)	(((sts) >> 47) & 1) -struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *, -				     struct qlcnic_host_rds_ring *, u16, u16); +static int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, +				   int max); -inline void qlcnic_enable_tx_intr(struct qlcnic_adapter *adapter, -				  struct qlcnic_host_tx_ring *tx_ring) -{ -	if (qlcnic_check_multi_tx(adapter) && -	    !adapter->ahw->diag_test) -		writel(0x0, tx_ring->crb_intr_mask); -} - - -static inline void qlcnic_disable_tx_int(struct qlcnic_adapter *adapter, -					 struct qlcnic_host_tx_ring *tx_ring) -{ -	if (qlcnic_check_multi_tx(adapter) && -	    !adapter->ahw->diag_test) -		writel(1, tx_ring->crb_intr_mask); -} - -inline void qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter, -				       struct qlcnic_host_tx_ring *tx_ring) -{ -	writel(0, tx_ring->crb_intr_mask); -} - -inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter, -					struct qlcnic_host_tx_ring *tx_ring) -{ -	writel(1, tx_ring->crb_intr_mask); -} +static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *, +					    struct qlcnic_host_rds_ring *, +					    u16, u16); -static inline u8 qlcnic_mac_hash(u64 mac) +static inline u8 qlcnic_mac_hash(u64 mac, u16 vlan)  { -	return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff)); +	return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff) ^ (vlan & 0xff));  }  static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter, @@ -202,7 +180,7 @@ static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head,  	struct hlist_node *n;  	hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { -		if (!memcmp(tmp_fil->faddr, addr, ETH_ALEN) && +		if (ether_addr_equal(tmp_fil->faddr, addr) &&  		    tmp_fil->vlan_id == vlan_id)  			return tmp_fil;  	} @@ -210,8 +188,8 @@ static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head,  	return NULL;  } -void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, -			  int loopback_pkt, u16 vlan_id) +static void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, +				 struct sk_buff *skb, int loopback_pkt, u16 vlan_id)  {  	struct ethhdr *phdr = (struct ethhdr *)(skb->data);  	struct qlcnic_filter *fil, *tmp_fil; @@ -221,8 +199,11 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,  	u8 hindex, op;  	int ret; +	if (!qlcnic_sriov_pf_check(adapter) || (vlan_id == 0xffff)) +		vlan_id = 0; +  	memcpy(&src_addr, phdr->h_source, ETH_ALEN); -	hindex = qlcnic_mac_hash(src_addr) & +	hindex = qlcnic_mac_hash(src_addr, vlan_id) &  		 (adapter->fhash.fbucket_size - 1);  	if (loopback_pkt) { @@ -322,31 +303,35 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,  			       struct cmd_desc_type0 *first_desc,  			       struct sk_buff *skb)  { +	struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data); +	struct ethhdr *phdr = (struct ethhdr *)(skb->data); +	u16 protocol = ntohs(skb->protocol);  	struct qlcnic_filter *fil, *tmp_fil; -	struct hlist_node *n;  	struct hlist_head *head; -	struct net_device *netdev = adapter->netdev; -	struct ethhdr *phdr = (struct ethhdr *)(skb->data); +	struct hlist_node *n;  	u64 src_addr = 0;  	u16 vlan_id = 0; -	u8 hindex; +	u8 hindex, hval;  	if (ether_addr_equal(phdr->h_source, adapter->mac_addr))  		return; -	if (adapter->fhash.fnum >= adapter->fhash.fmax) { -		adapter->stats.mac_filter_limit_overrun++; -		netdev_info(netdev, "Can not add more than %d mac addresses\n", -			    adapter->fhash.fmax); -		return; +	if (adapter->flags & QLCNIC_VLAN_FILTERING) { +		if (protocol == ETH_P_8021Q) { +			vh = (struct vlan_ethhdr *)skb->data; +			vlan_id = ntohs(vh->h_vlan_TCI); +		} else if (vlan_tx_tag_present(skb)) { +			vlan_id = vlan_tx_tag_get(skb); +		}  	}  	memcpy(&src_addr, phdr->h_source, ETH_ALEN); -	hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1); +	hval = qlcnic_mac_hash(src_addr, vlan_id); +	hindex = hval & (adapter->fhash.fbucket_size - 1);  	head = &(adapter->fhash.fhead[hindex]);  	hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { -		if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) && +		if (ether_addr_equal(tmp_fil->faddr, (u8 *)&src_addr) &&  		    tmp_fil->vlan_id == vlan_id) {  			if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))  				qlcnic_change_filter(adapter, &src_addr, @@ -356,6 +341,11 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,  		}  	} +	if (unlikely(adapter->fhash.fnum >= adapter->fhash.fmax)) { +		adapter->stats.mac_filter_limit_overrun++; +		return; +	} +  	fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);  	if (!fil)  		return; @@ -370,6 +360,101 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,  	spin_unlock(&adapter->mac_learn_lock);  } +#define QLCNIC_ENCAP_VXLAN_PKT		BIT_0 +#define QLCNIC_ENCAP_OUTER_L3_IP6	BIT_1 +#define QLCNIC_ENCAP_INNER_L3_IP6	BIT_2 +#define QLCNIC_ENCAP_INNER_L4_UDP	BIT_3 +#define QLCNIC_ENCAP_DO_L3_CSUM		BIT_4 +#define QLCNIC_ENCAP_DO_L4_CSUM		BIT_5 + +static int qlcnic_tx_encap_pkt(struct qlcnic_adapter *adapter, +			       struct cmd_desc_type0 *first_desc, +			       struct sk_buff *skb, +			       struct qlcnic_host_tx_ring *tx_ring) +{ +	u8 opcode = 0, inner_hdr_len = 0, outer_hdr_len = 0, total_hdr_len = 0; +	int copied, copy_len, descr_size; +	u32 producer = tx_ring->producer; +	struct cmd_desc_type0 *hwdesc; +	u16 flags = 0, encap_descr = 0; + +	opcode = QLCNIC_TX_ETHER_PKT; +	encap_descr = QLCNIC_ENCAP_VXLAN_PKT; + +	if (skb_is_gso(skb)) { +		inner_hdr_len = skb_inner_transport_header(skb) + +				inner_tcp_hdrlen(skb) - +				skb_inner_mac_header(skb); + +		/* VXLAN header size = 8 */ +		outer_hdr_len = skb_transport_offset(skb) + 8 + +				sizeof(struct udphdr); +		first_desc->outer_hdr_length = outer_hdr_len; +		total_hdr_len = inner_hdr_len + outer_hdr_len; +		encap_descr |= QLCNIC_ENCAP_DO_L3_CSUM | +			       QLCNIC_ENCAP_DO_L4_CSUM; +		first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); +		first_desc->hdr_length = inner_hdr_len; + +		/* Copy inner and outer headers in Tx descriptor(s) +		 * If total_hdr_len > cmd_desc_type0, use multiple +		 * descriptors +		 */ +		copied = 0; +		descr_size = (int)sizeof(struct cmd_desc_type0); +		while (copied < total_hdr_len) { +			copy_len = min(descr_size, (total_hdr_len - copied)); +			hwdesc = &tx_ring->desc_head[producer]; +			tx_ring->cmd_buf_arr[producer].skb = NULL; +			skb_copy_from_linear_data_offset(skb, copied, +							 (char *)hwdesc, +							 copy_len); +			copied += copy_len; +			producer = get_next_index(producer, tx_ring->num_desc); +		} + +		tx_ring->producer = producer; + +		/* Make sure updated tx_ring->producer is visible +		 * for qlcnic_tx_avail() +		 */ +		smp_mb(); +		adapter->stats.encap_lso_frames++; + +		opcode = QLCNIC_TX_ENCAP_LSO; +	} else if (skb->ip_summed == CHECKSUM_PARTIAL) { +		if (inner_ip_hdr(skb)->version == 6) { +			if (inner_ipv6_hdr(skb)->nexthdr == IPPROTO_UDP) +				encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP; +		} else { +			if (inner_ip_hdr(skb)->protocol == IPPROTO_UDP) +				encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP; +		} + +		adapter->stats.encap_tx_csummed++; +		opcode = QLCNIC_TX_ENCAP_PKT; +	} + +	/* Prepare first 16 bits of byte offset 16 of Tx descriptor */ +	if (ip_hdr(skb)->version == 6) +		encap_descr |= QLCNIC_ENCAP_OUTER_L3_IP6; + +	/* outer IP header's size in 32bit words size*/ +	encap_descr |= (skb_network_header_len(skb) >> 2) << 6; + +	/* outer IP header offset */ +	encap_descr |= skb_network_offset(skb) << 10; +	first_desc->encap_descr = cpu_to_le16(encap_descr); + +	first_desc->tcp_hdr_offset = skb_inner_transport_header(skb) - +				     skb->data; +	first_desc->ip_hdr_offset = skb_inner_network_offset(skb); + +	qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); + +	return 0; +} +  static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,  			 struct cmd_desc_type0 *first_desc, struct sk_buff *skb,  			 struct qlcnic_host_tx_ring *tx_ring) @@ -384,11 +469,11 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,  	if (protocol == ETH_P_8021Q) {  		vh = (struct vlan_ethhdr *)skb->data; -		flags = FLAGS_VLAN_TAGGED; +		flags = QLCNIC_FLAGS_VLAN_TAGGED;  		vlan_tci = ntohs(vh->h_vlan_TCI);  		protocol = ntohs(vh->h_vlan_encapsulated_proto);  	} else if (vlan_tx_tag_present(skb)) { -		flags = FLAGS_VLAN_OOB; +		flags = QLCNIC_FLAGS_VLAN_OOB;  		vlan_tci = vlan_tx_tag_get(skb);  	}  	if (unlikely(adapter->tx_pvid)) { @@ -397,7 +482,7 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,  		if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))  			goto set_flags; -		flags = FLAGS_VLAN_OOB; +		flags = QLCNIC_FLAGS_VLAN_OOB;  		vlan_tci = adapter->tx_pvid;  	}  set_flags: @@ -408,25 +493,26 @@ set_flags:  		flags |= BIT_0;  		memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);  	} -	opcode = TX_ETHER_PKT; +	opcode = QLCNIC_TX_ETHER_PKT;  	if (skb_is_gso(skb)) {  		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);  		first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); -		first_desc->total_hdr_length = hdr_len; -		opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO; +		first_desc->hdr_length = hdr_len; +		opcode = (protocol == ETH_P_IPV6) ? QLCNIC_TX_TCP_LSO6 : +						    QLCNIC_TX_TCP_LSO;  		/* For LSO, we need to copy the MAC/IP/TCP headers into  		* the descriptor ring */  		copied = 0;  		offset = 2; -		if (flags & FLAGS_VLAN_OOB) { -			first_desc->total_hdr_length += VLAN_HLEN; +		if (flags & QLCNIC_FLAGS_VLAN_OOB) { +			first_desc->hdr_length += VLAN_HLEN;  			first_desc->tcp_hdr_offset = VLAN_HLEN;  			first_desc->ip_hdr_offset = VLAN_HLEN;  			/* Only in case of TSO on vlan device */ -			flags |= FLAGS_VLAN_TAGGED; +			flags |= QLCNIC_FLAGS_VLAN_TAGGED;  			/* Create a TSO vlan header template for firmware */  			hwdesc = &tx_ring->desc_head[producer]; @@ -470,16 +556,16 @@ set_flags:  			l4proto = ip_hdr(skb)->protocol;  			if (l4proto == IPPROTO_TCP) -				opcode = TX_TCP_PKT; +				opcode = QLCNIC_TX_TCP_PKT;  			else if (l4proto == IPPROTO_UDP) -				opcode = TX_UDP_PKT; +				opcode = QLCNIC_TX_UDP_PKT;  		} else if (protocol == ETH_P_IPV6) {  			l4proto = ipv6_hdr(skb)->nexthdr;  			if (l4proto == IPPROTO_TCP) -				opcode = TX_TCPV6_PKT; +				opcode = QLCNIC_TX_TCPV6_PKT;  			else if (l4proto == IPPROTO_UDP) -				opcode = TX_UDPV6_PKT; +				opcode = QLCNIC_TX_UDPV6_PKT;  		}  	}  	first_desc->tcp_hdr_offset += skb_transport_offset(skb); @@ -569,6 +655,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)  	struct ethhdr *phdr;  	int i, k, frag_count, delta = 0;  	u32 producer, num_txd; +	u16 protocol; +	bool l4_is_udp = false;  	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {  		netif_tx_stop_all_queues(netdev); @@ -581,10 +669,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)  			goto drop_packet;  	} -	if (qlcnic_check_multi_tx(adapter)) -		tx_ring = &adapter->tx_ring[skb_get_queue_mapping(skb)]; -	else -		tx_ring = &adapter->tx_ring[0]; +	tx_ring = &adapter->tx_ring[skb_get_queue_mapping(skb)];  	num_txd = tx_ring->num_desc;  	frag_count = skb_shinfo(skb)->nr_frags + 1; @@ -607,8 +692,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)  		if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {  			netif_tx_start_queue(tx_ring->txq);  		} else { -			adapter->stats.xmit_off++; -			tx_ring->xmit_off++; +			tx_ring->tx_stats.xmit_off++;  			return NETDEV_TX_BUSY;  		}  	} @@ -663,15 +747,29 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)  	tx_ring->producer = get_next_index(producer, num_txd);  	smp_mb(); -	if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb, tx_ring))) -		goto unwind_buff; +	protocol = ntohs(skb->protocol); +	if (protocol == ETH_P_IP) +		l4_is_udp = ip_hdr(skb)->protocol == IPPROTO_UDP; +	else if (protocol == ETH_P_IPV6) +		l4_is_udp = ipv6_hdr(skb)->nexthdr == IPPROTO_UDP; + +	/* Check if it is a VXLAN packet */ +	if (!skb->encapsulation || !l4_is_udp || +	    !qlcnic_encap_tx_offload(adapter)) { +		if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb, +					   tx_ring))) +			goto unwind_buff; +	} else { +		if (unlikely(qlcnic_tx_encap_pkt(adapter, first_desc, +						 skb, tx_ring))) +			goto unwind_buff; +	}  	if (adapter->drv_mac_learn)  		qlcnic_send_filter(adapter, first_desc, skb); -	adapter->stats.txbytes += skb->len; -	adapter->stats.xmitcalled++; -	tx_ring->xmit_called++; +	tx_ring->tx_stats.tx_bytes += skb->len; +	tx_ring->tx_stats.xmit_called++;  	qlcnic_update_cmd_producer(tx_ring); @@ -692,17 +790,20 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)  	if (adapter->ahw->linkup && !linkup) {  		netdev_info(netdev, "NIC Link is down\n");  		adapter->ahw->linkup = 0; -		if (netif_running(netdev)) { -			netif_carrier_off(netdev); -			netif_tx_stop_all_queues(netdev); -		} +		netif_carrier_off(netdev);  	} else if (!adapter->ahw->linkup && linkup) { -		netdev_info(netdev, "NIC Link is up\n");  		adapter->ahw->linkup = 1; -		if (netif_running(netdev)) { -			netif_carrier_on(netdev); -			netif_wake_queue(netdev); + +		/* Do not advertise Link up to the stack if device +		 * is in loopback mode +		 */ +		if (qlcnic_83xx_check(adapter) && adapter->ahw->lb_mode) { +			netdev_info(netdev, "NIC Link is up for loopback test\n"); +			return;  		} + +		netdev_info(netdev, "NIC Link is up\n"); +		netif_carrier_on(netdev);  	}  } @@ -789,6 +890,9 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,  	struct net_device *netdev = adapter->netdev;  	struct qlcnic_skb_frag *frag; +	if (!spin_trylock(&tx_ring->tx_clean_lock)) +		return 1; +  	sw_consumer = tx_ring->sw_consumer;  	hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); @@ -805,8 +909,7 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,  					       PCI_DMA_TODEVICE);  				frag->dma = 0ULL;  			} -			adapter->stats.xmitfinished++; -			tx_ring->xmit_finished++; +			tx_ring->tx_stats.xmit_finished++;  			dev_kfree_skb_any(buffer->skb);  			buffer->skb = NULL;  		} @@ -816,15 +919,15 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,  			break;  	} +	tx_ring->sw_consumer = sw_consumer; +  	if (count && netif_running(netdev)) { -		tx_ring->sw_consumer = sw_consumer;  		smp_mb();  		if (netif_tx_queue_stopped(tx_ring->txq) &&  		    netif_carrier_ok(netdev)) {  			if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {  				netif_tx_wake_queue(tx_ring->txq); -				adapter->stats.xmit_on++; -				tx_ring->xmit_on++; +				tx_ring->tx_stats.xmit_on++;  			}  		}  		adapter->tx_timeo_cnt = 0; @@ -845,6 +948,8 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,  	hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));  	done = (sw_consumer == hw_consumer); +	spin_unlock(&tx_ring->tx_clean_lock); +  	return done;  } @@ -865,7 +970,7 @@ static int qlcnic_poll(struct napi_struct *napi, int budget)  	if ((work_done < budget) && tx_complete) {  		napi_complete(&sds_ring->napi);  		if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { -			qlcnic_enable_int(sds_ring); +			qlcnic_enable_sds_intr(adapter, sds_ring);  			qlcnic_enable_tx_intr(adapter, tx_ring);  		}  	} @@ -906,7 +1011,7 @@ static int qlcnic_rx_poll(struct napi_struct *napi, int budget)  	if (work_done < budget) {  		napi_complete(&sds_ring->napi);  		if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) -			qlcnic_enable_int(sds_ring); +			qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	return work_done; @@ -1011,16 +1116,16 @@ static void qlcnic_handle_fw_message(int desc_cnt, int index,  		}  		break;  	case QLCNIC_C2H_OPCODE_GET_DCB_AEN: -		qlcnic_dcb_handle_aen(adapter, (void *)&msg); +		qlcnic_dcb_aen_handler(adapter->dcb, (void *)&msg);  		break;  	default:  		break;  	}  } -struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, -				     struct qlcnic_host_rds_ring *ring, -				     u16 index, u16 cksum) +static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, +					    struct qlcnic_host_rds_ring *ring, +					    u16 index, u16 cksum)  {  	struct qlcnic_rx_buffer *buffer;  	struct sk_buff *skb; @@ -1104,8 +1209,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,  	if (!skb)  		return buffer; -	if (adapter->drv_mac_learn && -	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { +	if (adapter->rx_mac_learn) {  		t_vid = 0;  		is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);  		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); @@ -1159,13 +1263,13 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,  	u16 lro_length, length, data_offset, t_vid, vid = 0xffff;  	u32 seq_number; -	if (unlikely(ring > adapter->max_rds_rings)) +	if (unlikely(ring >= adapter->max_rds_rings))  		return NULL;  	rds_ring = &recv_ctx->rds_rings[ring];  	index = qlcnic_get_lro_sts_refhandle(sts_data0); -	if (unlikely(index > rds_ring->num_desc)) +	if (unlikely(index >= rds_ring->num_desc))  		return NULL;  	buffer = &rds_ring->rx_buf_arr[index]; @@ -1181,8 +1285,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,  	if (!skb)  		return buffer; -	if (adapter->drv_mac_learn && -	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { +	if (adapter->rx_mac_learn) {  		t_vid = 0;  		is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);  		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); @@ -1239,7 +1342,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,  	return buffer;  } -int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max) +static int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)  {  	struct qlcnic_host_rds_ring *rds_ring;  	struct qlcnic_adapter *adapter = sds_ring->adapter; @@ -1463,18 +1566,17 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;  	struct qlcnic_host_tx_ring *tx_ring; -	if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) +	if (qlcnic_alloc_sds_rings(recv_ctx, adapter->drv_sds_rings))  		return -ENOMEM; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		if (qlcnic_check_multi_tx(adapter) && -		    !adapter->ahw->diag_test && -		    (adapter->max_drv_tx_rings > 1)) { +		    !adapter->ahw->diag_test) {  			netif_napi_add(netdev, &sds_ring->napi, qlcnic_rx_poll,  				       NAPI_POLL_WEIGHT);  		} else { -			if (ring == (adapter->max_sds_rings - 1)) +			if (ring == (adapter->drv_sds_rings - 1))  				netif_napi_add(netdev, &sds_ring->napi,  					       qlcnic_poll,  					       NAPI_POLL_WEIGHT); @@ -1491,7 +1593,7 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,  	}  	if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			netif_napi_add(netdev, &tx_ring->napi, qlcnic_tx_poll,  				       NAPI_POLL_WEIGHT); @@ -1508,7 +1610,7 @@ void qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter)  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;  	struct qlcnic_host_tx_ring *tx_ring; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		netif_napi_del(&sds_ring->napi);  	} @@ -1516,7 +1618,7 @@ void qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter)  	qlcnic_free_sds_rings(adapter->recv_ctx);  	if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			netif_napi_del(&tx_ring->napi);  		} @@ -1535,17 +1637,16 @@ void qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter)  	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)  		return; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		napi_enable(&sds_ring->napi); -		qlcnic_enable_int(sds_ring); +		qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	if (qlcnic_check_multi_tx(adapter) &&  	    (adapter->flags & QLCNIC_MSIX_ENABLED) && -	    !adapter->ahw->diag_test && -	    (adapter->max_drv_tx_rings > 1)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +	    !adapter->ahw->diag_test) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			napi_enable(&tx_ring->napi);  			qlcnic_enable_tx_intr(adapter, tx_ring); @@ -1563,9 +1664,9 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)  	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)  		return; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring]; -		qlcnic_disable_int(sds_ring); +		qlcnic_disable_sds_intr(adapter, sds_ring);  		napi_synchronize(&sds_ring->napi);  		napi_disable(&sds_ring->napi);  	} @@ -1573,9 +1674,9 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !adapter->ahw->diag_test &&  	    qlcnic_check_multi_tx(adapter)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring]; -			qlcnic_disable_tx_int(adapter, tx_ring); +			qlcnic_disable_tx_intr(adapter, tx_ring);  			napi_synchronize(&tx_ring->napi);  			napi_disable(&tx_ring->napi);  		} @@ -1593,6 +1694,13 @@ static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt)  		return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0;  } +#define QLCNIC_ENCAP_LENGTH_MASK	0x7f + +static inline u8 qlcnic_encap_length(u64 sts_data) +{ +	return sts_data & QLCNIC_ENCAP_LENGTH_MASK; +} +  static struct qlcnic_rx_buffer *  qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,  			struct qlcnic_host_sds_ring *sds_ring, @@ -1604,7 +1712,8 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,  	struct sk_buff *skb;  	struct qlcnic_host_rds_ring *rds_ring;  	int index, length, cksum, is_lb_pkt; -	u16 vid = 0xffff, t_vid; +	u16 vid = 0xffff; +	int err;  	if (unlikely(ring >= adapter->max_rds_rings))  		return NULL; @@ -1622,19 +1731,19 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,  	if (!skb)  		return buffer; -	if (adapter->drv_mac_learn && -	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { -		t_vid = 0; -		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); -		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); -	} -  	if (length > rds_ring->skb_size)  		skb_put(skb, rds_ring->skb_size);  	else  		skb_put(skb, length); -	if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { +	err = qlcnic_check_rx_tagging(adapter, skb, &vid); + +	if (adapter->rx_mac_learn) { +		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); +		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); +	} + +	if (unlikely(err)) {  		adapter->stats.rxdropped++;  		dev_kfree_skb(skb);  		return buffer; @@ -1642,6 +1751,12 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,  	skb->protocol = eth_type_trans(skb, netdev); +	if (qlcnic_encap_length(sts_data[1]) && +	    skb->ip_summed == CHECKSUM_UNNECESSARY) { +		skb->encapsulation = 1; +		adapter->stats.encap_rx_csummed++; +	} +  	if (vid != 0xffff)  		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); @@ -1669,15 +1784,16 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,  	int l2_hdr_offset, l4_hdr_offset;  	int index, is_lb_pkt;  	u16 lro_length, length, data_offset, gso_size; -	u16 vid = 0xffff, t_vid; +	u16 vid = 0xffff; +	int err; -	if (unlikely(ring > adapter->max_rds_rings)) +	if (unlikely(ring >= adapter->max_rds_rings))  		return NULL;  	rds_ring = &recv_ctx->rds_rings[ring];  	index = qlcnic_83xx_hndl(sts_data[0]); -	if (unlikely(index > rds_ring->num_desc)) +	if (unlikely(index >= rds_ring->num_desc))  		return NULL;  	buffer = &rds_ring->rx_buf_arr[index]; @@ -1691,12 +1807,6 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,  	if (!skb)  		return buffer; -	if (adapter->drv_mac_learn && -	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { -		t_vid = 0; -		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); -		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); -	}  	if (qlcnic_83xx_is_tstamp(sts_data[1]))  		data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE;  	else @@ -1705,7 +1815,14 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,  	skb_put(skb, lro_length + data_offset);  	skb_pull(skb, l2_hdr_offset); -	if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { +	err = qlcnic_check_rx_tagging(adapter, skb, &vid); + +	if (adapter->rx_mac_learn) { +		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); +		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); +	} + +	if (unlikely(err)) {  		adapter->stats.rxdropped++;  		dev_kfree_skb(skb);  		return buffer; @@ -1835,7 +1952,7 @@ static int qlcnic_83xx_msix_sriov_vf_poll(struct napi_struct *napi, int budget)  	work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);  	if ((work_done < budget) && tx_complete) {  		napi_complete(&sds_ring->napi); -		qlcnic_83xx_enable_intr(adapter, sds_ring); +		qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	return work_done; @@ -1858,7 +1975,7 @@ static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)  	work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);  	if ((work_done < budget) && tx_complete) {  		napi_complete(&sds_ring->napi); -		qlcnic_83xx_enable_intr(adapter, sds_ring); +		qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	return work_done; @@ -1877,7 +1994,7 @@ static int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget)  	if (work_done) {  		napi_complete(&tx_ring->napi);  		if (test_bit(__QLCNIC_DEV_UP , &adapter->state)) -			qlcnic_83xx_enable_tx_intr(adapter, tx_ring); +			qlcnic_enable_tx_intr(adapter, tx_ring);  	}  	return work_done; @@ -1895,7 +2012,7 @@ static int qlcnic_83xx_rx_poll(struct napi_struct *napi, int budget)  	if (work_done < budget) {  		napi_complete(&sds_ring->napi);  		if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) -			qlcnic_83xx_enable_intr(adapter, sds_ring); +			qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	return work_done; @@ -1911,19 +2028,19 @@ void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter)  	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)  		return; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		napi_enable(&sds_ring->napi);  		if (adapter->flags & QLCNIC_MSIX_ENABLED) -			qlcnic_83xx_enable_intr(adapter, sds_ring); +			qlcnic_enable_sds_intr(adapter, sds_ring);  	}  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			napi_enable(&tx_ring->napi); -			qlcnic_83xx_enable_tx_intr(adapter, tx_ring); +			qlcnic_enable_tx_intr(adapter, tx_ring);  		}  	}  } @@ -1938,19 +2055,19 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter)  	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)  		return; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		if (adapter->flags & QLCNIC_MSIX_ENABLED) -			qlcnic_83xx_disable_intr(adapter, sds_ring); +			qlcnic_disable_sds_intr(adapter, sds_ring);  		napi_synchronize(&sds_ring->napi);  		napi_disable(&sds_ring->napi);  	}  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring]; -			qlcnic_83xx_disable_tx_intr(adapter, tx_ring); +			qlcnic_disable_tx_intr(adapter, tx_ring);  			napi_synchronize(&tx_ring->napi);  			napi_disable(&tx_ring->napi);  		} @@ -1965,10 +2082,10 @@ int qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter,  	struct qlcnic_host_tx_ring *tx_ring;  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; -	if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) +	if (qlcnic_alloc_sds_rings(recv_ctx, adapter->drv_sds_rings))  		return -ENOMEM; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		if (adapter->flags & QLCNIC_MSIX_ENABLED) {  			if (!(adapter->flags & QLCNIC_TX_INTR_SHARED)) @@ -1994,7 +2111,7 @@ int qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter,  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			netif_napi_add(netdev, &tx_ring->napi,  				       qlcnic_83xx_msix_tx_poll, @@ -2012,7 +2129,7 @@ void qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter)  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;  	struct qlcnic_host_tx_ring *tx_ring; -	for (ring = 0; ring < adapter->max_sds_rings; ring++) { +	for (ring = 0; ring < adapter->drv_sds_rings; ring++) {  		sds_ring = &recv_ctx->sds_rings[ring];  		netif_napi_del(&sds_ring->napi);  	} @@ -2021,7 +2138,7 @@ void qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter)  	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&  	    !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { -		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) { +		for (ring = 0; ring < adapter->drv_tx_rings; ring++) {  			tx_ring = &adapter->tx_ring[ring];  			netif_napi_del(&tx_ring->napi);  		} @@ -2030,8 +2147,8 @@ void qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter)  	qlcnic_free_tx_rings(adapter);  } -void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter, -				  int ring, u64 sts_data[]) +static void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter, +					 int ring, u64 sts_data[])  {  	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;  	struct sk_buff *skb;  | 
