diff options
Diffstat (limited to 'drivers/net/ethernet/emulex/benet/be_main.c')
| -rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 516 | 
1 files changed, 295 insertions, 221 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 501dfa9c88e..4d967717449 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -155,7 +155,7 @@ static void be_intr_set(struct be_adapter *adapter, bool enable)  {  	u32 reg, enabled; -	if (adapter->eeh_err) +	if (adapter->eeh_error)  		return;  	pci_read_config_dword(adapter->pdev, PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET, @@ -201,7 +201,7 @@ static void be_eq_notify(struct be_adapter *adapter, u16 qid,  	val |= ((qid & DB_EQ_RING_ID_EXT_MASK) <<  			DB_EQ_RING_ID_EXT_MASK_SHIFT); -	if (adapter->eeh_err) +	if (adapter->eeh_error)  		return;  	if (arm) @@ -220,7 +220,7 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped)  	val |= ((qid & DB_CQ_RING_ID_EXT_MASK) <<  			DB_CQ_RING_ID_EXT_MASK_SHIFT); -	if (adapter->eeh_err) +	if (adapter->eeh_error)  		return;  	if (arm) @@ -558,6 +558,7 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)  	wrb->frag_pa_hi = upper_32_bits(addr);  	wrb->frag_pa_lo = addr & 0xFFFFFFFF;  	wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK; +	wrb->rsvd0 = 0;  }  static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, @@ -576,6 +577,11 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,  	return vlan_tag;  } +static int be_vlan_tag_chk(struct be_adapter *adapter, struct sk_buff *skb) +{ +	return vlan_tx_tag_present(skb) || adapter->pvid; +} +  static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,  		struct sk_buff *skb, u32 wrb_cnt, u32 len)  { @@ -703,33 +709,56 @@ dma_err:  	return 0;  } +static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, +					     struct sk_buff *skb) +{ +	u16 vlan_tag = 0; + +	skb = skb_share_check(skb, GFP_ATOMIC); +	if (unlikely(!skb)) +		return skb; + +	if (vlan_tx_tag_present(skb)) { +		vlan_tag = be_get_tx_vlan_tag(adapter, skb); +		__vlan_put_tag(skb, vlan_tag); +		skb->vlan_tci = 0; +	} + +	return skb; +} +  static netdev_tx_t be_xmit(struct sk_buff *skb,  			struct net_device *netdev)  {  	struct be_adapter *adapter = netdev_priv(netdev);  	struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)];  	struct be_queue_info *txq = &txo->q; +	struct iphdr *ip = NULL;  	u32 wrb_cnt = 0, copied = 0; -	u32 start = txq->head; +	u32 start = txq->head, eth_hdr_len;  	bool dummy_wrb, stopped = false; -	/* For vlan tagged pkts, BE -	 * 1) calculates checksum even when CSO is not requested -	 * 2) calculates checksum wrongly for padded pkt less than -	 * 60 bytes long. -	 * As a workaround disable TX vlan offloading in such cases. +	eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? +		VLAN_ETH_HLEN : ETH_HLEN; + +	/* HW has a bug which considers padding bytes as legal +	 * and modifies the IPv4 hdr's 'tot_len' field  	 */ -	if (unlikely(vlan_tx_tag_present(skb) && -		     (skb->ip_summed != CHECKSUM_PARTIAL || skb->len <= 60))) { -		skb = skb_share_check(skb, GFP_ATOMIC); -		if (unlikely(!skb)) -			goto tx_drop; +	if (skb->len <= 60 && be_vlan_tag_chk(adapter, skb) && +			is_ipv4_pkt(skb)) { +		ip = (struct iphdr *)ip_hdr(skb); +		pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len)); +	} -		skb = __vlan_put_tag(skb, be_get_tx_vlan_tag(adapter, skb)); +	/* HW has a bug wherein it will calculate CSUM for VLAN +	 * pkts even though it is disabled. +	 * Manually insert VLAN in pkt. +	 */ +	if (skb->ip_summed != CHECKSUM_PARTIAL && +			be_vlan_tag_chk(adapter, skb)) { +		skb = be_insert_vlan_in_pkt(adapter, skb);  		if (unlikely(!skb))  			goto tx_drop; - -		skb->vlan_tci = 0;  	}  	wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); @@ -786,19 +815,12 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)   * A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE.   * If the user configures more, place BE in vlan promiscuous mode.   */ -static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) +static int be_vid_config(struct be_adapter *adapter)  { -	struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf_num]; -	u16 vtag[BE_NUM_VLANS_SUPPORTED]; -	u16 ntags = 0, i; +	u16 vids[BE_NUM_VLANS_SUPPORTED]; +	u16 num = 0, i;  	int status = 0; -	if (vf) { -		vtag[0] = cpu_to_le16(vf_cfg->vlan_tag); -		status = be_cmd_vlan_config(adapter, vf_cfg->if_handle, vtag, -					    1, 1, 0); -	} -  	/* No need to further configure vids if in promiscuous mode */  	if (adapter->promiscuous)  		return 0; @@ -809,10 +831,10 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)  	/* Construct VLAN Table to give to HW */  	for (i = 0; i < VLAN_N_VID; i++)  		if (adapter->vlan_tag[i]) -			vtag[ntags++] = cpu_to_le16(i); +			vids[num++] = cpu_to_le16(i);  	status = be_cmd_vlan_config(adapter, adapter->if_handle, -				    vtag, ntags, 1, 0); +				    vids, num, 1, 0);  	/* Set to VLAN promisc mode as setting VLAN filter failed */  	if (status) { @@ -841,7 +863,7 @@ static int be_vlan_add_vid(struct net_device *netdev, u16 vid)  	adapter->vlan_tag[vid] = 1;  	if (adapter->vlans_added <= (adapter->max_vlans + 1)) -		status = be_vid_config(adapter, false, 0); +		status = be_vid_config(adapter);  	if (!status)  		adapter->vlans_added++; @@ -863,7 +885,7 @@ static int be_vlan_rem_vid(struct net_device *netdev, u16 vid)  	adapter->vlan_tag[vid] = 0;  	if (adapter->vlans_added <= adapter->max_vlans) -		status = be_vid_config(adapter, false, 0); +		status = be_vid_config(adapter);  	if (!status)  		adapter->vlans_added--; @@ -890,7 +912,7 @@ static void be_set_rx_mode(struct net_device *netdev)  		be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);  		if (adapter->vlans_added) -			be_vid_config(adapter, false, 0); +			be_vid_config(adapter);  	}  	/* Enable multicast promisc if num configured exceeds what we support */ @@ -1057,13 +1079,16 @@ static int be_find_vfs(struct be_adapter *adapter, int vf_state)  	u16 offset, stride;  	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); +	if (!pos) +		return 0;  	pci_read_config_word(pdev, pos + PCI_SRIOV_VF_OFFSET, &offset);  	pci_read_config_word(pdev, pos + PCI_SRIOV_VF_STRIDE, &stride);  	dev = pci_get_device(pdev->vendor, PCI_ANY_ID, NULL);  	while (dev) {  		vf_fn = (pdev->devfn + offset + stride * vfs) & 0xFFFF; -		if (dev->is_virtfn && dev->devfn == vf_fn) { +		if (dev->is_virtfn && dev->devfn == vf_fn && +			dev->bus->number == pdev->bus->number) {  			vfs++;  			if (dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)  				assigned_vfs++; @@ -1203,16 +1228,16 @@ static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb,  	/* Copy data in the first descriptor of this completion */  	curr_frag_len = min(rxcp->pkt_size, rx_frag_size); -	/* Copy the header portion into skb_data */ -	hdr_len = min(BE_HDR_LEN, curr_frag_len); -	memcpy(skb->data, start, hdr_len);  	skb->len = curr_frag_len;  	if (curr_frag_len <= BE_HDR_LEN) { /* tiny packet */ +		memcpy(skb->data, start, curr_frag_len);  		/* Complete packet has now been moved to data */  		put_page(page_info->page);  		skb->data_len = 0;  		skb->tail += curr_frag_len;  	} else { +		hdr_len = ETH_HLEN; +		memcpy(skb->data, start, hdr_len);  		skb_shinfo(skb)->nr_frags = 1;  		skb_frag_set_page(skb, 0, page_info->page);  		skb_shinfo(skb)->frags[0].page_offset = @@ -1709,9 +1734,10 @@ static void be_evt_queues_destroy(struct be_adapter *adapter)  	int i;  	for_all_evt_queues(adapter, eqo, i) { -		be_eq_clean(eqo); -		if (eqo->q.created) +		if (eqo->q.created) { +			be_eq_clean(eqo);  			be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ); +		}  		be_queue_free(adapter, &eqo->q);  	}  } @@ -1898,6 +1924,12 @@ static int be_rx_cqs_create(struct be_adapter *adapter)  	 */  	adapter->num_rx_qs = (num_irqs(adapter) > 1) ?  				num_irqs(adapter) + 1 : 1; +	if (adapter->num_rx_qs != MAX_RX_QS) { +		rtnl_lock(); +		netif_set_real_num_rx_queues(adapter->netdev, +					     adapter->num_rx_qs); +		rtnl_unlock(); +	}  	adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;  	for_all_rx_queues(adapter, rxo, i) { @@ -2067,13 +2099,13 @@ int be_poll(struct napi_struct *napi, int budget)  	return max_work;  } -void be_detect_dump_ue(struct be_adapter *adapter) +void be_detect_error(struct be_adapter *adapter)  {  	u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0;  	u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;  	u32 i; -	if (adapter->eeh_err || adapter->ue_detected) +	if (be_crit_error(adapter))  		return;  	if (lancer_chip(adapter)) { @@ -2094,16 +2126,24 @@ void be_detect_dump_ue(struct be_adapter *adapter)  		pci_read_config_dword(adapter->pdev,  				PCICFG_UE_STATUS_HI_MASK, &ue_hi_mask); -		ue_lo = (ue_lo & (~ue_lo_mask)); -		ue_hi = (ue_hi & (~ue_hi_mask)); +		ue_lo = (ue_lo & ~ue_lo_mask); +		ue_hi = (ue_hi & ~ue_hi_mask);  	}  	if (ue_lo || ue_hi ||  		sliport_status & SLIPORT_STATUS_ERR_MASK) { -		adapter->ue_detected = true; -		adapter->eeh_err = true; +		adapter->hw_error = true; +		dev_err(&adapter->pdev->dev, +			"Error detected in the card\n"); +	} + +	if (sliport_status & SLIPORT_STATUS_ERR_MASK) { +		dev_err(&adapter->pdev->dev, +			"ERR: sliport status 0x%x\n", sliport_status);  		dev_err(&adapter->pdev->dev, -			"Unrecoverable error in the card\n"); +			"ERR: sliport error1 0x%x\n", sliport_err1); +		dev_err(&adapter->pdev->dev, +			"ERR: sliport error2 0x%x\n", sliport_err2);  	}  	if (ue_lo) { @@ -2113,6 +2153,7 @@ void be_detect_dump_ue(struct be_adapter *adapter)  				"UE: %s bit set\n", ue_status_low_desc[i]);  		}  	} +  	if (ue_hi) {  		for (i = 0; ue_hi; ue_hi >>= 1, i++) {  			if (ue_hi & 1) @@ -2121,14 +2162,6 @@ void be_detect_dump_ue(struct be_adapter *adapter)  		}  	} -	if (sliport_status & SLIPORT_STATUS_ERR_MASK) { -		dev_err(&adapter->pdev->dev, -			"sliport status 0x%x\n", sliport_status); -		dev_err(&adapter->pdev->dev, -			"sliport error1 0x%x\n", sliport_err1); -		dev_err(&adapter->pdev->dev, -			"sliport error2 0x%x\n", sliport_err2); -	}  }  static void be_msix_disable(struct be_adapter *adapter) @@ -2141,12 +2174,14 @@ static void be_msix_disable(struct be_adapter *adapter)  static uint be_num_rss_want(struct be_adapter *adapter)  { +	u32 num = 0;  	if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&  	     !sriov_want(adapter) && be_physfn(adapter) && -	     !be_is_mc(adapter)) -		return (adapter->be3_native) ? BE3_MAX_RSS_QS : BE2_MAX_RSS_QS; -	else -		return 0; +	     !be_is_mc(adapter)) { +		num = (adapter->be3_native) ? BE3_MAX_RSS_QS : BE2_MAX_RSS_QS; +		num = min_t(u32, num, (u32)netif_get_num_default_rss_queues()); +	} +	return num;  }  static void be_msix_enable(struct be_adapter *adapter) @@ -2540,11 +2575,7 @@ static int be_clear(struct be_adapter *adapter)  	be_tx_queues_destroy(adapter);  	be_evt_queues_destroy(adapter); -	/* tell fw we're done with firing cmds */ -	be_cmd_fw_clean(adapter); -  	be_msix_disable(adapter); -	pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 0);  	return 0;  } @@ -2602,8 +2633,8 @@ static int be_vf_setup(struct be_adapter *adapter)  	cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |  				BE_IF_FLAGS_MULTICAST;  	for_all_vfs(adapter, vf_cfg, vf) { -		status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL, -					  &vf_cfg->if_handle, NULL, vf + 1); +		status = be_cmd_if_create(adapter, cap_flags, en_flags, +					  &vf_cfg->if_handle, vf + 1);  		if (status)  			goto err;  	} @@ -2643,29 +2674,43 @@ static void be_setup_init(struct be_adapter *adapter)  	adapter->phy.forced_port_speed = -1;  } -static int be_add_mac_from_list(struct be_adapter *adapter, u8 *mac) +static int be_get_mac_addr(struct be_adapter *adapter, u8 *mac, u32 if_handle, +			   bool *active_mac, u32 *pmac_id)  { -	u32 pmac_id; -	int status; -	bool pmac_id_active; +	int status = 0; -	status = be_cmd_get_mac_from_list(adapter, 0, &pmac_id_active, -							&pmac_id, mac); -	if (status != 0) -		goto do_none; +	if (!is_zero_ether_addr(adapter->netdev->perm_addr)) { +		memcpy(mac, adapter->netdev->dev_addr, ETH_ALEN); +		if (!lancer_chip(adapter) && !be_physfn(adapter)) +			*active_mac = true; +		else +			*active_mac = false; -	if (pmac_id_active) { -		status = be_cmd_mac_addr_query(adapter, mac, -				MAC_ADDRESS_TYPE_NETWORK, -				false, adapter->if_handle, pmac_id); +		return status; +	} -		if (!status) -			adapter->pmac_id[0] = pmac_id; +	if (lancer_chip(adapter)) { +		status = be_cmd_get_mac_from_list(adapter, mac, +						  active_mac, pmac_id, 0); +		if (*active_mac) { +			status = be_cmd_mac_addr_query(adapter, mac, +						       MAC_ADDRESS_TYPE_NETWORK, +						       false, if_handle, +						       *pmac_id); +		} +	} else if (be_physfn(adapter)) { +		/* For BE3, for PF get permanent MAC */ +		status = be_cmd_mac_addr_query(adapter, mac, +					       MAC_ADDRESS_TYPE_NETWORK, true, +					       0, 0); +		*active_mac = false;  	} else { -		status = be_cmd_pmac_add(adapter, mac, -				adapter->if_handle, &adapter->pmac_id[0], 0); +		/* For BE3, for VF get soft MAC assigned by PF*/ +		status = be_cmd_mac_addr_query(adapter, mac, +					       MAC_ADDRESS_TYPE_NETWORK, false, +					       if_handle, 0); +		*active_mac = true;  	} -do_none:  	return status;  } @@ -2686,12 +2731,12 @@ static int be_get_config(struct be_adapter *adapter)  static int be_setup(struct be_adapter *adapter)  { -	struct net_device *netdev = adapter->netdev;  	struct device *dev = &adapter->pdev->dev;  	u32 cap_flags, en_flags;  	u32 tx_fc, rx_fc;  	int status;  	u8 mac[ETH_ALEN]; +	bool active_mac;  	be_setup_init(adapter); @@ -2717,14 +2762,6 @@ static int be_setup(struct be_adapter *adapter)  	if (status)  		goto err; -	memset(mac, 0, ETH_ALEN); -	status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, -			true /*permanent */, 0, 0); -	if (status) -		return status; -	memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); -	memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); -  	en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |  			BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;  	cap_flags = en_flags | BE_IF_FLAGS_MCAST_PROMISCUOUS | @@ -2734,27 +2771,36 @@ static int be_setup(struct be_adapter *adapter)  		cap_flags |= BE_IF_FLAGS_RSS;  		en_flags |= BE_IF_FLAGS_RSS;  	} + +	if (lancer_chip(adapter) && !be_physfn(adapter)) { +		en_flags = BE_IF_FLAGS_UNTAGGED | +			    BE_IF_FLAGS_BROADCAST | +			    BE_IF_FLAGS_MULTICAST; +		cap_flags = en_flags; +	} +  	status = be_cmd_if_create(adapter, cap_flags, en_flags, -			netdev->dev_addr, &adapter->if_handle, -			&adapter->pmac_id[0], 0); +				  &adapter->if_handle, 0);  	if (status != 0)  		goto err; -	 /* The VF's permanent mac queried from card is incorrect. -	  * For BEx: Query the mac configued by the PF using if_handle -	  * For Lancer: Get and use mac_list to obtain mac address. -	  */ -	if (!be_physfn(adapter)) { -		if (lancer_chip(adapter)) -			status = be_add_mac_from_list(adapter, mac); -		else -			status = be_cmd_mac_addr_query(adapter, mac, -					MAC_ADDRESS_TYPE_NETWORK, false, -					adapter->if_handle, 0); -		if (!status) { -			memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); -			memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); -		} +	memset(mac, 0, ETH_ALEN); +	active_mac = false; +	status = be_get_mac_addr(adapter, mac, adapter->if_handle, +				 &active_mac, &adapter->pmac_id[0]); +	if (status != 0) +		goto err; + +	if (!active_mac) { +		status = be_cmd_pmac_add(adapter, mac, adapter->if_handle, +					 &adapter->pmac_id[0], 0); +		if (status != 0) +			goto err; +	} + +	if (is_zero_ether_addr(adapter->netdev->dev_addr)) { +		memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); +		memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);  	}  	status = be_tx_qs_create(adapter); @@ -2763,7 +2809,8 @@ static int be_setup(struct be_adapter *adapter)  	be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL); -	be_vid_config(adapter, false, 0); +	if (adapter->vlans_added) +		be_vid_config(adapter);  	be_set_rx_mode(adapter->netdev); @@ -2773,8 +2820,6 @@ static int be_setup(struct be_adapter *adapter)  		be_cmd_set_flow_control(adapter, adapter->tx_fc,  					adapter->rx_fc); -	pcie_set_readrq(adapter->pdev, 4096); -  	if (be_physfn(adapter) && num_vfs) {  		if (adapter->dev_num_vfs)  			be_vf_setup(adapter); @@ -2788,8 +2833,6 @@ static int be_setup(struct be_adapter *adapter)  	schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));  	adapter->flags |= BE_FLAGS_WORKER_SCHEDULED; - -	pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 1);  	return 0;  err:  	be_clear(adapter); @@ -3033,6 +3076,40 @@ static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr)  		return 0;  } +static int lancer_wait_idle(struct be_adapter *adapter) +{ +#define SLIPORT_IDLE_TIMEOUT 30 +	u32 reg_val; +	int status = 0, i; + +	for (i = 0; i < SLIPORT_IDLE_TIMEOUT; i++) { +		reg_val = ioread32(adapter->db + PHYSDEV_CONTROL_OFFSET); +		if ((reg_val & PHYSDEV_CONTROL_INP_MASK) == 0) +			break; + +		ssleep(1); +	} + +	if (i == SLIPORT_IDLE_TIMEOUT) +		status = -1; + +	return status; +} + +static int lancer_fw_reset(struct be_adapter *adapter) +{ +	int status = 0; + +	status = lancer_wait_idle(adapter); +	if (status) +		return status; + +	iowrite32(PHYSDEV_CONTROL_FW_RESET_MASK, adapter->db + +		  PHYSDEV_CONTROL_OFFSET); + +	return status; +} +  static int lancer_fw_download(struct be_adapter *adapter,  				const struct firmware *fw)  { @@ -3047,6 +3124,7 @@ static int lancer_fw_download(struct be_adapter *adapter,  	u32 offset = 0;  	int status = 0;  	u8 add_status = 0; +	u8 change_status;  	if (!IS_ALIGNED(fw->size, sizeof(u32))) {  		dev_err(&adapter->pdev->dev, @@ -3079,9 +3157,10 @@ static int lancer_fw_download(struct be_adapter *adapter,  		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); - +						 chunk_size, offset, +						 LANCER_FW_DOWNLOAD_LOCATION, +						 &data_written, &change_status, +						 &add_status);  		if (status)  			break; @@ -3093,8 +3172,10 @@ static int lancer_fw_download(struct be_adapter *adapter,  	if (!status) {  		/* Commit the FW written */  		status = lancer_cmd_write_object(adapter, &flash_cmd, -					0, offset, LANCER_FW_DOWNLOAD_LOCATION, -					&data_written, &add_status); +						 0, offset, +						 LANCER_FW_DOWNLOAD_LOCATION, +						 &data_written, &change_status, +						 &add_status);  	}  	dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va, @@ -3107,6 +3188,20 @@ static int lancer_fw_download(struct be_adapter *adapter,  		goto lancer_fw_exit;  	} +	if (change_status == LANCER_FW_RESET_NEEDED) { +		status = lancer_fw_reset(adapter); +		if (status) { +			dev_err(&adapter->pdev->dev, +				"Adapter busy for FW reset.\n" +				"New FW will not be active.\n"); +			goto lancer_fw_exit; +		} +	} else if (change_status != LANCER_NO_RESET_NEEDED) { +			dev_err(&adapter->pdev->dev, +				"System reboot required for new FW" +				" to be active\n"); +	} +  	dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");  lancer_fw_exit:  	return status; @@ -3435,10 +3530,15 @@ static void __devexit be_remove(struct pci_dev *pdev)  	be_roce_dev_remove(adapter); +	cancel_delayed_work_sync(&adapter->func_recovery_work); +  	unregister_netdev(adapter->netdev);  	be_clear(adapter); +	/* tell fw we're done with firing cmds */ +	be_cmd_fw_clean(adapter); +  	be_stats_cleanup(adapter);  	be_ctrl_cleanup(adapter); @@ -3530,6 +3630,9 @@ static int be_get_initial_config(struct be_adapter *adapter)  	if (be_is_wol_supported(adapter))  		adapter->wol = true; +	/* Must be a power of 2 or else MODULO will BUG_ON */ +	adapter->be_get_temp_freq = 64; +  	level = be_get_fw_log_level(adapter);  	adapter->msg_enable = level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0; @@ -3585,101 +3688,68 @@ static int be_dev_type_check(struct be_adapter *adapter)  	return 0;  } -static int lancer_wait_ready(struct be_adapter *adapter) +static int lancer_recover_func(struct be_adapter *adapter)  { -#define SLIPORT_READY_TIMEOUT 30 -	u32 sliport_status; -	int status = 0, i; +	int status; -	for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) { -		sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); -		if (sliport_status & SLIPORT_STATUS_RDY_MASK) -			break; +	status = lancer_test_and_set_rdy_state(adapter); +	if (status) +		goto err; -		msleep(1000); -	} +	if (netif_running(adapter->netdev)) +		be_close(adapter->netdev); -	if (i == SLIPORT_READY_TIMEOUT) -		status = -1; +	be_clear(adapter); -	return status; -} +	adapter->hw_error = false; +	adapter->fw_timeout = false; -static int lancer_test_and_set_rdy_state(struct be_adapter *adapter) -{ -	int status; -	u32 sliport_status, err, reset_needed; -	status = lancer_wait_ready(adapter); -	if (!status) { -		sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); -		err = sliport_status & SLIPORT_STATUS_ERR_MASK; -		reset_needed = sliport_status & SLIPORT_STATUS_RN_MASK; -		if (err && reset_needed) { -			iowrite32(SLI_PORT_CONTROL_IP_MASK, -					adapter->db + SLIPORT_CONTROL_OFFSET); +	status = be_setup(adapter); +	if (status) +		goto err; -			/* check adapter has corrected the error */ -			status = lancer_wait_ready(adapter); -			sliport_status = ioread32(adapter->db + -							SLIPORT_STATUS_OFFSET); -			sliport_status &= (SLIPORT_STATUS_ERR_MASK | -						SLIPORT_STATUS_RN_MASK); -			if (status || sliport_status) -				status = -1; -		} else if (err || reset_needed) { -			status = -1; -		} +	if (netif_running(adapter->netdev)) { +		status = be_open(adapter->netdev); +		if (status) +			goto err;  	} + +	dev_err(&adapter->pdev->dev, +		"Adapter SLIPORT recovery succeeded\n"); +	return 0; +err: +	dev_err(&adapter->pdev->dev, +		"Adapter SLIPORT recovery failed\n"); +  	return status;  } -static void lancer_test_and_recover_fn_err(struct be_adapter *adapter) +static void be_func_recovery_task(struct work_struct *work)  { +	struct be_adapter *adapter = +		container_of(work, struct be_adapter,  func_recovery_work.work);  	int status; -	u32 sliport_status; - -	if (adapter->eeh_err || adapter->ue_detected) -		return; -	sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); +	be_detect_error(adapter); -	if (sliport_status & SLIPORT_STATUS_ERR_MASK) { -		dev_err(&adapter->pdev->dev, -				"Adapter in error state." -				"Trying to recover.\n"); +	if (adapter->hw_error && lancer_chip(adapter)) { -		status = lancer_test_and_set_rdy_state(adapter); -		if (status) -			goto err; +		if (adapter->eeh_error) +			goto out; +		rtnl_lock();  		netif_device_detach(adapter->netdev); +		rtnl_unlock(); -		if (netif_running(adapter->netdev)) -			be_close(adapter->netdev); - -		be_clear(adapter); - -		adapter->fw_timeout = false; - -		status = be_setup(adapter); -		if (status) -			goto err; - -		if (netif_running(adapter->netdev)) { -			status = be_open(adapter->netdev); -			if (status) -				goto err; -		} - -		netif_device_attach(adapter->netdev); +		status = lancer_recover_func(adapter); -		dev_err(&adapter->pdev->dev, -				"Adapter error recovery succeeded\n"); +		if (!status) +			netif_device_attach(adapter->netdev);  	} -	return; -err: -	dev_err(&adapter->pdev->dev, -			"Adapter error recovery failed\n"); + +out: +	schedule_delayed_work(&adapter->func_recovery_work, +			      msecs_to_jiffies(1000));  }  static void be_worker(struct work_struct *work) @@ -3690,11 +3760,6 @@ static void be_worker(struct work_struct *work)  	struct be_eq_obj *eqo;  	int i; -	if (lancer_chip(adapter)) -		lancer_test_and_recover_fn_err(adapter); - -	be_detect_dump_ue(adapter); -  	/* when interrupts are not yet enabled, just reap any pending  	* mcc completions */  	if (!netif_running(adapter->netdev)) { @@ -3710,6 +3775,9 @@ static void be_worker(struct work_struct *work)  			be_cmd_get_stats(adapter, &adapter->stats_cmd);  	} +	if (MODULO(adapter->work_counter, adapter->be_get_temp_freq) == 0) +		be_cmd_get_die_temperature(adapter); +  	for_all_rx_queues(adapter, rxo, i) {  		if (rxo->rx_post_starved) {  			rxo->rx_post_starved = false; @@ -3727,10 +3795,7 @@ reschedule:  static bool be_reset_required(struct be_adapter *adapter)  { -	u32 reg; - -	pci_read_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, ®); -	return reg; +	return be_find_vfs(adapter, ENABLED) > 0 ? false : true;  }  static int __devinit be_probe(struct pci_dev *pdev, @@ -3739,6 +3804,7 @@ static int __devinit be_probe(struct pci_dev *pdev,  	int status = 0;  	struct be_adapter *adapter;  	struct net_device *netdev; +	char port_name;  	status = pci_enable_device(pdev);  	if (status) @@ -3749,7 +3815,7 @@ static int __devinit be_probe(struct pci_dev *pdev,  		goto disable_dev;  	pci_set_master(pdev); -	netdev = alloc_etherdev_mq(sizeof(struct be_adapter), MAX_TX_QS); +	netdev = alloc_etherdev_mqs(sizeof(*adapter), MAX_TX_QS, MAX_RX_QS);  	if (netdev == NULL) {  		status = -ENOMEM;  		goto rel_reg; @@ -3780,22 +3846,9 @@ static int __devinit be_probe(struct pci_dev *pdev,  	if (status)  		goto free_netdev; -	if (lancer_chip(adapter)) { -		status = lancer_wait_ready(adapter); -		if (!status) { -			iowrite32(SLI_PORT_CONTROL_IP_MASK, -					adapter->db + SLIPORT_CONTROL_OFFSET); -			status = lancer_test_and_set_rdy_state(adapter); -		} -		if (status) { -			dev_err(&pdev->dev, "Adapter in non recoverable error\n"); -			goto ctrl_clean; -		} -	} -  	/* sync up with fw's ready state */  	if (be_physfn(adapter)) { -		status = be_cmd_POST(adapter); +		status = be_fw_wait_ready(adapter);  		if (status)  			goto ctrl_clean;  	} @@ -3826,6 +3879,7 @@ static int __devinit be_probe(struct pci_dev *pdev,  		goto stats_clean;  	INIT_DELAYED_WORK(&adapter->work, be_worker); +	INIT_DELAYED_WORK(&adapter->func_recovery_work, be_func_recovery_task);  	adapter->rx_fc = adapter->tx_fc = true;  	status = be_setup(adapter); @@ -3839,8 +3893,13 @@ static int __devinit be_probe(struct pci_dev *pdev,  	be_roce_dev_add(adapter); -	dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev), -		adapter->port_num); +	schedule_delayed_work(&adapter->func_recovery_work, +			      msecs_to_jiffies(1000)); + +	be_cmd_query_port_name(adapter, &port_name); + +	dev_info(&pdev->dev, "%s: %s port %c\n", netdev->name, nic_name(pdev), +		 port_name);  	return 0; @@ -3872,6 +3931,8 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)  	if (adapter->wol)  		be_setup_wol(adapter, true); +	cancel_delayed_work_sync(&adapter->func_recovery_work); +  	netif_device_detach(netdev);  	if (netif_running(netdev)) {  		rtnl_lock(); @@ -3912,6 +3973,9 @@ static int be_resume(struct pci_dev *pdev)  		be_open(netdev);  		rtnl_unlock();  	} + +	schedule_delayed_work(&adapter->func_recovery_work, +			      msecs_to_jiffies(1000));  	netif_device_attach(netdev);  	if (adapter->wol) @@ -3931,6 +3995,7 @@ static void be_shutdown(struct pci_dev *pdev)  		return;  	cancel_delayed_work_sync(&adapter->work); +	cancel_delayed_work_sync(&adapter->func_recovery_work);  	netif_device_detach(adapter->netdev); @@ -3950,9 +4015,13 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev,  	dev_err(&adapter->pdev->dev, "EEH error detected\n"); -	adapter->eeh_err = true; +	adapter->eeh_error = true; +	cancel_delayed_work_sync(&adapter->func_recovery_work); + +	rtnl_lock();  	netif_device_detach(netdev); +	rtnl_unlock();  	if (netif_running(netdev)) {  		rtnl_lock(); @@ -3980,9 +4049,7 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)  	int status;  	dev_info(&adapter->pdev->dev, "EEH reset\n"); -	adapter->eeh_err = false; -	adapter->ue_detected = false; -	adapter->fw_timeout = false; +	be_clear_all_error(adapter);  	status = pci_enable_device(pdev);  	if (status) @@ -3993,7 +4060,7 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)  	pci_restore_state(pdev);  	/* Check if card is ok and fw is ready */ -	status = be_cmd_POST(adapter); +	status = be_fw_wait_ready(adapter);  	if (status)  		return PCI_ERS_RESULT_DISCONNECT; @@ -4015,6 +4082,10 @@ static void be_eeh_resume(struct pci_dev *pdev)  	if (status)  		goto err; +	status = be_cmd_reset_function(adapter); +	if (status) +		goto err; +  	status = be_setup(adapter);  	if (status)  		goto err; @@ -4024,6 +4095,9 @@ static void be_eeh_resume(struct pci_dev *pdev)  		if (status)  			goto err;  	} + +	schedule_delayed_work(&adapter->func_recovery_work, +			      msecs_to_jiffies(1000));  	netif_device_attach(netdev);  	return;  err:  |