diff options
Diffstat (limited to 'drivers/net/ethernet/intel/iavf/iavf_virtchnl.c')
| -rw-r--r-- | drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 360 | 
1 files changed, 358 insertions, 2 deletions
| diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index 647e7fde11b4..0eab3c43bdc5 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -140,6 +140,9 @@ int iavf_send_vf_config_msg(struct iavf_adapter *adapter)  	       VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM |  	       VIRTCHNL_VF_OFFLOAD_REQ_QUEUES |  	       VIRTCHNL_VF_OFFLOAD_ADQ | +	       VIRTCHNL_VF_OFFLOAD_USO | +	       VIRTCHNL_VF_OFFLOAD_FDIR_PF | +	       VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF |  	       VIRTCHNL_VF_CAP_ADV_LINK_SPEED;  	adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES; @@ -1005,7 +1008,7 @@ iavf_set_adapter_link_speed_from_vpe(struct iavf_adapter *adapter,  }  /** - * iavf_enable_channel + * iavf_enable_channels   * @adapter: adapter structure   *   * Request that the PF enable channels as specified by @@ -1046,7 +1049,7 @@ void iavf_enable_channels(struct iavf_adapter *adapter)  }  /** - * iavf_disable_channel + * iavf_disable_channels   * @adapter: adapter structure   *   * Request that the PF disable channels that are configured @@ -1198,6 +1201,200 @@ void iavf_del_cloud_filter(struct iavf_adapter *adapter)  }  /** + * iavf_add_fdir_filter + * @adapter: the VF adapter structure + * + * Request that the PF add Flow Director filters as specified + * by the user via ethtool. + **/ +void iavf_add_fdir_filter(struct iavf_adapter *adapter) +{ +	struct iavf_fdir_fltr *fdir; +	struct virtchnl_fdir_add *f; +	bool process_fltr = false; +	int len; + +	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { +		/* bail because we already have a command pending */ +		dev_err(&adapter->pdev->dev, "Cannot add Flow Director filter, command %d pending\n", +			adapter->current_op); +		return; +	} + +	len = sizeof(struct virtchnl_fdir_add); +	f = kzalloc(len, GFP_KERNEL); +	if (!f) +		return; + +	spin_lock_bh(&adapter->fdir_fltr_lock); +	list_for_each_entry(fdir, &adapter->fdir_list_head, list) { +		if (fdir->state == IAVF_FDIR_FLTR_ADD_REQUEST) { +			process_fltr = true; +			fdir->state = IAVF_FDIR_FLTR_ADD_PENDING; +			memcpy(f, &fdir->vc_add_msg, len); +			break; +		} +	} +	spin_unlock_bh(&adapter->fdir_fltr_lock); + +	if (!process_fltr) { +		/* prevent iavf_add_fdir_filter() from being called when there +		 * are no filters to add +		 */ +		adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_FDIR_FILTER; +		kfree(f); +		return; +	} +	adapter->current_op = VIRTCHNL_OP_ADD_FDIR_FILTER; +	iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_FDIR_FILTER, (u8 *)f, len); +	kfree(f); +} + +/** + * iavf_del_fdir_filter + * @adapter: the VF adapter structure + * + * Request that the PF delete Flow Director filters as specified + * by the user via ethtool. + **/ +void iavf_del_fdir_filter(struct iavf_adapter *adapter) +{ +	struct iavf_fdir_fltr *fdir; +	struct virtchnl_fdir_del f; +	bool process_fltr = false; +	int len; + +	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { +		/* bail because we already have a command pending */ +		dev_err(&adapter->pdev->dev, "Cannot remove Flow Director filter, command %d pending\n", +			adapter->current_op); +		return; +	} + +	len = sizeof(struct virtchnl_fdir_del); + +	spin_lock_bh(&adapter->fdir_fltr_lock); +	list_for_each_entry(fdir, &adapter->fdir_list_head, list) { +		if (fdir->state == IAVF_FDIR_FLTR_DEL_REQUEST) { +			process_fltr = true; +			memset(&f, 0, len); +			f.vsi_id = fdir->vc_add_msg.vsi_id; +			f.flow_id = fdir->flow_id; +			fdir->state = IAVF_FDIR_FLTR_DEL_PENDING; +			break; +		} +	} +	spin_unlock_bh(&adapter->fdir_fltr_lock); + +	if (!process_fltr) { +		adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_FDIR_FILTER; +		return; +	} + +	adapter->current_op = VIRTCHNL_OP_DEL_FDIR_FILTER; +	iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_FDIR_FILTER, (u8 *)&f, len); +} + +/** + * iavf_add_adv_rss_cfg + * @adapter: the VF adapter structure + * + * Request that the PF add RSS configuration as specified + * by the user via ethtool. + **/ +void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter) +{ +	struct virtchnl_rss_cfg *rss_cfg; +	struct iavf_adv_rss *rss; +	bool process_rss = false; +	int len; + +	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { +		/* bail because we already have a command pending */ +		dev_err(&adapter->pdev->dev, "Cannot add RSS configuration, command %d pending\n", +			adapter->current_op); +		return; +	} + +	len = sizeof(struct virtchnl_rss_cfg); +	rss_cfg = kzalloc(len, GFP_KERNEL); +	if (!rss_cfg) +		return; + +	spin_lock_bh(&adapter->adv_rss_lock); +	list_for_each_entry(rss, &adapter->adv_rss_list_head, list) { +		if (rss->state == IAVF_ADV_RSS_ADD_REQUEST) { +			process_rss = true; +			rss->state = IAVF_ADV_RSS_ADD_PENDING; +			memcpy(rss_cfg, &rss->cfg_msg, len); +			iavf_print_adv_rss_cfg(adapter, rss, +					       "Input set change for", +					       "is pending"); +			break; +		} +	} +	spin_unlock_bh(&adapter->adv_rss_lock); + +	if (process_rss) { +		adapter->current_op = VIRTCHNL_OP_ADD_RSS_CFG; +		iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_RSS_CFG, +				 (u8 *)rss_cfg, len); +	} else { +		adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_ADV_RSS_CFG; +	} + +	kfree(rss_cfg); +} + +/** + * iavf_del_adv_rss_cfg + * @adapter: the VF adapter structure + * + * Request that the PF delete RSS configuration as specified + * by the user via ethtool. + **/ +void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter) +{ +	struct virtchnl_rss_cfg *rss_cfg; +	struct iavf_adv_rss *rss; +	bool process_rss = false; +	int len; + +	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { +		/* bail because we already have a command pending */ +		dev_err(&adapter->pdev->dev, "Cannot remove RSS configuration, command %d pending\n", +			adapter->current_op); +		return; +	} + +	len = sizeof(struct virtchnl_rss_cfg); +	rss_cfg = kzalloc(len, GFP_KERNEL); +	if (!rss_cfg) +		return; + +	spin_lock_bh(&adapter->adv_rss_lock); +	list_for_each_entry(rss, &adapter->adv_rss_list_head, list) { +		if (rss->state == IAVF_ADV_RSS_DEL_REQUEST) { +			process_rss = true; +			rss->state = IAVF_ADV_RSS_DEL_PENDING; +			memcpy(rss_cfg, &rss->cfg_msg, len); +			break; +		} +	} +	spin_unlock_bh(&adapter->adv_rss_lock); + +	if (process_rss) { +		adapter->current_op = VIRTCHNL_OP_DEL_RSS_CFG; +		iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_RSS_CFG, +				 (u8 *)rss_cfg, len); +	} else { +		adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_ADV_RSS_CFG; +	} + +	kfree(rss_cfg); +} + +/**   * iavf_request_reset   * @adapter: adapter structure   * @@ -1357,6 +1554,84 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,  			}  			}  			break; +		case VIRTCHNL_OP_ADD_FDIR_FILTER: { +			struct iavf_fdir_fltr *fdir, *fdir_tmp; + +			spin_lock_bh(&adapter->fdir_fltr_lock); +			list_for_each_entry_safe(fdir, fdir_tmp, +						 &adapter->fdir_list_head, +						 list) { +				if (fdir->state == IAVF_FDIR_FLTR_ADD_PENDING) { +					dev_info(&adapter->pdev->dev, "Failed to add Flow Director filter, error %s\n", +						 iavf_stat_str(&adapter->hw, +							       v_retval)); +					iavf_print_fdir_fltr(adapter, fdir); +					if (msglen) +						dev_err(&adapter->pdev->dev, +							"%s\n", msg); +					list_del(&fdir->list); +					kfree(fdir); +					adapter->fdir_active_fltr--; +				} +			} +			spin_unlock_bh(&adapter->fdir_fltr_lock); +			} +			break; +		case VIRTCHNL_OP_DEL_FDIR_FILTER: { +			struct iavf_fdir_fltr *fdir; + +			spin_lock_bh(&adapter->fdir_fltr_lock); +			list_for_each_entry(fdir, &adapter->fdir_list_head, +					    list) { +				if (fdir->state == IAVF_FDIR_FLTR_DEL_PENDING) { +					fdir->state = IAVF_FDIR_FLTR_ACTIVE; +					dev_info(&adapter->pdev->dev, "Failed to del Flow Director filter, error %s\n", +						 iavf_stat_str(&adapter->hw, +							       v_retval)); +					iavf_print_fdir_fltr(adapter, fdir); +				} +			} +			spin_unlock_bh(&adapter->fdir_fltr_lock); +			} +			break; +		case VIRTCHNL_OP_ADD_RSS_CFG: { +			struct iavf_adv_rss *rss, *rss_tmp; + +			spin_lock_bh(&adapter->adv_rss_lock); +			list_for_each_entry_safe(rss, rss_tmp, +						 &adapter->adv_rss_list_head, +						 list) { +				if (rss->state == IAVF_ADV_RSS_ADD_PENDING) { +					iavf_print_adv_rss_cfg(adapter, rss, +							       "Failed to change the input set for", +							       NULL); +					list_del(&rss->list); +					kfree(rss); +				} +			} +			spin_unlock_bh(&adapter->adv_rss_lock); +			} +			break; +		case VIRTCHNL_OP_DEL_RSS_CFG: { +			struct iavf_adv_rss *rss; + +			spin_lock_bh(&adapter->adv_rss_lock); +			list_for_each_entry(rss, &adapter->adv_rss_list_head, +					    list) { +				if (rss->state == IAVF_ADV_RSS_DEL_PENDING) { +					rss->state = IAVF_ADV_RSS_ACTIVE; +					dev_err(&adapter->pdev->dev, "Failed to delete RSS configuration, error %s\n", +						iavf_stat_str(&adapter->hw, +							      v_retval)); +				} +			} +			spin_unlock_bh(&adapter->adv_rss_lock); +			} +			break; +		case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: +		case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING: +			dev_warn(&adapter->pdev->dev, "Changing VLAN Stripping is not allowed when Port VLAN is configured\n"); +			break;  		default:  			dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",  				v_retval, iavf_stat_str(&adapter->hw, v_retval), @@ -1490,6 +1765,87 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,  		}  		}  		break; +	case VIRTCHNL_OP_ADD_FDIR_FILTER: { +		struct virtchnl_fdir_add *add_fltr = (struct virtchnl_fdir_add *)msg; +		struct iavf_fdir_fltr *fdir, *fdir_tmp; + +		spin_lock_bh(&adapter->fdir_fltr_lock); +		list_for_each_entry_safe(fdir, fdir_tmp, +					 &adapter->fdir_list_head, +					 list) { +			if (fdir->state == IAVF_FDIR_FLTR_ADD_PENDING) { +				if (add_fltr->status == VIRTCHNL_FDIR_SUCCESS) { +					dev_info(&adapter->pdev->dev, "Flow Director filter with location %u is added\n", +						 fdir->loc); +					fdir->state = IAVF_FDIR_FLTR_ACTIVE; +					fdir->flow_id = add_fltr->flow_id; +				} else { +					dev_info(&adapter->pdev->dev, "Failed to add Flow Director filter with status: %d\n", +						 add_fltr->status); +					iavf_print_fdir_fltr(adapter, fdir); +					list_del(&fdir->list); +					kfree(fdir); +					adapter->fdir_active_fltr--; +				} +			} +		} +		spin_unlock_bh(&adapter->fdir_fltr_lock); +		} +		break; +	case VIRTCHNL_OP_DEL_FDIR_FILTER: { +		struct virtchnl_fdir_del *del_fltr = (struct virtchnl_fdir_del *)msg; +		struct iavf_fdir_fltr *fdir, *fdir_tmp; + +		spin_lock_bh(&adapter->fdir_fltr_lock); +		list_for_each_entry_safe(fdir, fdir_tmp, &adapter->fdir_list_head, +					 list) { +			if (fdir->state == IAVF_FDIR_FLTR_DEL_PENDING) { +				if (del_fltr->status == VIRTCHNL_FDIR_SUCCESS) { +					dev_info(&adapter->pdev->dev, "Flow Director filter with location %u is deleted\n", +						 fdir->loc); +					list_del(&fdir->list); +					kfree(fdir); +					adapter->fdir_active_fltr--; +				} else { +					fdir->state = IAVF_FDIR_FLTR_ACTIVE; +					dev_info(&adapter->pdev->dev, "Failed to delete Flow Director filter with status: %d\n", +						 del_fltr->status); +					iavf_print_fdir_fltr(adapter, fdir); +				} +			} +		} +		spin_unlock_bh(&adapter->fdir_fltr_lock); +		} +		break; +	case VIRTCHNL_OP_ADD_RSS_CFG: { +		struct iavf_adv_rss *rss; + +		spin_lock_bh(&adapter->adv_rss_lock); +		list_for_each_entry(rss, &adapter->adv_rss_list_head, list) { +			if (rss->state == IAVF_ADV_RSS_ADD_PENDING) { +				iavf_print_adv_rss_cfg(adapter, rss, +						       "Input set change for", +						       "successful"); +				rss->state = IAVF_ADV_RSS_ACTIVE; +			} +		} +		spin_unlock_bh(&adapter->adv_rss_lock); +		} +		break; +	case VIRTCHNL_OP_DEL_RSS_CFG: { +		struct iavf_adv_rss *rss, *rss_tmp; + +		spin_lock_bh(&adapter->adv_rss_lock); +		list_for_each_entry_safe(rss, rss_tmp, +					 &adapter->adv_rss_list_head, list) { +			if (rss->state == IAVF_ADV_RSS_DEL_PENDING) { +				list_del(&rss->list); +				kfree(rss); +			} +		} +		spin_unlock_bh(&adapter->adv_rss_lock); +		} +		break;  	default:  		if (adapter->current_op && (v_opcode != adapter->current_op))  			dev_warn(&adapter->pdev->dev, "Expected response %d from PF, received %d\n", | 
