diff options
Diffstat (limited to 'drivers/net/benet/be_main.c')
| -rw-r--r-- | drivers/net/benet/be_main.c | 641 | 
1 files changed, 491 insertions, 150 deletions
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7cb5a114c73..a485f7fdaf3 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -15,6 +15,7 @@   * Costa Mesa, CA 92626   */ +#include <linux/prefetch.h>  #include "be.h"  #include "be_cmds.h"  #include <asm/div64.h> @@ -42,6 +43,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {  	{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },  	{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },  	{ PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)}, +	{ PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID4)},  	{ 0 }  };  MODULE_DEVICE_TABLE(pci, be_dev_ids); @@ -116,11 +118,6 @@ static char *ue_status_hi_desc[] = {  	"Unknown"  }; -static inline bool be_multi_rxq(struct be_adapter *adapter) -{ -	return (adapter->num_rx_qs > 1); -} -  static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)  {  	struct be_dma_mem *mem = &q->dma_mem; @@ -250,14 +247,185 @@ netdev_addr:  	return status;  } +static void populate_be2_stats(struct be_adapter *adapter) +{ + +	struct be_drv_stats *drvs = &adapter->drv_stats; +	struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter); +	struct be_port_rxf_stats_v0 *port_stats = +		be_port_rxf_stats_from_cmd(adapter); +	struct be_rxf_stats_v0 *rxf_stats = +		be_rxf_stats_from_cmd(adapter); + +	drvs->rx_pause_frames = port_stats->rx_pause_frames; +	drvs->rx_crc_errors = port_stats->rx_crc_errors; +	drvs->rx_control_frames = port_stats->rx_control_frames; +	drvs->rx_in_range_errors = port_stats->rx_in_range_errors; +	drvs->rx_frame_too_long = port_stats->rx_frame_too_long; +	drvs->rx_dropped_runt = port_stats->rx_dropped_runt; +	drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs; +	drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs; +	drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs; +	drvs->rxpp_fifo_overflow_drop = port_stats->rx_fifo_overflow; +	drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length; +	drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small; +	drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short; +	drvs->rx_out_range_errors = port_stats->rx_out_range_errors; +	drvs->rx_input_fifo_overflow_drop = +		port_stats->rx_input_fifo_overflow; +	drvs->rx_dropped_header_too_small = +		port_stats->rx_dropped_header_too_small; +	drvs->rx_address_match_errors = +		port_stats->rx_address_match_errors; +	drvs->rx_alignment_symbol_errors = +		port_stats->rx_alignment_symbol_errors; + +	drvs->tx_pauseframes = port_stats->tx_pauseframes; +	drvs->tx_controlframes = port_stats->tx_controlframes; + +	if (adapter->port_num) +		drvs->jabber_events = +			rxf_stats->port1_jabber_events; +	else +		drvs->jabber_events = +			rxf_stats->port0_jabber_events; +	drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; +	drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb; +	drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; +	drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring; +	drvs->forwarded_packets = rxf_stats->forwarded_packets; +	drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; +	drvs->rx_drops_no_tpre_descr = +		rxf_stats->rx_drops_no_tpre_descr; +	drvs->rx_drops_too_many_frags = +		rxf_stats->rx_drops_too_many_frags; +	adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; +} + +static void populate_be3_stats(struct be_adapter *adapter) +{ +	struct be_drv_stats *drvs = &adapter->drv_stats; +	struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter); + +	struct be_rxf_stats_v1 *rxf_stats = +		be_rxf_stats_from_cmd(adapter); +	struct be_port_rxf_stats_v1 *port_stats = +		be_port_rxf_stats_from_cmd(adapter); + +	drvs->rx_priority_pause_frames = 0; +	drvs->pmem_fifo_overflow_drop = 0; +	drvs->rx_pause_frames = port_stats->rx_pause_frames; +	drvs->rx_crc_errors = port_stats->rx_crc_errors; +	drvs->rx_control_frames = port_stats->rx_control_frames; +	drvs->rx_in_range_errors = port_stats->rx_in_range_errors; +	drvs->rx_frame_too_long = port_stats->rx_frame_too_long; +	drvs->rx_dropped_runt = port_stats->rx_dropped_runt; +	drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs; +	drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs; +	drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs; +	drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length; +	drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small; +	drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short; +	drvs->rx_out_range_errors = port_stats->rx_out_range_errors; +	drvs->rx_dropped_header_too_small = +		port_stats->rx_dropped_header_too_small; +	drvs->rx_input_fifo_overflow_drop = +		port_stats->rx_input_fifo_overflow_drop; +	drvs->rx_address_match_errors = +		port_stats->rx_address_match_errors; +	drvs->rx_alignment_symbol_errors = +		port_stats->rx_alignment_symbol_errors; +	drvs->rxpp_fifo_overflow_drop = +		port_stats->rxpp_fifo_overflow_drop; +	drvs->tx_pauseframes = port_stats->tx_pauseframes; +	drvs->tx_controlframes = port_stats->tx_controlframes; +	drvs->jabber_events = port_stats->jabber_events; +	drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; +	drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb; +	drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; +	drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring; +	drvs->forwarded_packets = rxf_stats->forwarded_packets; +	drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; +	drvs->rx_drops_no_tpre_descr = +		rxf_stats->rx_drops_no_tpre_descr; +	drvs->rx_drops_too_many_frags = +		rxf_stats->rx_drops_too_many_frags; +	adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; +} + +static void populate_lancer_stats(struct be_adapter *adapter) +{ + +	struct be_drv_stats *drvs = &adapter->drv_stats; +	struct lancer_cmd_pport_stats *pport_stats = pport_stats_from_cmd +						(adapter); +	drvs->rx_priority_pause_frames = 0; +	drvs->pmem_fifo_overflow_drop = 0; +	drvs->rx_pause_frames = +		make_64bit_val(pport_stats->rx_pause_frames_lo, +				 pport_stats->rx_pause_frames_hi); +	drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi, +						pport_stats->rx_crc_errors_lo); +	drvs->rx_control_frames = +			make_64bit_val(pport_stats->rx_control_frames_hi, +			pport_stats->rx_control_frames_lo); +	drvs->rx_in_range_errors = pport_stats->rx_in_range_errors; +	drvs->rx_frame_too_long = +		make_64bit_val(pport_stats->rx_internal_mac_errors_hi, +					pport_stats->rx_frames_too_long_lo); +	drvs->rx_dropped_runt = pport_stats->rx_dropped_runt; +	drvs->rx_ip_checksum_errs = pport_stats->rx_ip_checksum_errors; +	drvs->rx_tcp_checksum_errs = pport_stats->rx_tcp_checksum_errors; +	drvs->rx_udp_checksum_errs = pport_stats->rx_udp_checksum_errors; +	drvs->rx_dropped_tcp_length = +				pport_stats->rx_dropped_invalid_tcp_length; +	drvs->rx_dropped_too_small = pport_stats->rx_dropped_too_small; +	drvs->rx_dropped_too_short = pport_stats->rx_dropped_too_short; +	drvs->rx_out_range_errors = pport_stats->rx_out_of_range_errors; +	drvs->rx_dropped_header_too_small = +				pport_stats->rx_dropped_header_too_small; +	drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow; +	drvs->rx_address_match_errors = pport_stats->rx_address_match_errors; +	drvs->rx_alignment_symbol_errors = +		make_64bit_val(pport_stats->rx_symbol_errors_hi, +				pport_stats->rx_symbol_errors_lo); +	drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow; +	drvs->tx_pauseframes = make_64bit_val(pport_stats->tx_pause_frames_hi, +					pport_stats->tx_pause_frames_lo); +	drvs->tx_controlframes = +		make_64bit_val(pport_stats->tx_control_frames_hi, +				pport_stats->tx_control_frames_lo); +	drvs->jabber_events = pport_stats->rx_jabbers; +	drvs->rx_drops_no_pbuf = 0; +	drvs->rx_drops_no_txpb = 0; +	drvs->rx_drops_no_erx_descr = 0; +	drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue; +	drvs->forwarded_packets = make_64bit_val(pport_stats->num_forwards_hi, +						pport_stats->num_forwards_lo); +	drvs->rx_drops_mtu = make_64bit_val(pport_stats->rx_drops_mtu_hi, +						pport_stats->rx_drops_mtu_lo); +	drvs->rx_drops_no_tpre_descr = 0; +	drvs->rx_drops_too_many_frags = +		make_64bit_val(pport_stats->rx_drops_too_many_frags_hi, +				pport_stats->rx_drops_too_many_frags_lo); +} + +void be_parse_stats(struct be_adapter *adapter) +{ +	if (adapter->generation == BE_GEN3) { +		if (lancer_chip(adapter)) +			populate_lancer_stats(adapter); +		 else +			populate_be3_stats(adapter); +	} else { +		populate_be2_stats(adapter); +	} +} +  void netdev_stats_update(struct be_adapter *adapter)  { -	struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va); -	struct be_rxf_stats *rxf_stats = &hw_stats->rxf; -	struct be_port_rxf_stats *port_stats = -			&rxf_stats->port[adapter->port_num]; +	struct be_drv_stats *drvs = &adapter->drv_stats;  	struct net_device_stats *dev_stats = &adapter->netdev->stats; -	struct be_erx_stats *erx_stats = &hw_stats->erx;  	struct be_rx_obj *rxo;  	int i; @@ -267,43 +435,54 @@ void netdev_stats_update(struct be_adapter *adapter)  		dev_stats->rx_bytes += rx_stats(rxo)->rx_bytes;  		dev_stats->multicast += rx_stats(rxo)->rx_mcast_pkts;  		/*  no space in linux buffers: best possible approximation */ -		dev_stats->rx_dropped += -			erx_stats->rx_drops_no_fragments[rxo->q.id]; +		if (adapter->generation == BE_GEN3) { +			if (!(lancer_chip(adapter))) { +				struct be_erx_stats_v1 *erx_stats = +					be_erx_stats_from_cmd(adapter); +				dev_stats->rx_dropped += +				erx_stats->rx_drops_no_fragments[rxo->q.id]; +			} +		} else { +			struct be_erx_stats_v0 *erx_stats = +					be_erx_stats_from_cmd(adapter); +			dev_stats->rx_dropped += +				erx_stats->rx_drops_no_fragments[rxo->q.id]; +		}  	}  	dev_stats->tx_packets = tx_stats(adapter)->be_tx_pkts;  	dev_stats->tx_bytes = tx_stats(adapter)->be_tx_bytes;  	/* bad pkts received */ -	dev_stats->rx_errors = port_stats->rx_crc_errors + -		port_stats->rx_alignment_symbol_errors + -		port_stats->rx_in_range_errors + -		port_stats->rx_out_range_errors + -		port_stats->rx_frame_too_long + -		port_stats->rx_dropped_too_small + -		port_stats->rx_dropped_too_short + -		port_stats->rx_dropped_header_too_small + -		port_stats->rx_dropped_tcp_length + -		port_stats->rx_dropped_runt + -		port_stats->rx_tcp_checksum_errs + -		port_stats->rx_ip_checksum_errs + -		port_stats->rx_udp_checksum_errs; +	dev_stats->rx_errors = drvs->rx_crc_errors + +		drvs->rx_alignment_symbol_errors + +		drvs->rx_in_range_errors + +		drvs->rx_out_range_errors + +		drvs->rx_frame_too_long + +		drvs->rx_dropped_too_small + +		drvs->rx_dropped_too_short + +		drvs->rx_dropped_header_too_small + +		drvs->rx_dropped_tcp_length + +		drvs->rx_dropped_runt + +		drvs->rx_tcp_checksum_errs + +		drvs->rx_ip_checksum_errs + +		drvs->rx_udp_checksum_errs;  	/* detailed rx errors */ -	dev_stats->rx_length_errors = port_stats->rx_in_range_errors + -		port_stats->rx_out_range_errors + -		port_stats->rx_frame_too_long; +	dev_stats->rx_length_errors = drvs->rx_in_range_errors + +		drvs->rx_out_range_errors + +		drvs->rx_frame_too_long; -	dev_stats->rx_crc_errors = port_stats->rx_crc_errors; +	dev_stats->rx_crc_errors = drvs->rx_crc_errors;  	/* frame alignment errors */ -	dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors; +	dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors;  	/* receiver fifo overrun */  	/* drops_no_pbuf is no per i/f, it's per BE card */ -	dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + -					port_stats->rx_input_fifo_overflow + -					rxf_stats->rx_drops_no_pbuf; +	dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop + +				drvs->rx_input_fifo_overflow_drop + +				drvs->rx_drops_no_pbuf;  }  void be_link_status_update(struct be_adapter *adapter, bool link_up) @@ -703,7 +882,7 @@ static void be_set_multicast_list(struct net_device *netdev)  	struct be_adapter *adapter = netdev_priv(netdev);  	if (netdev->flags & IFF_PROMISC) { -		be_cmd_promiscuous_config(adapter, adapter->port_num, 1); +		be_cmd_promiscuous_config(adapter, true);  		adapter->promiscuous = true;  		goto done;  	} @@ -711,7 +890,7 @@ static void be_set_multicast_list(struct net_device *netdev)  	/* BE was previously in promiscuous mode; disable it */  	if (adapter->promiscuous) {  		adapter->promiscuous = false; -		be_cmd_promiscuous_config(adapter, adapter->port_num, 0); +		be_cmd_promiscuous_config(adapter, false);  	}  	/* Enable multicast promisc if num configured exceeds what we support */ @@ -993,9 +1172,10 @@ static void be_rx_compl_process(struct be_adapter *adapter,  			struct be_rx_obj *rxo,  			struct be_rx_compl_info *rxcp)  { +	struct net_device *netdev = adapter->netdev;  	struct sk_buff *skb; -	skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN); +	skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN);  	if (unlikely(!skb)) {  		if (net_ratelimit())  			dev_warn(&adapter->pdev->dev, "skb alloc failed\n"); @@ -1005,20 +1185,24 @@ static void be_rx_compl_process(struct be_adapter *adapter,  	skb_fill_rx_data(adapter, rxo, skb, rxcp); -	if (likely(adapter->rx_csum && csum_passed(rxcp))) +	if (likely((netdev->features & NETIF_F_RXCSUM) && csum_passed(rxcp)))  		skb->ip_summed = CHECKSUM_UNNECESSARY;  	else  		skb_checksum_none_assert(skb);  	skb->truesize = skb->len + sizeof(struct sk_buff); -	skb->protocol = eth_type_trans(skb, adapter->netdev); +	skb->protocol = eth_type_trans(skb, netdev); +	if (adapter->netdev->features & NETIF_F_RXHASH) +		skb->rxhash = rxcp->rss_hash; +  	if (unlikely(rxcp->vlanf)) {  		if (!adapter->vlan_grp || adapter->vlans_added == 0) {  			kfree_skb(skb);  			return;  		} -		vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rxcp->vid); +		vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, +					rxcp->vlan_tag);  	} else {  		netif_receive_skb(skb);  	} @@ -1072,11 +1256,14 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,  	skb->data_len = rxcp->pkt_size;  	skb->truesize += rxcp->pkt_size;  	skb->ip_summed = CHECKSUM_UNNECESSARY; +	if (adapter->netdev->features & NETIF_F_RXHASH) +		skb->rxhash = rxcp->rss_hash;  	if (likely(!rxcp->vlanf))  		napi_gro_frags(&eq_obj->napi);  	else -		vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, rxcp->vid); +		vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, +				rxcp->vlan_tag);  }  static void be_parse_rx_compl_v1(struct be_adapter *adapter, @@ -1101,8 +1288,14 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter,  		AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl);  	rxcp->pkt_type =  		AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl); -	rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl); -	rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl); +	rxcp->rss_hash = +		AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp); +	if (rxcp->vlanf) { +		rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, +					  compl); +		rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, +					       compl); +	}  }  static void be_parse_rx_compl_v0(struct be_adapter *adapter, @@ -1127,8 +1320,14 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter,  		AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl);  	rxcp->pkt_type =  		AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl); -	rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl); -	rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl); +	rxcp->rss_hash = +		AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp); +	if (rxcp->vlanf) { +		rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, +					  compl); +		rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, +					       compl); +	}  }  static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) @@ -1150,15 +1349,20 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)  	else  		be_parse_rx_compl_v0(adapter, compl, rxcp); -	/* vlanf could be wrongly set in some cards. ignore if vtm is not set */ -	if ((adapter->function_mode & 0x400) && !rxcp->vtm) -		rxcp->vlanf = 0; +	if (rxcp->vlanf) { +		/* vlanf could be wrongly set in some cards. +		 * ignore if vtm is not set */ +		if ((adapter->function_mode & 0x400) && !rxcp->vtm) +			rxcp->vlanf = 0; -	if (!lancer_chip(adapter)) -		rxcp->vid = swab16(rxcp->vid); +		if (!lancer_chip(adapter)) +			rxcp->vlan_tag = swab16(rxcp->vlan_tag); -	if ((adapter->pvid == rxcp->vid) && !adapter->vlan_tag[rxcp->vid]) -		rxcp->vlanf = 0; +		if (((adapter->pvid & VLAN_VID_MASK) == +		     (rxcp->vlan_tag & VLAN_VID_MASK)) && +		    !adapter->vlan_tag[rxcp->vlan_tag]) +			rxcp->vlanf = 0; +	}  	/* As the compl has been parsed, reset it; we wont touch it again */  	compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0; @@ -1255,7 +1459,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)  	return txcp;  } -static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) +static u16 be_tx_compl_process(struct be_adapter *adapter, u16 last_index)  {  	struct be_queue_info *txq = &adapter->tx_obj.q;  	struct be_eth_wrb *wrb; @@ -1282,9 +1486,8 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)  		queue_tail_inc(txq);  	} while (cur_index != last_index); -	atomic_sub(num_wrbs, &txq->used); -  	kfree_skb(sent_skb); +	return num_wrbs;  }  static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) @@ -1367,7 +1570,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)  	struct be_queue_info *tx_cq = &adapter->tx_obj.cq;  	struct be_queue_info *txq = &adapter->tx_obj.q;  	struct be_eth_tx_compl *txcp; -	u16 end_idx, cmpl = 0, timeo = 0; +	u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0;  	struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;  	struct sk_buff *sent_skb;  	bool dummy_wrb; @@ -1377,12 +1580,14 @@ static void be_tx_compl_clean(struct be_adapter *adapter)  		while ((txcp = be_tx_compl_get(tx_cq))) {  			end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,  					wrb_index, txcp); -			be_tx_compl_process(adapter, end_idx); +			num_wrbs += be_tx_compl_process(adapter, end_idx);  			cmpl++;  		}  		if (cmpl) {  			be_cq_notify(adapter, tx_cq->id, false, cmpl); +			atomic_sub(num_wrbs, &txq->used);  			cmpl = 0; +			num_wrbs = 0;  		}  		if (atomic_read(&txq->used) == 0 || ++timeo > 200) @@ -1402,7 +1607,8 @@ static void be_tx_compl_clean(struct be_adapter *adapter)  		index_adv(&end_idx,  			wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1,  			txq->len); -		be_tx_compl_process(adapter, end_idx); +		num_wrbs = be_tx_compl_process(adapter, end_idx); +		atomic_sub(num_wrbs, &txq->used);  	}  } @@ -1567,12 +1773,31 @@ static void be_rx_queues_destroy(struct be_adapter *adapter)  	}  } +static u32 be_num_rxqs_want(struct be_adapter *adapter) +{ +	if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && +		!adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { +		return 1 + MAX_RSS_QS; /* one default non-RSS queue */ +	} else { +		dev_warn(&adapter->pdev->dev, +			"No support for multiple RX queues\n"); +		return 1; +	} +} +  static int be_rx_queues_create(struct be_adapter *adapter)  {  	struct be_queue_info *eq, *q, *cq;  	struct be_rx_obj *rxo;  	int rc, i; +	adapter->num_rx_qs = min(be_num_rxqs_want(adapter), +				msix_enabled(adapter) ? +					adapter->num_msix_vec - 1 : 1); +	if (adapter->num_rx_qs != MAX_RX_QS) +		dev_warn(&adapter->pdev->dev, +			"Can create only %d RX queues", adapter->num_rx_qs); +  	adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;  	for_all_rx_queues(adapter, rxo, i) {  		rxo->adapter = adapter; @@ -1718,12 +1943,15 @@ static int be_poll_rx(struct napi_struct *napi, int budget)  			break;  		/* Ignore flush completions */ -		if (rxcp->num_rcvd) { +		if (rxcp->num_rcvd && rxcp->pkt_size) {  			if (do_gro(rxcp))  				be_rx_compl_process_gro(adapter, rxo, rxcp);  			else  				be_rx_compl_process(adapter, rxo, rxcp); +		} else if (rxcp->pkt_size == 0) { +			be_rx_compl_discard(adapter, rxo, rxcp);  		} +  		be_rx_stats_update(rxo, rxcp);  	} @@ -1754,12 +1982,12 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)  	struct be_queue_info *tx_cq = &adapter->tx_obj.cq;  	struct be_eth_tx_compl *txcp;  	int tx_compl = 0, mcc_compl, status = 0; -	u16 end_idx; +	u16 end_idx, num_wrbs = 0;  	while ((txcp = be_tx_compl_get(tx_cq))) {  		end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,  				wrb_index, txcp); -		be_tx_compl_process(adapter, end_idx); +		num_wrbs += be_tx_compl_process(adapter, end_idx);  		tx_compl++;  	} @@ -1775,6 +2003,8 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)  	if (tx_compl) {  		be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl); +		atomic_sub(num_wrbs, &txq->used); +  		/* As Tx wrbs have been freed up, wake up netdev queue if  		 * it was stopped due to lack of tx wrbs.  		 */ @@ -1837,6 +2067,9 @@ static void be_worker(struct work_struct *work)  	struct be_rx_obj *rxo;  	int i; +	if (!adapter->ue_detected && !lancer_chip(adapter)) +		be_detect_dump_ue(adapter); +  	/* when interrupts are not yet enabled, just reap any pending  	* mcc completions */  	if (!netif_running(adapter->netdev)) { @@ -1849,15 +2082,16 @@ static void be_worker(struct work_struct *work)  			be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl);  		} -		if (!adapter->ue_detected && !lancer_chip(adapter)) -			be_detect_dump_ue(adapter); -  		goto reschedule;  	} -	if (!adapter->stats_cmd_sent) -		be_cmd_get_stats(adapter, &adapter->stats_cmd); - +	if (!adapter->stats_cmd_sent) { +		if (lancer_chip(adapter)) +			lancer_cmd_get_pport_stats(adapter, +						&adapter->stats_cmd); +		else +			be_cmd_get_stats(adapter, &adapter->stats_cmd); +	}  	be_tx_rate_update(adapter);  	for_all_rx_queues(adapter, rxo, i) { @@ -1869,60 +2103,43 @@ static void be_worker(struct work_struct *work)  			be_post_rx_frags(rxo, GFP_KERNEL);  		}  	} -	if (!adapter->ue_detected && !lancer_chip(adapter)) -		be_detect_dump_ue(adapter);  reschedule: +	adapter->work_counter++;  	schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));  }  static void be_msix_disable(struct be_adapter *adapter)  { -	if (adapter->msix_enabled) { +	if (msix_enabled(adapter)) {  		pci_disable_msix(adapter->pdev); -		adapter->msix_enabled = false; -	} -} - -static int be_num_rxqs_get(struct be_adapter *adapter) -{ -	if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && -		!adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { -		return 1 + MAX_RSS_QS; /* one default non-RSS queue */ -	} else { -		dev_warn(&adapter->pdev->dev, -			"No support for multiple RX queues\n"); -		return 1; +		adapter->num_msix_vec = 0;  	}  }  static void be_msix_enable(struct be_adapter *adapter)  {  #define BE_MIN_MSIX_VECTORS	(1 + 1) /* Rx + Tx */ -	int i, status; +	int i, status, num_vec; -	adapter->num_rx_qs = be_num_rxqs_get(adapter); +	num_vec = be_num_rxqs_want(adapter) + 1; -	for (i = 0; i < (adapter->num_rx_qs + 1); i++) +	for (i = 0; i < num_vec; i++)  		adapter->msix_entries[i].entry = i; -	status = pci_enable_msix(adapter->pdev, adapter->msix_entries, -			adapter->num_rx_qs + 1); +	status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec);  	if (status == 0) {  		goto done;  	} else if (status >= BE_MIN_MSIX_VECTORS) { +		num_vec = status;  		if (pci_enable_msix(adapter->pdev, adapter->msix_entries, -				status) == 0) { -			adapter->num_rx_qs = status - 1; -			dev_warn(&adapter->pdev->dev, -				"Could alloc only %d MSIx vectors. " -				"Using %d RX Qs\n", status, adapter->num_rx_qs); +				num_vec) == 0)  			goto done; -		}  	}  	return;  done: -	adapter->msix_enabled = true; +	adapter->num_msix_vec = num_vec; +	return;  }  static void be_sriov_enable(struct be_adapter *adapter) @@ -1930,7 +2147,20 @@ static void be_sriov_enable(struct be_adapter *adapter)  	be_check_sriov_fn_type(adapter);  #ifdef CONFIG_PCI_IOV  	if (be_physfn(adapter) && num_vfs) { -		int status; +		int status, pos; +		u16 nvfs; + +		pos = pci_find_ext_capability(adapter->pdev, +						PCI_EXT_CAP_ID_SRIOV); +		pci_read_config_word(adapter->pdev, +					pos + PCI_SRIOV_TOTAL_VF, &nvfs); + +		if (num_vfs > nvfs) { +			dev_info(&adapter->pdev->dev, +					"Device supports %d VFs and not %d\n", +					nvfs, num_vfs); +			num_vfs = nvfs; +		}  		status = pci_enable_sriov(adapter->pdev, num_vfs);  		adapter->sriov_enabled = status ? false : true; @@ -2003,8 +2233,7 @@ err_msix:  err:  	dev_warn(&adapter->pdev->dev,  		"MSIX Request IRQ failed - err %d\n", status); -	pci_disable_msix(adapter->pdev); -	adapter->msix_enabled = false; +	be_msix_disable(adapter);  	return status;  } @@ -2013,7 +2242,7 @@ static int be_irq_register(struct be_adapter *adapter)  	struct net_device *netdev = adapter->netdev;  	int status; -	if (adapter->msix_enabled) { +	if (msix_enabled(adapter)) {  		status = be_msix_register(adapter);  		if (status == 0)  			goto done; @@ -2046,7 +2275,7 @@ static void be_irq_unregister(struct be_adapter *adapter)  		return;  	/* INTx */ -	if (!adapter->msix_enabled) { +	if (!msix_enabled(adapter)) {  		free_irq(netdev->irq, adapter);  		goto done;  	} @@ -2088,7 +2317,7 @@ static int be_close(struct net_device *netdev)  			 be_cq_notify(adapter, rxo->cq.id, false, 0);  	} -	if (adapter->msix_enabled) { +	if (msix_enabled(adapter)) {  		vec = be_msix_vec_get(adapter, tx_eq);  		synchronize_irq(vec); @@ -2141,7 +2370,7 @@ static int be_open(struct net_device *netdev)  	be_async_mcc_enable(adapter);  	status = be_cmd_link_status_query(adapter, &link_up, &mac_speed, -			&link_speed); +			&link_speed, 0);  	if (status)  		goto err;  	be_link_status_update(adapter, link_up); @@ -2261,7 +2490,7 @@ static int be_setup(struct be_adapter *adapter)  				BE_IF_FLAGS_PASS_L3L4_ERRORS;  		en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS; -		if (be_multi_rxq(adapter)) { +		if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) {  			cap_flags |= BE_IF_FLAGS_RSS;  			en_flags |= BE_IF_FLAGS_RSS;  		} @@ -2318,7 +2547,6 @@ static int be_setup(struct be_adapter *adapter)  	return 0; -	be_mcc_queues_destroy(adapter);  rx_qs_destroy:  	be_rx_queues_destroy(adapter);  tx_qs_destroy: @@ -2486,7 +2714,6 @@ static int be_flash_data(struct be_adapter *adapter,  					"cmd to write to flash rom failed.\n");  				return -1;  			} -			yield();  		}  	}  	return 0; @@ -2504,32 +2731,96 @@ static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr)  		return 0;  } -int be_load_fw(struct be_adapter *adapter, u8 *func) +static int lancer_fw_download(struct be_adapter *adapter, +				const struct firmware *fw)  { -	char fw_file[ETHTOOL_FLASH_MAX_FILENAME]; -	const struct firmware *fw; -	struct flash_file_hdr_g2 *fhdr; -	struct flash_file_hdr_g3 *fhdr3; -	struct image_hdr *img_hdr_ptr = NULL; +#define LANCER_FW_DOWNLOAD_CHUNK      (32 * 1024) +#define LANCER_FW_DOWNLOAD_LOCATION   "/prg"  	struct be_dma_mem flash_cmd; -	int status, i = 0, num_imgs = 0; -	const u8 *p; +	const u8 *data_ptr = NULL; +	u8 *dest_image_ptr = NULL; +	size_t image_size = 0; +	u32 chunk_size = 0; +	u32 data_written = 0; +	u32 offset = 0; +	int status = 0; +	u8 add_status = 0; -	if (!netif_running(adapter->netdev)) { +	if (!IS_ALIGNED(fw->size, sizeof(u32))) {  		dev_err(&adapter->pdev->dev, -			"Firmware load not allowed (interface is down)\n"); -		return -EPERM; +			"FW Image not properly aligned. " +			"Length must be 4 byte aligned.\n"); +		status = -EINVAL; +		goto lancer_fw_exit; +	} + +	flash_cmd.size = sizeof(struct lancer_cmd_req_write_object) +				+ LANCER_FW_DOWNLOAD_CHUNK; +	flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size, +						&flash_cmd.dma, GFP_KERNEL); +	if (!flash_cmd.va) { +		status = -ENOMEM; +		dev_err(&adapter->pdev->dev, +			"Memory allocation failure while flashing\n"); +		goto lancer_fw_exit;  	} -	strcpy(fw_file, func); +	dest_image_ptr = flash_cmd.va + +				sizeof(struct lancer_cmd_req_write_object); +	image_size = fw->size; +	data_ptr = fw->data; -	status = request_firmware(&fw, fw_file, &adapter->pdev->dev); -	if (status) -		goto fw_exit; +	while (image_size) { +		chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK); + +		/* Copy the image chunk content. */ +		memcpy(dest_image_ptr, data_ptr, chunk_size); + +		status = lancer_cmd_write_object(adapter, &flash_cmd, +				chunk_size, offset, LANCER_FW_DOWNLOAD_LOCATION, +				&data_written, &add_status); + +		if (status) +			break; + +		offset += data_written; +		data_ptr += data_written; +		image_size -= data_written; +	} + +	if (!status) { +		/* Commit the FW written */ +		status = lancer_cmd_write_object(adapter, &flash_cmd, +					0, offset, LANCER_FW_DOWNLOAD_LOCATION, +					&data_written, &add_status); +	} + +	dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va, +				flash_cmd.dma); +	if (status) { +		dev_err(&adapter->pdev->dev, +			"Firmware load error. " +			"Status code: 0x%x Additional Status: 0x%x\n", +			status, add_status); +		goto lancer_fw_exit; +	} + +	dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); +lancer_fw_exit: +	return status; +} + +static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw) +{ +	struct flash_file_hdr_g2 *fhdr; +	struct flash_file_hdr_g3 *fhdr3; +	struct image_hdr *img_hdr_ptr = NULL; +	struct be_dma_mem flash_cmd; +	const u8 *p; +	int status = 0, i = 0, num_imgs = 0;  	p = fw->data;  	fhdr = (struct flash_file_hdr_g2 *) p; -	dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);  	flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024;  	flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size, @@ -2538,7 +2829,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)  		status = -ENOMEM;  		dev_err(&adapter->pdev->dev,  			"Memory allocation failure while flashing\n"); -		goto fw_exit; +		goto be_fw_exit;  	}  	if ((adapter->generation == BE_GEN3) && @@ -2566,11 +2857,37 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)  			  flash_cmd.dma);  	if (status) {  		dev_err(&adapter->pdev->dev, "Firmware load error\n"); -		goto fw_exit; +		goto be_fw_exit;  	}  	dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); +be_fw_exit: +	return status; +} + +int be_load_fw(struct be_adapter *adapter, u8 *fw_file) +{ +	const struct firmware *fw; +	int status; + +	if (!netif_running(adapter->netdev)) { +		dev_err(&adapter->pdev->dev, +			"Firmware load not allowed (interface is down)\n"); +		return -1; +	} + +	status = request_firmware(&fw, fw_file, &adapter->pdev->dev); +	if (status) +		goto fw_exit; + +	dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); + +	if (lancer_chip(adapter)) +		status = lancer_fw_download(adapter, fw); +	else +		status = be_fw_download(adapter, fw); +  fw_exit:  	release_firmware(fw);  	return status; @@ -2599,10 +2916,14 @@ static void be_netdev_init(struct net_device *netdev)  	struct be_rx_obj *rxo;  	int i; -	netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | -		NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | -		NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | -		NETIF_F_GRO | NETIF_F_TSO6; +	netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | +		NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | +		NETIF_F_HW_VLAN_TX; +	if (be_multi_rxq(adapter)) +		netdev->hw_features |= NETIF_F_RXHASH; + +	netdev->features |= netdev->hw_features | +		NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;  	netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO |  		NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; @@ -2612,8 +2933,6 @@ static void be_netdev_init(struct net_device *netdev)  	netdev->flags |= IFF_MULTICAST; -	adapter->rx_csum = true; -  	/* Default settings for Rx and Tx flow control */  	adapter->rx_fc = true;  	adapter->tx_fc = true; @@ -2781,7 +3100,14 @@ static int be_stats_init(struct be_adapter *adapter)  {  	struct be_dma_mem *cmd = &adapter->stats_cmd; -	cmd->size = sizeof(struct be_cmd_req_get_stats); +	if (adapter->generation == BE_GEN2) { +		cmd->size = sizeof(struct be_cmd_req_get_stats_v0); +	} else { +		if (lancer_chip(adapter)) +			cmd->size = sizeof(struct lancer_cmd_req_pport_stats); +		else +			cmd->size = sizeof(struct be_cmd_req_get_stats_v1); +	}  	cmd->va = dma_alloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma,  				     GFP_KERNEL);  	if (cmd->va == NULL) @@ -2807,6 +3133,7 @@ static void __devexit be_remove(struct pci_dev *pdev)  	be_ctrl_cleanup(adapter); +	kfree(adapter->vf_cfg);  	be_sriov_disable(adapter);  	be_msix_disable(adapter); @@ -2834,7 +3161,8 @@ static int be_get_config(struct be_adapter *adapter)  	memset(mac, 0, ETH_ALEN); -	if (be_physfn(adapter)) { +	/* A default permanent address is given to each VF for Lancer*/ +	if (be_physfn(adapter) || lancer_chip(adapter)) {  		status = be_cmd_mac_addr_query(adapter, mac,  			MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0); @@ -2876,6 +3204,7 @@ static int be_dev_family_check(struct be_adapter *adapter)  		adapter->generation = BE_GEN3;  		break;  	case OC_DEVICE_ID3: +	case OC_DEVICE_ID4:  		pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);  		if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>  						SLI_INTF_IF_TYPE_SHIFT; @@ -2885,10 +3214,6 @@ static int be_dev_family_check(struct be_adapter *adapter)  			dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");  			return -EINVAL;  		} -		if (num_vfs > 0) { -			dev_err(&pdev->dev, "VFs not supported\n"); -			return -EINVAL; -		}  		adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >>  					 SLI_INTF_FAMILY_SHIFT);  		adapter->generation = BE_GEN3; @@ -2991,16 +3316,23 @@ static int __devinit be_probe(struct pci_dev *pdev,  	}  	be_sriov_enable(adapter); +	if (adapter->sriov_enabled) { +		adapter->vf_cfg = kcalloc(num_vfs, +			sizeof(struct be_vf_cfg), GFP_KERNEL); + +		if (!adapter->vf_cfg) +			goto free_netdev; +	}  	status = be_ctrl_init(adapter);  	if (status) -		goto free_netdev; +		goto free_vf_cfg;  	if (lancer_chip(adapter)) {  		status = lancer_test_and_set_rdy_state(adapter);  		if (status) {  			dev_err(&pdev->dev, "Adapter in non recoverable error\n"); -			goto free_netdev; +			goto ctrl_clean;  		}  	} @@ -3043,9 +3375,24 @@ static int __devinit be_probe(struct pci_dev *pdev,  	netif_carrier_off(netdev);  	if (be_physfn(adapter) && adapter->sriov_enabled) { -		status = be_vf_eth_addr_config(adapter); -		if (status) -			goto unreg_netdev; +		u8 mac_speed; +		bool link_up; +		u16 vf, lnk_speed; + +		if (!lancer_chip(adapter)) { +			status = be_vf_eth_addr_config(adapter); +			if (status) +				goto unreg_netdev; +		} + +		for (vf = 0; vf < num_vfs; vf++) { +			status = be_cmd_link_status_query(adapter, &link_up, +					&mac_speed, &lnk_speed, vf + 1); +			if (!status) +				adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10; +			else +				goto unreg_netdev; +		}  	}  	dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); @@ -3062,6 +3409,8 @@ stats_clean:  	be_stats_cleanup(adapter);  ctrl_clean:  	be_ctrl_cleanup(adapter); +free_vf_cfg: +	kfree(adapter->vf_cfg);  free_netdev:  	be_sriov_disable(adapter);  	free_netdev(netdev); @@ -3146,16 +3495,15 @@ static void be_shutdown(struct pci_dev *pdev)  	if (!adapter)  		return; -	if (netif_running(adapter->netdev)) -		cancel_delayed_work_sync(&adapter->work); +	cancel_delayed_work_sync(&adapter->work);  	netif_device_detach(adapter->netdev); -	be_cmd_reset_function(adapter); -  	if (adapter->wol)  		be_setup_wol(adapter, true); +	be_cmd_reset_function(adapter); +  	pci_disable_device(pdev);  } @@ -3267,13 +3615,6 @@ static int __init be_init_module(void)  		rx_frag_size = 2048;  	} -	if (num_vfs > 32) { -		printk(KERN_WARNING DRV_NAME -			" : Module param num_vfs must not be greater than 32." -			"Using 32\n"); -		num_vfs = 32; -	} -  	return pci_register_driver(&be_driver);  }  module_init(be_init_module);  |