diff options
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice.h | 21 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_lib.c | 75 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_main.c | 116 | 
3 files changed, 148 insertions, 64 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 9cce4cb91401..fc6bc1233f10 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -172,7 +172,8 @@ struct ice_vsi {  	u32 rx_buf_failed;  	u32 rx_page_failed;  	int num_q_vectors; -	int base_vector; +	int sw_base_vector;		/* Irq base for OS reserved vectors */ +	int hw_base_vector;		/* HW (absolute) index of a vector */  	enum ice_vsi_type type;  	u16 vsi_num;			 /* HW (absolute) index of this VSI */  	u16 idx;			 /* software index in pf->vsi[] */ @@ -240,8 +241,14 @@ enum ice_pf_flags {  struct ice_pf {  	struct pci_dev *pdev; + +	/* OS reserved IRQ details */  	struct msix_entry *msix_entries; -	struct ice_res_tracker *irq_tracker; +	struct ice_res_tracker *sw_irq_tracker; + +	/* HW reserved Interrupts for this PF */ +	struct ice_res_tracker *hw_irq_tracker; +  	struct ice_vsi **vsi;		/* VSIs created by the driver */  	struct ice_sw *first_sw;	/* first switch created by firmware */  	DECLARE_BITMAP(state, __ICE_STATE_NBITS); @@ -256,9 +263,11 @@ struct ice_pf {  	struct mutex sw_mutex;		/* lock for protecting VSI alloc flow */  	u32 msg_enable;  	u32 hw_csum_rx_error; -	u32 oicr_idx;		/* Other interrupt cause vector index */ +	u32 sw_oicr_idx;	/* Other interrupt cause SW vector index */ +	u32 num_avail_sw_msix;	/* remaining MSIX SW vectors left unclaimed */ +	u32 hw_oicr_idx;	/* Other interrupt cause vector HW index */ +	u32 num_avail_hw_msix;	/* remaining HW MSIX vectors left unclaimed */  	u32 num_lan_msix;	/* Total MSIX vectors for base driver */ -	u32 num_avail_msix;	/* remaining MSIX vectors left unclaimed */  	u16 num_lan_tx;		/* num lan tx queues setup */  	u16 num_lan_rx;		/* num lan rx queues setup */  	u16 q_left_tx;		/* remaining num tx queues left unclaimed */ @@ -293,8 +302,8 @@ struct ice_netdev_priv {  static inline void ice_irq_dynamic_ena(struct ice_hw *hw, struct ice_vsi *vsi,  				       struct ice_q_vector *q_vector)  { -	u32 vector = (vsi && q_vector) ? vsi->base_vector + q_vector->v_idx : -					((struct ice_pf *)hw->back)->oicr_idx; +	u32 vector = (vsi && q_vector) ? vsi->hw_base_vector + q_vector->v_idx : +				((struct ice_pf *)hw->back)->hw_oicr_idx;  	int itr = ICE_ITR_NONE;  	u32 val; diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index a4dfdf35ceab..8f7ee77cb70b 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1039,9 +1039,9 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)  	struct ice_pf *pf = vsi->back;  	int num_q_vectors = 0; -	if (vsi->base_vector) { -		dev_dbg(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n", -			vsi->vsi_num, vsi->base_vector); +	if (vsi->sw_base_vector || vsi->hw_base_vector) { +		dev_dbg(&pf->pdev->dev, "VSI %d has non-zero HW base vector %d or SW base vector %d\n", +			vsi->vsi_num, vsi->hw_base_vector, vsi->sw_base_vector);  		return -EEXIST;  	} @@ -1051,6 +1051,21 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)  	switch (vsi->type) {  	case ICE_VSI_PF:  		num_q_vectors = vsi->num_q_vectors; +		/* reserve slots from OS requested IRQs */ +		vsi->sw_base_vector = ice_get_res(pf, pf->sw_irq_tracker, +						  num_q_vectors, vsi->idx); +		if (vsi->sw_base_vector < 0) { +			dev_err(&pf->pdev->dev, +				"Failed to get tracking for %d SW vectors for VSI %d, err=%d\n", +				num_q_vectors, vsi->vsi_num, +				vsi->sw_base_vector); +			return -ENOENT; +		} +		pf->num_avail_sw_msix -= num_q_vectors; + +		/* reserve slots from HW interrupts */ +		vsi->hw_base_vector = ice_get_res(pf, pf->hw_irq_tracker, +						  num_q_vectors, vsi->idx);  		break;  	default:  		dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", @@ -1058,17 +1073,18 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)  		break;  	} -	if (num_q_vectors) -		vsi->base_vector = ice_get_res(pf, pf->irq_tracker, -					       num_q_vectors, vsi->idx); - -	if (vsi->base_vector < 0) { +	if (vsi->hw_base_vector < 0) {  		dev_err(&pf->pdev->dev, -			"Failed to get tracking for %d vectors for VSI %d, err=%d\n", -			num_q_vectors, vsi->vsi_num, vsi->base_vector); +			"Failed to get tracking for %d HW vectors for VSI %d, err=%d\n", +			num_q_vectors, vsi->vsi_num, vsi->hw_base_vector); +		ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, +			     vsi->idx); +		pf->num_avail_sw_msix += num_q_vectors;  		return -ENOENT;  	} +	pf->num_avail_hw_msix -= num_q_vectors; +  	return 0;  } @@ -1554,7 +1570,7 @@ err_cfg_txqs:  void ice_vsi_cfg_msix(struct ice_vsi *vsi)  {  	struct ice_pf *pf = vsi->back; -	u16 vector = vsi->base_vector; +	u16 vector = vsi->hw_base_vector;  	struct ice_hw *hw = &pf->hw;  	u32 txq = 0, rxq = 0;  	int i, q, itr; @@ -1762,7 +1778,7 @@ int ice_vsi_stop_tx_rings(struct ice_vsi *vsi)  		 * the queue to schedule NAPI handler  		 */  		v_idx = vsi->tx_rings[i]->q_vector->v_idx; -		wr32(hw, GLINT_DYN_CTL(vsi->base_vector + v_idx), +		wr32(hw, GLINT_DYN_CTL(vsi->hw_base_vector + v_idx),  		     GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M);  	}  	status = ice_dis_vsi_txq(vsi->port_info, vsi->num_txq, q_ids, q_teids, @@ -1939,7 +1955,12 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,  	return vsi;  unroll_vector_base: -	ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); +	/* reclaim SW interrupts back to the common pool */ +	ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); +	pf->num_avail_sw_msix += vsi->num_q_vectors; +	/* reclaim HW interrupt back to the common pool */ +	ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); +	pf->num_avail_hw_msix += vsi->num_q_vectors;  unroll_alloc_q_vector:  	ice_vsi_free_q_vectors(vsi);  unroll_vsi_init: @@ -1960,7 +1981,7 @@ unroll_get_qs:  static void ice_vsi_release_msix(struct ice_vsi *vsi)  {  	struct ice_pf *pf = vsi->back; -	u16 vector = vsi->base_vector; +	u16 vector = vsi->hw_base_vector;  	struct ice_hw *hw = &pf->hw;  	u32 txq = 0;  	u32 rxq = 0; @@ -1992,7 +2013,7 @@ static void ice_vsi_release_msix(struct ice_vsi *vsi)  void ice_vsi_free_irq(struct ice_vsi *vsi)  {  	struct ice_pf *pf = vsi->back; -	int base = vsi->base_vector; +	int base = vsi->sw_base_vector;  	if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {  		int i; @@ -2000,6 +2021,8 @@ void ice_vsi_free_irq(struct ice_vsi *vsi)  		if (!vsi->q_vectors || !vsi->irqs_ready)  			return; +		ice_vsi_release_msix(vsi); +  		vsi->irqs_ready = false;  		for (i = 0; i < vsi->num_q_vectors; i++) {  			u16 vector = i + base; @@ -2022,7 +2045,6 @@ void ice_vsi_free_irq(struct ice_vsi *vsi)  			devm_free_irq(&pf->pdev->dev, irq_num,  				      vsi->q_vectors[i]);  		} -		ice_vsi_release_msix(vsi);  	}  } @@ -2110,6 +2132,9 @@ static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id)  	int start = res->search_hint;  	int end = start; +	if ((start + needed) >  res->num_entries) +		return -ENOMEM; +  	id |= ICE_RES_VALID_BIT;  	do { @@ -2183,9 +2208,9 @@ ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id)   */  void ice_vsi_dis_irq(struct ice_vsi *vsi)  { +	int base = vsi->sw_base_vector;  	struct ice_pf *pf = vsi->back;  	struct ice_hw *hw = &pf->hw; -	int base = vsi->base_vector;  	u32 val;  	int i; @@ -2218,8 +2243,8 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi)  	/* disable each interrupt */  	if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { -		for (i = vsi->base_vector; -		     i < (vsi->num_q_vectors + vsi->base_vector); i++) +		for (i = vsi->hw_base_vector; +		     i < (vsi->num_q_vectors + vsi->hw_base_vector); i++)  			wr32(hw, GLINT_DYN_CTL(i), 0);  		ice_flush(hw); @@ -2262,8 +2287,10 @@ int ice_vsi_release(struct ice_vsi *vsi)  	ice_vsi_close(vsi);  	/* reclaim interrupt vectors back to PF */ -	ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); -	pf->num_avail_msix += vsi->num_q_vectors; +	ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); +	pf->num_avail_sw_msix += vsi->num_q_vectors; +	ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); +	pf->num_avail_hw_msix += vsi->num_q_vectors;  	ice_remove_vsi_fltr(&pf->hw, vsi->idx);  	ice_vsi_delete(vsi); @@ -2299,8 +2326,10 @@ int ice_vsi_rebuild(struct ice_vsi *vsi)  		return -EINVAL;  	ice_vsi_free_q_vectors(vsi); -	ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); -	vsi->base_vector = 0; +	ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); +	ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); +	vsi->sw_base_vector = 0; +	vsi->hw_base_vector = 0;  	ice_vsi_clear_rings(vsi);  	ice_vsi_free_arrays(vsi, false);  	ice_vsi_set_num_qs(vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index bb42ee643b77..d9f30d15ad65 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -95,7 +95,7 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf)  				/* Trigger sw interrupt to revive the queue */  				v_idx = tx_ring->q_vector->v_idx;  				wr32(&vsi->back->hw, -				     GLINT_DYN_CTL(vsi->base_vector + v_idx), +				     GLINT_DYN_CTL(vsi->hw_base_vector + v_idx),  				     (itr << GLINT_DYN_CTL_ITR_INDX_S) |  				     GLINT_DYN_CTL_SWINT_TRIG_M |  				     GLINT_DYN_CTL_INTENA_MSK_M); @@ -1122,7 +1122,7 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename)  {  	int q_vectors = vsi->num_q_vectors;  	struct ice_pf *pf = vsi->back; -	int base = vsi->base_vector; +	int base = vsi->sw_base_vector;  	int rx_int_idx = 0;  	int tx_int_idx = 0;  	int vector, err; @@ -1203,7 +1203,7 @@ static void ice_ena_misc_vector(struct ice_pf *pf)  	wr32(hw, PFINT_OICR_ENA, val);  	/* SW_ITR_IDX = 0, but don't change INTENA */ -	wr32(hw, GLINT_DYN_CTL(pf->oicr_idx), +	wr32(hw, GLINT_DYN_CTL(pf->hw_oicr_idx),  	     GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M);  } @@ -1321,12 +1321,15 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf)  	ice_flush(&pf->hw);  	if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags) && pf->msix_entries) { -		synchronize_irq(pf->msix_entries[pf->oicr_idx].vector); +		synchronize_irq(pf->msix_entries[pf->sw_oicr_idx].vector);  		devm_free_irq(&pf->pdev->dev, -			      pf->msix_entries[pf->oicr_idx].vector, pf); +			      pf->msix_entries[pf->sw_oicr_idx].vector, pf);  	} -	ice_free_res(pf->irq_tracker, pf->oicr_idx, ICE_RES_MISC_VEC_ID); +	pf->num_avail_sw_msix += 1; +	ice_free_res(pf->sw_irq_tracker, pf->sw_oicr_idx, ICE_RES_MISC_VEC_ID); +	pf->num_avail_hw_msix += 1; +	ice_free_res(pf->hw_irq_tracker, pf->hw_oicr_idx, ICE_RES_MISC_VEC_ID);  }  /** @@ -1356,39 +1359,53 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)  	if (ice_is_reset_in_progress(pf->state))  		goto skip_req_irq; -	/* reserve one vector in irq_tracker for misc interrupts */ -	oicr_idx = ice_get_res(pf, pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID); +	/* reserve one vector in sw_irq_tracker for misc interrupts */ +	oicr_idx = ice_get_res(pf, pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);  	if (oicr_idx < 0)  		return oicr_idx; -	pf->oicr_idx = oicr_idx; +	pf->num_avail_sw_msix -= 1; +	pf->sw_oicr_idx = oicr_idx; + +	/* reserve one vector in hw_irq_tracker for misc interrupts */ +	oicr_idx = ice_get_res(pf, pf->hw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); +	if (oicr_idx < 0) { +		ice_free_res(pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); +		pf->num_avail_sw_msix += 1; +		return oicr_idx; +	} +	pf->num_avail_hw_msix -= 1; +	pf->hw_oicr_idx = oicr_idx;  	err = devm_request_irq(&pf->pdev->dev, -			       pf->msix_entries[pf->oicr_idx].vector, +			       pf->msix_entries[pf->sw_oicr_idx].vector,  			       ice_misc_intr, 0, pf->int_name, pf);  	if (err) {  		dev_err(&pf->pdev->dev,  			"devm_request_irq for %s failed: %d\n",  			pf->int_name, err); -		ice_free_res(pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID); +		ice_free_res(pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); +		pf->num_avail_sw_msix += 1; +		ice_free_res(pf->hw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); +		pf->num_avail_hw_msix += 1;  		return err;  	}  skip_req_irq:  	ice_ena_misc_vector(pf); -	val = ((pf->oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) | +	val = ((pf->hw_oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) |  	       PFINT_OICR_CTL_CAUSE_ENA_M);  	wr32(hw, PFINT_OICR_CTL, val);  	/* This enables Admin queue Interrupt causes */ -	val = ((pf->oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) | +	val = ((pf->hw_oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) |  	       PFINT_FW_CTL_CAUSE_ENA_M);  	wr32(hw, PFINT_FW_CTL, val);  	itr_gran = hw->itr_gran_200; -	wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_idx), +	wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->hw_oicr_idx),  	     ITR_TO_REG(ICE_ITR_8K, itr_gran));  	ice_flush(hw); @@ -1797,6 +1814,7 @@ static int ice_ena_msix_range(struct ice_pf *pf)  	/* reserve vectors for LAN traffic */  	pf->num_lan_msix = min_t(int, num_online_cpus(), v_left);  	v_budget += pf->num_lan_msix; +	v_left -= pf->num_lan_msix;  	pf->msix_entries = devm_kcalloc(&pf->pdev->dev, v_budget,  					sizeof(struct msix_entry), GFP_KERNEL); @@ -1824,10 +1842,11 @@ static int ice_ena_msix_range(struct ice_pf *pf)  			 "not enough vectors. requested = %d, obtained = %d\n",  			 v_budget, v_actual);  		if (v_actual >= (pf->num_lan_msix + 1)) { -			pf->num_avail_msix = v_actual - (pf->num_lan_msix + 1); +			pf->num_avail_sw_msix = v_actual - +						(pf->num_lan_msix + 1);  		} else if (v_actual >= 2) {  			pf->num_lan_msix = 1; -			pf->num_avail_msix = v_actual - 2; +			pf->num_avail_sw_msix = v_actual - 2;  		} else {  			pci_disable_msix(pf->pdev);  			err = -ERANGE; @@ -1860,12 +1879,32 @@ static void ice_dis_msix(struct ice_pf *pf)  }  /** + * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme + * @pf: board private structure + */ +static void ice_clear_interrupt_scheme(struct ice_pf *pf) +{ +	if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) +		ice_dis_msix(pf); + +	if (pf->sw_irq_tracker) { +		devm_kfree(&pf->pdev->dev, pf->sw_irq_tracker); +		pf->sw_irq_tracker = NULL; +	} + +	if (pf->hw_irq_tracker) { +		devm_kfree(&pf->pdev->dev, pf->hw_irq_tracker); +		pf->hw_irq_tracker = NULL; +	} +} + +/**   * ice_init_interrupt_scheme - Determine proper interrupt scheme   * @pf: board private structure to initialize   */  static int ice_init_interrupt_scheme(struct ice_pf *pf)  { -	int vectors = 0; +	int vectors = 0, hw_vectors = 0;  	ssize_t size;  	if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) @@ -1879,30 +1918,31 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf)  	/* set up vector assignment tracking */  	size = sizeof(struct ice_res_tracker) + (sizeof(u16) * vectors); -	pf->irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL); -	if (!pf->irq_tracker) { +	pf->sw_irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL); +	if (!pf->sw_irq_tracker) {  		ice_dis_msix(pf);  		return -ENOMEM;  	} -	pf->irq_tracker->num_entries = vectors; +	/* populate SW interrupts pool with number of OS granted IRQs. */ +	pf->num_avail_sw_msix = vectors; +	pf->sw_irq_tracker->num_entries = vectors; -	return 0; -} +	/* set up HW vector assignment tracking */ +	hw_vectors = pf->hw.func_caps.common_cap.num_msix_vectors; +	size = sizeof(struct ice_res_tracker) + (sizeof(u16) * hw_vectors); -/** - * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme - * @pf: board private structure - */ -static void ice_clear_interrupt_scheme(struct ice_pf *pf) -{ -	if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) -		ice_dis_msix(pf); - -	if (pf->irq_tracker) { -		devm_kfree(&pf->pdev->dev, pf->irq_tracker); -		pf->irq_tracker = NULL; +	pf->hw_irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL); +	if (!pf->hw_irq_tracker) { +		ice_clear_interrupt_scheme(pf); +		return -ENOMEM;  	} + +	/* populate HW interrupts pool with number of HW supported irqs. */ +	pf->num_avail_hw_msix = hw_vectors; +	pf->hw_irq_tracker->num_entries = hw_vectors; + +	return 0;  }  /** @@ -3213,6 +3253,12 @@ static void ice_rebuild(struct ice_pf *pf)  	if (err)  		goto err_sched_init_port; +	/* reset search_hint of irq_trackers to 0 since interrupts are +	 * reclaimed and could be allocated from beginning during VSI rebuild +	 */ +	pf->sw_irq_tracker->search_hint = 0; +	pf->hw_irq_tracker->search_hint = 0; +  	err = ice_vsi_rebuild_all(pf);  	if (err) {  		dev_err(dev, "ice_vsi_rebuild_all failed\n"); @@ -3610,7 +3656,7 @@ static void ice_tx_timeout(struct net_device *netdev)  		if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))  			val = rd32(&pf->hw,  				   GLINT_DYN_CTL(tx_ring->q_vector->v_idx + -						tx_ring->vsi->base_vector - 1)); +					tx_ring->vsi->hw_base_vector));  		netdev_info(netdev, "tx_timeout: VSI_num: %d, Q %d, NTC: 0x%x, HWB: 0x%x, NTU: 0x%x, TAIL: 0x%x, INT: 0x%x\n",  			    vsi->vsi_num, hung_queue, tx_ring->next_to_clean,  | 
