mirror of
				https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
				synced 2025-10-31 16:18:51 +01:00 
			
		
		
		
	Fixed MTP to work with TWRP
This commit is contained in:
		
						commit
						f6dfaef42e
					
				
					 50820 changed files with 20846062 additions and 0 deletions
				
			
		
							
								
								
									
										36
									
								
								drivers/net/ethernet/intel/i40evf/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								drivers/net/ethernet/intel/i40evf/Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| ################################################################################
 | ||||
| #
 | ||||
| # Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
 | ||||
| # Copyright(c) 2013 - 2014 Intel Corporation.
 | ||||
| #
 | ||||
| # This program is free software; you can redistribute it and/or modify it
 | ||||
| # under the terms and conditions of the GNU General Public License,
 | ||||
| # version 2, as published by the Free Software Foundation.
 | ||||
| #
 | ||||
| # This program is distributed in the hope it will be useful, but WITHOUT
 | ||||
| # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | ||||
| # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | ||||
| # more details.
 | ||||
| #
 | ||||
| # You should have received a copy of the GNU General Public License along
 | ||||
| # with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| #
 | ||||
| # The full GNU General Public License is included in this distribution in
 | ||||
| # the file called "COPYING".
 | ||||
| #
 | ||||
| # Contact Information:
 | ||||
| # e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
 | ||||
| # Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 | ||||
| #
 | ||||
| ################################################################################
 | ||||
| 
 | ||||
| #
 | ||||
| ## Makefile for the Intel(R) 40GbE VF driver
 | ||||
| #
 | ||||
| #
 | ||||
| 
 | ||||
| obj-$(CONFIG_I40EVF) += i40evf.o | ||||
| 
 | ||||
| i40evf-objs :=	i40evf_main.o i40evf_ethtool.o i40evf_virtchnl.o \
 | ||||
| 		i40e_txrx.o i40e_common.o i40e_adminq.o | ||||
| 
 | ||||
							
								
								
									
										990
									
								
								drivers/net/ethernet/intel/i40evf/i40e_adminq.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										990
									
								
								drivers/net/ethernet/intel/i40evf/i40e_adminq.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,990 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #include "i40e_status.h" | ||||
| #include "i40e_type.h" | ||||
| #include "i40e_register.h" | ||||
| #include "i40e_adminq.h" | ||||
| #include "i40e_prototype.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * i40e_is_nvm_update_op - return true if this is an NVM update operation | ||||
|  * @desc: API request descriptor | ||||
|  **/ | ||||
| static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc) | ||||
| { | ||||
| 	return (desc->opcode == i40e_aqc_opc_nvm_erase) || | ||||
| 	       (desc->opcode == i40e_aqc_opc_nvm_update); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_adminq_init_regs - Initialize AdminQ registers | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  *  This assumes the alloc_asq and alloc_arq functions have already been called | ||||
|  **/ | ||||
| static void i40e_adminq_init_regs(struct i40e_hw *hw) | ||||
| { | ||||
| 	/* set head and tail registers in our local struct */ | ||||
| 	if (hw->mac.type == I40E_MAC_VF) { | ||||
| 		hw->aq.asq.tail = I40E_VF_ATQT1; | ||||
| 		hw->aq.asq.head = I40E_VF_ATQH1; | ||||
| 		hw->aq.asq.len  = I40E_VF_ATQLEN1; | ||||
| 		hw->aq.asq.bal  = I40E_VF_ATQBAL1; | ||||
| 		hw->aq.asq.bah  = I40E_VF_ATQBAH1; | ||||
| 		hw->aq.arq.tail = I40E_VF_ARQT1; | ||||
| 		hw->aq.arq.head = I40E_VF_ARQH1; | ||||
| 		hw->aq.arq.len  = I40E_VF_ARQLEN1; | ||||
| 		hw->aq.arq.bal  = I40E_VF_ARQBAL1; | ||||
| 		hw->aq.arq.bah  = I40E_VF_ARQBAH1; | ||||
| 	} else { | ||||
| 		hw->aq.asq.tail = I40E_PF_ATQT; | ||||
| 		hw->aq.asq.head = I40E_PF_ATQH; | ||||
| 		hw->aq.asq.len  = I40E_PF_ATQLEN; | ||||
| 		hw->aq.asq.bal  = I40E_PF_ATQBAL; | ||||
| 		hw->aq.asq.bah  = I40E_PF_ATQBAH; | ||||
| 		hw->aq.arq.tail = I40E_PF_ARQT; | ||||
| 		hw->aq.arq.head = I40E_PF_ARQH; | ||||
| 		hw->aq.arq.len  = I40E_PF_ARQLEN; | ||||
| 		hw->aq.arq.bal  = I40E_PF_ARQBAL; | ||||
| 		hw->aq.arq.bah  = I40E_PF_ARQBAH; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_alloc_adminq_asq_ring - Allocate Admin Queue send rings | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  **/ | ||||
| static i40e_status i40e_alloc_adminq_asq_ring(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code; | ||||
| 
 | ||||
| 	ret_code = i40e_allocate_dma_mem(hw, &hw->aq.asq.desc_buf, | ||||
| 					 i40e_mem_atq_ring, | ||||
| 					 (hw->aq.num_asq_entries * | ||||
| 					 sizeof(struct i40e_aq_desc)), | ||||
| 					 I40E_ADMINQ_DESC_ALIGNMENT); | ||||
| 	if (ret_code) | ||||
| 		return ret_code; | ||||
| 
 | ||||
| 	ret_code = i40e_allocate_virt_mem(hw, &hw->aq.asq.cmd_buf, | ||||
| 					  (hw->aq.num_asq_entries * | ||||
| 					  sizeof(struct i40e_asq_cmd_details))); | ||||
| 	if (ret_code) { | ||||
| 		i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf); | ||||
| 		return ret_code; | ||||
| 	} | ||||
| 
 | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_alloc_adminq_arq_ring - Allocate Admin Queue receive rings | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  **/ | ||||
| static i40e_status i40e_alloc_adminq_arq_ring(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code; | ||||
| 
 | ||||
| 	ret_code = i40e_allocate_dma_mem(hw, &hw->aq.arq.desc_buf, | ||||
| 					 i40e_mem_arq_ring, | ||||
| 					 (hw->aq.num_arq_entries * | ||||
| 					 sizeof(struct i40e_aq_desc)), | ||||
| 					 I40E_ADMINQ_DESC_ALIGNMENT); | ||||
| 
 | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_free_adminq_asq - Free Admin Queue send rings | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  *  This assumes the posted send buffers have already been cleaned | ||||
|  *  and de-allocated | ||||
|  **/ | ||||
| static void i40e_free_adminq_asq(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_free_adminq_arq - Free Admin Queue receive rings | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  *  This assumes the posted receive buffers have already been cleaned | ||||
|  *  and de-allocated | ||||
|  **/ | ||||
| static void i40e_free_adminq_arq(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_free_dma_mem(hw, &hw->aq.arq.desc_buf); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  **/ | ||||
| static i40e_status i40e_alloc_arq_bufs(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code; | ||||
| 	struct i40e_aq_desc *desc; | ||||
| 	struct i40e_dma_mem *bi; | ||||
| 	int i; | ||||
| 
 | ||||
| 	/* We'll be allocating the buffer info memory first, then we can
 | ||||
| 	 * allocate the mapped buffers for the event processing | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* buffer_info structures do not need alignment */ | ||||
| 	ret_code = i40e_allocate_virt_mem(hw, &hw->aq.arq.dma_head, | ||||
| 		(hw->aq.num_arq_entries * sizeof(struct i40e_dma_mem))); | ||||
| 	if (ret_code) | ||||
| 		goto alloc_arq_bufs; | ||||
| 	hw->aq.arq.r.arq_bi = (struct i40e_dma_mem *)hw->aq.arq.dma_head.va; | ||||
| 
 | ||||
| 	/* allocate the mapped buffers */ | ||||
| 	for (i = 0; i < hw->aq.num_arq_entries; i++) { | ||||
| 		bi = &hw->aq.arq.r.arq_bi[i]; | ||||
| 		ret_code = i40e_allocate_dma_mem(hw, bi, | ||||
| 						 i40e_mem_arq_buf, | ||||
| 						 hw->aq.arq_buf_size, | ||||
| 						 I40E_ADMINQ_DESC_ALIGNMENT); | ||||
| 		if (ret_code) | ||||
| 			goto unwind_alloc_arq_bufs; | ||||
| 
 | ||||
| 		/* now configure the descriptors for use */ | ||||
| 		desc = I40E_ADMINQ_DESC(hw->aq.arq, i); | ||||
| 
 | ||||
| 		desc->flags = cpu_to_le16(I40E_AQ_FLAG_BUF); | ||||
| 		if (hw->aq.arq_buf_size > I40E_AQ_LARGE_BUF) | ||||
| 			desc->flags |= cpu_to_le16(I40E_AQ_FLAG_LB); | ||||
| 		desc->opcode = 0; | ||||
| 		/* This is in accordance with Admin queue design, there is no
 | ||||
| 		 * register for buffer size configuration | ||||
| 		 */ | ||||
| 		desc->datalen = cpu_to_le16((u16)bi->size); | ||||
| 		desc->retval = 0; | ||||
| 		desc->cookie_high = 0; | ||||
| 		desc->cookie_low = 0; | ||||
| 		desc->params.external.addr_high = | ||||
| 			cpu_to_le32(upper_32_bits(bi->pa)); | ||||
| 		desc->params.external.addr_low = | ||||
| 			cpu_to_le32(lower_32_bits(bi->pa)); | ||||
| 		desc->params.external.param0 = 0; | ||||
| 		desc->params.external.param1 = 0; | ||||
| 	} | ||||
| 
 | ||||
| alloc_arq_bufs: | ||||
| 	return ret_code; | ||||
| 
 | ||||
| unwind_alloc_arq_bufs: | ||||
| 	/* don't try to free the one that failed... */ | ||||
| 	i--; | ||||
| 	for (; i >= 0; i--) | ||||
| 		i40e_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); | ||||
| 	i40e_free_virt_mem(hw, &hw->aq.arq.dma_head); | ||||
| 
 | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_alloc_asq_bufs - Allocate empty buffer structs for the send queue | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  **/ | ||||
| static i40e_status i40e_alloc_asq_bufs(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code; | ||||
| 	struct i40e_dma_mem *bi; | ||||
| 	int i; | ||||
| 
 | ||||
| 	/* No mapped memory needed yet, just the buffer info structures */ | ||||
| 	ret_code = i40e_allocate_virt_mem(hw, &hw->aq.asq.dma_head, | ||||
| 		(hw->aq.num_asq_entries * sizeof(struct i40e_dma_mem))); | ||||
| 	if (ret_code) | ||||
| 		goto alloc_asq_bufs; | ||||
| 	hw->aq.asq.r.asq_bi = (struct i40e_dma_mem *)hw->aq.asq.dma_head.va; | ||||
| 
 | ||||
| 	/* allocate the mapped buffers */ | ||||
| 	for (i = 0; i < hw->aq.num_asq_entries; i++) { | ||||
| 		bi = &hw->aq.asq.r.asq_bi[i]; | ||||
| 		ret_code = i40e_allocate_dma_mem(hw, bi, | ||||
| 						 i40e_mem_asq_buf, | ||||
| 						 hw->aq.asq_buf_size, | ||||
| 						 I40E_ADMINQ_DESC_ALIGNMENT); | ||||
| 		if (ret_code) | ||||
| 			goto unwind_alloc_asq_bufs; | ||||
| 	} | ||||
| alloc_asq_bufs: | ||||
| 	return ret_code; | ||||
| 
 | ||||
| unwind_alloc_asq_bufs: | ||||
| 	/* don't try to free the one that failed... */ | ||||
| 	i--; | ||||
| 	for (; i >= 0; i--) | ||||
| 		i40e_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); | ||||
| 	i40e_free_virt_mem(hw, &hw->aq.asq.dma_head); | ||||
| 
 | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_free_arq_bufs - Free receive queue buffer info elements | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  **/ | ||||
| static void i40e_free_arq_bufs(struct i40e_hw *hw) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	/* free descriptors */ | ||||
| 	for (i = 0; i < hw->aq.num_arq_entries; i++) | ||||
| 		i40e_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); | ||||
| 
 | ||||
| 	/* free the descriptor memory */ | ||||
| 	i40e_free_dma_mem(hw, &hw->aq.arq.desc_buf); | ||||
| 
 | ||||
| 	/* free the dma header */ | ||||
| 	i40e_free_virt_mem(hw, &hw->aq.arq.dma_head); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_free_asq_bufs - Free send queue buffer info elements | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  **/ | ||||
| static void i40e_free_asq_bufs(struct i40e_hw *hw) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	/* only unmap if the address is non-NULL */ | ||||
| 	for (i = 0; i < hw->aq.num_asq_entries; i++) | ||||
| 		if (hw->aq.asq.r.asq_bi[i].pa) | ||||
| 			i40e_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); | ||||
| 
 | ||||
| 	/* free the buffer info list */ | ||||
| 	i40e_free_virt_mem(hw, &hw->aq.asq.cmd_buf); | ||||
| 
 | ||||
| 	/* free the descriptor memory */ | ||||
| 	i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf); | ||||
| 
 | ||||
| 	/* free the dma header */ | ||||
| 	i40e_free_virt_mem(hw, &hw->aq.asq.dma_head); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_config_asq_regs - configure ASQ registers | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  *  Configure base address and length registers for the transmit queue | ||||
|  **/ | ||||
| static i40e_status i40e_config_asq_regs(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code = 0; | ||||
| 	u32 reg = 0; | ||||
| 
 | ||||
| 	/* Clear Head and Tail */ | ||||
| 	wr32(hw, hw->aq.asq.head, 0); | ||||
| 	wr32(hw, hw->aq.asq.tail, 0); | ||||
| 
 | ||||
| 	/* set starting point */ | ||||
| 	wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | | ||||
| 				  I40E_PF_ATQLEN_ATQENABLE_MASK)); | ||||
| 	wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa)); | ||||
| 	wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa)); | ||||
| 
 | ||||
| 	/* Check one register to verify that config was applied */ | ||||
| 	reg = rd32(hw, hw->aq.asq.bal); | ||||
| 	if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa)) | ||||
| 		ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; | ||||
| 
 | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_config_arq_regs - ARQ register configuration | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  * Configure base address and length registers for the receive (event queue) | ||||
|  **/ | ||||
| static i40e_status i40e_config_arq_regs(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code = 0; | ||||
| 	u32 reg = 0; | ||||
| 
 | ||||
| 	/* Clear Head and Tail */ | ||||
| 	wr32(hw, hw->aq.arq.head, 0); | ||||
| 	wr32(hw, hw->aq.arq.tail, 0); | ||||
| 
 | ||||
| 	/* set starting point */ | ||||
| 	wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | | ||||
| 				  I40E_PF_ARQLEN_ARQENABLE_MASK)); | ||||
| 	wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa)); | ||||
| 	wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa)); | ||||
| 
 | ||||
| 	/* Update tail in the HW to post pre-allocated buffers */ | ||||
| 	wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1); | ||||
| 
 | ||||
| 	/* Check one register to verify that config was applied */ | ||||
| 	reg = rd32(hw, hw->aq.arq.bal); | ||||
| 	if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa)) | ||||
| 		ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; | ||||
| 
 | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_init_asq - main initialization routine for ASQ | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  *  This is the main initialization routine for the Admin Send Queue | ||||
|  *  Prior to calling this function, drivers *MUST* set the following fields | ||||
|  *  in the hw->aq structure: | ||||
|  *     - hw->aq.num_asq_entries | ||||
|  *     - hw->aq.arq_buf_size | ||||
|  * | ||||
|  *  Do *NOT* hold the lock when calling this as the memory allocation routines | ||||
|  *  called are not going to be atomic context safe | ||||
|  **/ | ||||
| static i40e_status i40e_init_asq(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code = 0; | ||||
| 
 | ||||
| 	if (hw->aq.asq.count > 0) { | ||||
| 		/* queue already initialized */ | ||||
| 		ret_code = I40E_ERR_NOT_READY; | ||||
| 		goto init_adminq_exit; | ||||
| 	} | ||||
| 
 | ||||
| 	/* verify input for valid configuration */ | ||||
| 	if ((hw->aq.num_asq_entries == 0) || | ||||
| 	    (hw->aq.asq_buf_size == 0)) { | ||||
| 		ret_code = I40E_ERR_CONFIG; | ||||
| 		goto init_adminq_exit; | ||||
| 	} | ||||
| 
 | ||||
| 	hw->aq.asq.next_to_use = 0; | ||||
| 	hw->aq.asq.next_to_clean = 0; | ||||
| 	hw->aq.asq.count = hw->aq.num_asq_entries; | ||||
| 
 | ||||
| 	/* allocate the ring memory */ | ||||
| 	ret_code = i40e_alloc_adminq_asq_ring(hw); | ||||
| 	if (ret_code) | ||||
| 		goto init_adminq_exit; | ||||
| 
 | ||||
| 	/* allocate buffers in the rings */ | ||||
| 	ret_code = i40e_alloc_asq_bufs(hw); | ||||
| 	if (ret_code) | ||||
| 		goto init_adminq_free_rings; | ||||
| 
 | ||||
| 	/* initialize base registers */ | ||||
| 	ret_code = i40e_config_asq_regs(hw); | ||||
| 	if (ret_code) | ||||
| 		goto init_adminq_free_rings; | ||||
| 
 | ||||
| 	/* success! */ | ||||
| 	goto init_adminq_exit; | ||||
| 
 | ||||
| init_adminq_free_rings: | ||||
| 	i40e_free_adminq_asq(hw); | ||||
| 
 | ||||
| init_adminq_exit: | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_init_arq - initialize ARQ | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  *  The main initialization routine for the Admin Receive (Event) Queue. | ||||
|  *  Prior to calling this function, drivers *MUST* set the following fields | ||||
|  *  in the hw->aq structure: | ||||
|  *     - hw->aq.num_asq_entries | ||||
|  *     - hw->aq.arq_buf_size | ||||
|  * | ||||
|  *  Do *NOT* hold the lock when calling this as the memory allocation routines | ||||
|  *  called are not going to be atomic context safe | ||||
|  **/ | ||||
| static i40e_status i40e_init_arq(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code = 0; | ||||
| 
 | ||||
| 	if (hw->aq.arq.count > 0) { | ||||
| 		/* queue already initialized */ | ||||
| 		ret_code = I40E_ERR_NOT_READY; | ||||
| 		goto init_adminq_exit; | ||||
| 	} | ||||
| 
 | ||||
| 	/* verify input for valid configuration */ | ||||
| 	if ((hw->aq.num_arq_entries == 0) || | ||||
| 	    (hw->aq.arq_buf_size == 0)) { | ||||
| 		ret_code = I40E_ERR_CONFIG; | ||||
| 		goto init_adminq_exit; | ||||
| 	} | ||||
| 
 | ||||
| 	hw->aq.arq.next_to_use = 0; | ||||
| 	hw->aq.arq.next_to_clean = 0; | ||||
| 	hw->aq.arq.count = hw->aq.num_arq_entries; | ||||
| 
 | ||||
| 	/* allocate the ring memory */ | ||||
| 	ret_code = i40e_alloc_adminq_arq_ring(hw); | ||||
| 	if (ret_code) | ||||
| 		goto init_adminq_exit; | ||||
| 
 | ||||
| 	/* allocate buffers in the rings */ | ||||
| 	ret_code = i40e_alloc_arq_bufs(hw); | ||||
| 	if (ret_code) | ||||
| 		goto init_adminq_free_rings; | ||||
| 
 | ||||
| 	/* initialize base registers */ | ||||
| 	ret_code = i40e_config_arq_regs(hw); | ||||
| 	if (ret_code) | ||||
| 		goto init_adminq_free_rings; | ||||
| 
 | ||||
| 	/* success! */ | ||||
| 	goto init_adminq_exit; | ||||
| 
 | ||||
| init_adminq_free_rings: | ||||
| 	i40e_free_adminq_arq(hw); | ||||
| 
 | ||||
| init_adminq_exit: | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_shutdown_asq - shutdown the ASQ | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  *  The main shutdown routine for the Admin Send Queue | ||||
|  **/ | ||||
| static i40e_status i40e_shutdown_asq(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code = 0; | ||||
| 
 | ||||
| 	if (hw->aq.asq.count == 0) | ||||
| 		return I40E_ERR_NOT_READY; | ||||
| 
 | ||||
| 	/* Stop firmware AdminQ processing */ | ||||
| 	wr32(hw, hw->aq.asq.head, 0); | ||||
| 	wr32(hw, hw->aq.asq.tail, 0); | ||||
| 	wr32(hw, hw->aq.asq.len, 0); | ||||
| 	wr32(hw, hw->aq.asq.bal, 0); | ||||
| 	wr32(hw, hw->aq.asq.bah, 0); | ||||
| 
 | ||||
| 	/* make sure lock is available */ | ||||
| 	mutex_lock(&hw->aq.asq_mutex); | ||||
| 
 | ||||
| 	hw->aq.asq.count = 0; /* to indicate uninitialized queue */ | ||||
| 
 | ||||
| 	/* free ring buffers */ | ||||
| 	i40e_free_asq_bufs(hw); | ||||
| 
 | ||||
| 	mutex_unlock(&hw->aq.asq_mutex); | ||||
| 
 | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_shutdown_arq - shutdown ARQ | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  *  The main shutdown routine for the Admin Receive Queue | ||||
|  **/ | ||||
| static i40e_status i40e_shutdown_arq(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code = 0; | ||||
| 
 | ||||
| 	if (hw->aq.arq.count == 0) | ||||
| 		return I40E_ERR_NOT_READY; | ||||
| 
 | ||||
| 	/* Stop firmware AdminQ processing */ | ||||
| 	wr32(hw, hw->aq.arq.head, 0); | ||||
| 	wr32(hw, hw->aq.arq.tail, 0); | ||||
| 	wr32(hw, hw->aq.arq.len, 0); | ||||
| 	wr32(hw, hw->aq.arq.bal, 0); | ||||
| 	wr32(hw, hw->aq.arq.bah, 0); | ||||
| 
 | ||||
| 	/* make sure lock is available */ | ||||
| 	mutex_lock(&hw->aq.arq_mutex); | ||||
| 
 | ||||
| 	hw->aq.arq.count = 0; /* to indicate uninitialized queue */ | ||||
| 
 | ||||
| 	/* free ring buffers */ | ||||
| 	i40e_free_arq_bufs(hw); | ||||
| 
 | ||||
| 	mutex_unlock(&hw->aq.arq_mutex); | ||||
| 
 | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40evf_init_adminq - main initialization routine for Admin Queue | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  *  Prior to calling this function, drivers *MUST* set the following fields | ||||
|  *  in the hw->aq structure: | ||||
|  *     - hw->aq.num_asq_entries | ||||
|  *     - hw->aq.num_arq_entries | ||||
|  *     - hw->aq.arq_buf_size | ||||
|  *     - hw->aq.asq_buf_size | ||||
|  **/ | ||||
| i40e_status i40evf_init_adminq(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code; | ||||
| 
 | ||||
| 	/* verify input for valid configuration */ | ||||
| 	if ((hw->aq.num_arq_entries == 0) || | ||||
| 	    (hw->aq.num_asq_entries == 0) || | ||||
| 	    (hw->aq.arq_buf_size == 0) || | ||||
| 	    (hw->aq.asq_buf_size == 0)) { | ||||
| 		ret_code = I40E_ERR_CONFIG; | ||||
| 		goto init_adminq_exit; | ||||
| 	} | ||||
| 
 | ||||
| 	/* initialize locks */ | ||||
| 	mutex_init(&hw->aq.asq_mutex); | ||||
| 	mutex_init(&hw->aq.arq_mutex); | ||||
| 
 | ||||
| 	/* Set up register offsets */ | ||||
| 	i40e_adminq_init_regs(hw); | ||||
| 
 | ||||
| 	/* setup ASQ command write back timeout */ | ||||
| 	hw->aq.asq_cmd_timeout = I40E_ASQ_CMD_TIMEOUT; | ||||
| 
 | ||||
| 	/* allocate the ASQ */ | ||||
| 	ret_code = i40e_init_asq(hw); | ||||
| 	if (ret_code) | ||||
| 		goto init_adminq_destroy_locks; | ||||
| 
 | ||||
| 	/* allocate the ARQ */ | ||||
| 	ret_code = i40e_init_arq(hw); | ||||
| 	if (ret_code) | ||||
| 		goto init_adminq_free_asq; | ||||
| 
 | ||||
| 	/* success! */ | ||||
| 	goto init_adminq_exit; | ||||
| 
 | ||||
| init_adminq_free_asq: | ||||
| 	i40e_shutdown_asq(hw); | ||||
| init_adminq_destroy_locks: | ||||
| 
 | ||||
| init_adminq_exit: | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40evf_shutdown_adminq - shutdown routine for the Admin Queue | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  **/ | ||||
| i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status ret_code = 0; | ||||
| 
 | ||||
| 	if (i40evf_check_asq_alive(hw)) | ||||
| 		i40evf_aq_queue_shutdown(hw, true); | ||||
| 
 | ||||
| 	i40e_shutdown_asq(hw); | ||||
| 	i40e_shutdown_arq(hw); | ||||
| 
 | ||||
| 	/* destroy the locks */ | ||||
| 
 | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40e_clean_asq - cleans Admin send queue | ||||
|  *  @hw: pointer to the hardware structure | ||||
|  * | ||||
|  *  returns the number of free desc | ||||
|  **/ | ||||
| static u16 i40e_clean_asq(struct i40e_hw *hw) | ||||
| { | ||||
| 	struct i40e_adminq_ring *asq = &(hw->aq.asq); | ||||
| 	struct i40e_asq_cmd_details *details; | ||||
| 	u16 ntc = asq->next_to_clean; | ||||
| 	struct i40e_aq_desc desc_cb; | ||||
| 	struct i40e_aq_desc *desc; | ||||
| 
 | ||||
| 	desc = I40E_ADMINQ_DESC(*asq, ntc); | ||||
| 	details = I40E_ADMINQ_DETAILS(*asq, ntc); | ||||
| 	while (rd32(hw, hw->aq.asq.head) != ntc) { | ||||
| 		i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, | ||||
| 			   "%s: ntc %d head %d.\n", __func__, ntc, | ||||
| 			   rd32(hw, hw->aq.asq.head)); | ||||
| 
 | ||||
| 		if (details->callback) { | ||||
| 			I40E_ADMINQ_CALLBACK cb_func = | ||||
| 					(I40E_ADMINQ_CALLBACK)details->callback; | ||||
| 			desc_cb = *desc; | ||||
| 			cb_func(hw, &desc_cb); | ||||
| 		} | ||||
| 		memset((void *)desc, 0, sizeof(struct i40e_aq_desc)); | ||||
| 		memset((void *)details, 0, | ||||
| 		       sizeof(struct i40e_asq_cmd_details)); | ||||
| 		ntc++; | ||||
| 		if (ntc == asq->count) | ||||
| 			ntc = 0; | ||||
| 		desc = I40E_ADMINQ_DESC(*asq, ntc); | ||||
| 		details = I40E_ADMINQ_DETAILS(*asq, ntc); | ||||
| 	} | ||||
| 
 | ||||
| 	asq->next_to_clean = ntc; | ||||
| 
 | ||||
| 	return I40E_DESC_UNUSED(asq); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40evf_asq_done - check if FW has processed the Admin Send Queue | ||||
|  *  @hw: pointer to the hw struct | ||||
|  * | ||||
|  *  Returns true if the firmware has processed all descriptors on the | ||||
|  *  admin send queue. Returns false if there are still requests pending. | ||||
|  **/ | ||||
| bool i40evf_asq_done(struct i40e_hw *hw) | ||||
| { | ||||
| 	/* AQ designers suggest use of head for better
 | ||||
| 	 * timing reliability than DD bit | ||||
| 	 */ | ||||
| 	return rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40evf_asq_send_command - send command to Admin Queue | ||||
|  *  @hw: pointer to the hw struct | ||||
|  *  @desc: prefilled descriptor describing the command (non DMA mem) | ||||
|  *  @buff: buffer to use for indirect commands | ||||
|  *  @buff_size: size of buffer for indirect commands | ||||
|  *  @cmd_details: pointer to command details structure | ||||
|  * | ||||
|  *  This is the main send command driver routine for the Admin Queue send | ||||
|  *  queue.  It runs the queue, cleans the queue, etc | ||||
|  **/ | ||||
| i40e_status i40evf_asq_send_command(struct i40e_hw *hw, | ||||
| 				struct i40e_aq_desc *desc, | ||||
| 				void *buff, /* can be NULL */ | ||||
| 				u16  buff_size, | ||||
| 				struct i40e_asq_cmd_details *cmd_details) | ||||
| { | ||||
| 	i40e_status status = 0; | ||||
| 	struct i40e_dma_mem *dma_buff = NULL; | ||||
| 	struct i40e_asq_cmd_details *details; | ||||
| 	struct i40e_aq_desc *desc_on_ring; | ||||
| 	bool cmd_completed = false; | ||||
| 	u16  retval = 0; | ||||
| 	u32  val = 0; | ||||
| 
 | ||||
| 	val = rd32(hw, hw->aq.asq.head); | ||||
| 	if (val >= hw->aq.num_asq_entries) { | ||||
| 		i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, | ||||
| 			   "AQTX: head overrun at %d\n", val); | ||||
| 		status = I40E_ERR_QUEUE_EMPTY; | ||||
| 		goto asq_send_command_exit; | ||||
| 	} | ||||
| 
 | ||||
| 	if (hw->aq.asq.count == 0) { | ||||
| 		i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, | ||||
| 			   "AQTX: Admin queue not initialized.\n"); | ||||
| 		status = I40E_ERR_QUEUE_EMPTY; | ||||
| 		goto asq_send_command_exit; | ||||
| 	} | ||||
| 
 | ||||
| 	details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); | ||||
| 	if (cmd_details) { | ||||
| 		*details = *cmd_details; | ||||
| 
 | ||||
| 		/* If the cmd_details are defined copy the cookie.  The
 | ||||
| 		 * cpu_to_le32 is not needed here because the data is ignored | ||||
| 		 * by the FW, only used by the driver | ||||
| 		 */ | ||||
| 		if (details->cookie) { | ||||
| 			desc->cookie_high = | ||||
| 				cpu_to_le32(upper_32_bits(details->cookie)); | ||||
| 			desc->cookie_low = | ||||
| 				cpu_to_le32(lower_32_bits(details->cookie)); | ||||
| 		} | ||||
| 	} else { | ||||
| 		memset(details, 0, sizeof(struct i40e_asq_cmd_details)); | ||||
| 	} | ||||
| 
 | ||||
| 	/* clear requested flags and then set additional flags if defined */ | ||||
| 	desc->flags &= ~cpu_to_le16(details->flags_dis); | ||||
| 	desc->flags |= cpu_to_le16(details->flags_ena); | ||||
| 
 | ||||
| 	mutex_lock(&hw->aq.asq_mutex); | ||||
| 
 | ||||
| 	if (buff_size > hw->aq.asq_buf_size) { | ||||
| 		i40e_debug(hw, | ||||
| 			   I40E_DEBUG_AQ_MESSAGE, | ||||
| 			   "AQTX: Invalid buffer size: %d.\n", | ||||
| 			   buff_size); | ||||
| 		status = I40E_ERR_INVALID_SIZE; | ||||
| 		goto asq_send_command_error; | ||||
| 	} | ||||
| 
 | ||||
| 	if (details->postpone && !details->async) { | ||||
| 		i40e_debug(hw, | ||||
| 			   I40E_DEBUG_AQ_MESSAGE, | ||||
| 			   "AQTX: Async flag not set along with postpone flag"); | ||||
| 		status = I40E_ERR_PARAM; | ||||
| 		goto asq_send_command_error; | ||||
| 	} | ||||
| 
 | ||||
| 	/* call clean and check queue available function to reclaim the
 | ||||
| 	 * descriptors that were processed by FW, the function returns the | ||||
| 	 * number of desc available | ||||
| 	 */ | ||||
| 	/* the clean function called here could be called in a separate thread
 | ||||
| 	 * in case of asynchronous completions | ||||
| 	 */ | ||||
| 	if (i40e_clean_asq(hw) == 0) { | ||||
| 		i40e_debug(hw, | ||||
| 			   I40E_DEBUG_AQ_MESSAGE, | ||||
| 			   "AQTX: Error queue is full.\n"); | ||||
| 		status = I40E_ERR_ADMIN_QUEUE_FULL; | ||||
| 		goto asq_send_command_error; | ||||
| 	} | ||||
| 
 | ||||
| 	/* initialize the temp desc pointer with the right desc */ | ||||
| 	desc_on_ring = I40E_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use); | ||||
| 
 | ||||
| 	/* if the desc is available copy the temp desc to the right place */ | ||||
| 	*desc_on_ring = *desc; | ||||
| 
 | ||||
| 	/* if buff is not NULL assume indirect command */ | ||||
| 	if (buff != NULL) { | ||||
| 		dma_buff = &(hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use]); | ||||
| 		/* copy the user buff into the respective DMA buff */ | ||||
| 		memcpy(dma_buff->va, buff, buff_size); | ||||
| 		desc_on_ring->datalen = cpu_to_le16(buff_size); | ||||
| 
 | ||||
| 		/* Update the address values in the desc with the pa value
 | ||||
| 		 * for respective buffer | ||||
| 		 */ | ||||
| 		desc_on_ring->params.external.addr_high = | ||||
| 				cpu_to_le32(upper_32_bits(dma_buff->pa)); | ||||
| 		desc_on_ring->params.external.addr_low = | ||||
| 				cpu_to_le32(lower_32_bits(dma_buff->pa)); | ||||
| 	} | ||||
| 
 | ||||
| 	/* bump the tail */ | ||||
| 	i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); | ||||
| 	i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, | ||||
| 			buff, buff_size); | ||||
| 	(hw->aq.asq.next_to_use)++; | ||||
| 	if (hw->aq.asq.next_to_use == hw->aq.asq.count) | ||||
| 		hw->aq.asq.next_to_use = 0; | ||||
| 	if (!details->postpone) | ||||
| 		wr32(hw, hw->aq.asq.tail, hw->aq.asq.next_to_use); | ||||
| 
 | ||||
| 	/* if cmd_details are not defined or async flag is not set,
 | ||||
| 	 * we need to wait for desc write back | ||||
| 	 */ | ||||
| 	if (!details->async && !details->postpone) { | ||||
| 		u32 total_delay = 0; | ||||
| 		u32 delay_len = 10; | ||||
| 
 | ||||
| 		do { | ||||
| 			/* AQ designers suggest use of head for better
 | ||||
| 			 * timing reliability than DD bit | ||||
| 			 */ | ||||
| 			if (i40evf_asq_done(hw)) | ||||
| 				break; | ||||
| 			/* ugh! delay while spin_lock */ | ||||
| 			udelay(delay_len); | ||||
| 			total_delay += delay_len; | ||||
| 		} while (total_delay < hw->aq.asq_cmd_timeout); | ||||
| 	} | ||||
| 
 | ||||
| 	/* if ready, copy the desc back to temp */ | ||||
| 	if (i40evf_asq_done(hw)) { | ||||
| 		*desc = *desc_on_ring; | ||||
| 		if (buff != NULL) | ||||
| 			memcpy(buff, dma_buff->va, buff_size); | ||||
| 		retval = le16_to_cpu(desc->retval); | ||||
| 		if (retval != 0) { | ||||
| 			i40e_debug(hw, | ||||
| 				   I40E_DEBUG_AQ_MESSAGE, | ||||
| 				   "AQTX: Command completed with error 0x%X.\n", | ||||
| 				   retval); | ||||
| 
 | ||||
| 			/* strip off FW internal code */ | ||||
| 			retval &= 0xff; | ||||
| 		} | ||||
| 		cmd_completed = true; | ||||
| 		if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_OK) | ||||
| 			status = 0; | ||||
| 		else | ||||
| 			status = I40E_ERR_ADMIN_QUEUE_ERROR; | ||||
| 		hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; | ||||
| 	} | ||||
| 
 | ||||
| 	if (i40e_is_nvm_update_op(desc)) | ||||
| 		hw->aq.nvm_busy = true; | ||||
| 
 | ||||
| 	i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, | ||||
| 		   "AQTX: desc and buffer writeback:\n"); | ||||
| 	i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, | ||||
| 			buff_size); | ||||
| 
 | ||||
| 	/* update the error if time out occurred */ | ||||
| 	if ((!cmd_completed) && | ||||
| 	    (!details->async && !details->postpone)) { | ||||
| 		i40e_debug(hw, | ||||
| 			   I40E_DEBUG_AQ_MESSAGE, | ||||
| 			   "AQTX: Writeback timeout.\n"); | ||||
| 		status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; | ||||
| 	} | ||||
| 
 | ||||
| asq_send_command_error: | ||||
| 	mutex_unlock(&hw->aq.asq_mutex); | ||||
| asq_send_command_exit: | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40evf_fill_default_direct_cmd_desc - AQ descriptor helper function | ||||
|  *  @desc:     pointer to the temp descriptor (non DMA mem) | ||||
|  *  @opcode:   the opcode can be used to decide which flags to turn off or on | ||||
|  * | ||||
|  *  Fill the desc with default values | ||||
|  **/ | ||||
| void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, | ||||
| 				       u16 opcode) | ||||
| { | ||||
| 	/* zero out the desc */ | ||||
| 	memset((void *)desc, 0, sizeof(struct i40e_aq_desc)); | ||||
| 	desc->opcode = cpu_to_le16(opcode); | ||||
| 	desc->flags = cpu_to_le16(I40E_AQ_FLAG_SI); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *  i40evf_clean_arq_element | ||||
|  *  @hw: pointer to the hw struct | ||||
|  *  @e: event info from the receive descriptor, includes any buffers | ||||
|  *  @pending: number of events that could be left to process | ||||
|  * | ||||
|  *  This function cleans one Admin Receive Queue element and returns | ||||
|  *  the contents through e.  It can also return how many events are | ||||
|  *  left to process through 'pending' | ||||
|  **/ | ||||
| i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, | ||||
| 					     struct i40e_arq_event_info *e, | ||||
| 					     u16 *pending) | ||||
| { | ||||
| 	i40e_status ret_code = 0; | ||||
| 	u16 ntc = hw->aq.arq.next_to_clean; | ||||
| 	struct i40e_aq_desc *desc; | ||||
| 	struct i40e_dma_mem *bi; | ||||
| 	u16 desc_idx; | ||||
| 	u16 datalen; | ||||
| 	u16 flags; | ||||
| 	u16 ntu; | ||||
| 
 | ||||
| 	/* take the lock before we start messing with the ring */ | ||||
| 	mutex_lock(&hw->aq.arq_mutex); | ||||
| 
 | ||||
| 	/* set next_to_use to head */ | ||||
| 	ntu = (rd32(hw, hw->aq.arq.head) & I40E_PF_ARQH_ARQH_MASK); | ||||
| 	if (ntu == ntc) { | ||||
| 		/* nothing to do - shouldn't need to update ring's values */ | ||||
| 		i40e_debug(hw, | ||||
| 			   I40E_DEBUG_AQ_MESSAGE, | ||||
| 			   "AQRX: Queue is empty.\n"); | ||||
| 		ret_code = I40E_ERR_ADMIN_QUEUE_NO_WORK; | ||||
| 		goto clean_arq_element_out; | ||||
| 	} | ||||
| 
 | ||||
| 	/* now clean the next descriptor */ | ||||
| 	desc = I40E_ADMINQ_DESC(hw->aq.arq, ntc); | ||||
| 	desc_idx = ntc; | ||||
| 
 | ||||
| 	flags = le16_to_cpu(desc->flags); | ||||
| 	if (flags & I40E_AQ_FLAG_ERR) { | ||||
| 		ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; | ||||
| 		hw->aq.arq_last_status = | ||||
| 			(enum i40e_admin_queue_err)le16_to_cpu(desc->retval); | ||||
| 		i40e_debug(hw, | ||||
| 			   I40E_DEBUG_AQ_MESSAGE, | ||||
| 			   "AQRX: Event received with error 0x%X.\n", | ||||
| 			   hw->aq.arq_last_status); | ||||
| 	} | ||||
| 
 | ||||
| 	e->desc = *desc; | ||||
| 	datalen = le16_to_cpu(desc->datalen); | ||||
| 	e->msg_size = min(datalen, e->msg_size); | ||||
| 	if (e->msg_buf != NULL && (e->msg_size != 0)) | ||||
| 		memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va, | ||||
| 		       e->msg_size); | ||||
| 
 | ||||
| 	if (i40e_is_nvm_update_op(&e->desc)) | ||||
| 		hw->aq.nvm_busy = false; | ||||
| 
 | ||||
| 	i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); | ||||
| 	i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf, | ||||
| 			hw->aq.arq_buf_size); | ||||
| 
 | ||||
| 	/* Restore the original datalen and buffer address in the desc,
 | ||||
| 	 * FW updates datalen to indicate the event message | ||||
| 	 * size | ||||
| 	 */ | ||||
| 	bi = &hw->aq.arq.r.arq_bi[ntc]; | ||||
| 	memset((void *)desc, 0, sizeof(struct i40e_aq_desc)); | ||||
| 
 | ||||
| 	desc->flags = cpu_to_le16(I40E_AQ_FLAG_BUF); | ||||
| 	if (hw->aq.arq_buf_size > I40E_AQ_LARGE_BUF) | ||||
| 		desc->flags |= cpu_to_le16(I40E_AQ_FLAG_LB); | ||||
| 	desc->datalen = cpu_to_le16((u16)bi->size); | ||||
| 	desc->params.external.addr_high = cpu_to_le32(upper_32_bits(bi->pa)); | ||||
| 	desc->params.external.addr_low = cpu_to_le32(lower_32_bits(bi->pa)); | ||||
| 
 | ||||
| 	/* set tail = the last cleaned desc index. */ | ||||
| 	wr32(hw, hw->aq.arq.tail, ntc); | ||||
| 	/* ntc is updated to tail + 1 */ | ||||
| 	ntc++; | ||||
| 	if (ntc == hw->aq.num_arq_entries) | ||||
| 		ntc = 0; | ||||
| 	hw->aq.arq.next_to_clean = ntc; | ||||
| 	hw->aq.arq.next_to_use = ntu; | ||||
| 
 | ||||
| clean_arq_element_out: | ||||
| 	/* Set pending if needed, unlock and return */ | ||||
| 	if (pending != NULL) | ||||
| 		*pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc); | ||||
| 	mutex_unlock(&hw->aq.arq_mutex); | ||||
| 
 | ||||
| 	return ret_code; | ||||
| } | ||||
| 
 | ||||
| void i40evf_resume_aq(struct i40e_hw *hw) | ||||
| { | ||||
| 	/* Registers are reset after PF reset */ | ||||
| 	hw->aq.asq.next_to_use = 0; | ||||
| 	hw->aq.asq.next_to_clean = 0; | ||||
| 
 | ||||
| 	i40e_config_asq_regs(hw); | ||||
| 
 | ||||
| 	hw->aq.arq.next_to_use = 0; | ||||
| 	hw->aq.arq.next_to_clean = 0; | ||||
| 
 | ||||
| 	i40e_config_arq_regs(hw); | ||||
| } | ||||
							
								
								
									
										149
									
								
								drivers/net/ethernet/intel/i40evf/i40e_adminq.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								drivers/net/ethernet/intel/i40evf/i40e_adminq.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,149 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #ifndef _I40E_ADMINQ_H_ | ||||
| #define _I40E_ADMINQ_H_ | ||||
| 
 | ||||
| #include "i40e_osdep.h" | ||||
| #include "i40e_adminq_cmd.h" | ||||
| 
 | ||||
| #define I40E_ADMINQ_DESC(R, i)   \ | ||||
| 	(&(((struct i40e_aq_desc *)((R).desc_buf.va))[i])) | ||||
| 
 | ||||
| #define I40E_ADMINQ_DESC_ALIGNMENT 4096 | ||||
| 
 | ||||
| struct i40e_adminq_ring { | ||||
| 	struct i40e_virt_mem dma_head;	/* space for dma structures */ | ||||
| 	struct i40e_dma_mem desc_buf;	/* descriptor ring memory */ | ||||
| 	struct i40e_virt_mem cmd_buf;	/* command buffer memory */ | ||||
| 
 | ||||
| 	union { | ||||
| 		struct i40e_dma_mem *asq_bi; | ||||
| 		struct i40e_dma_mem *arq_bi; | ||||
| 	} r; | ||||
| 
 | ||||
| 	u16 count;		/* Number of descriptors */ | ||||
| 	u16 rx_buf_len;		/* Admin Receive Queue buffer length */ | ||||
| 
 | ||||
| 	/* used for interrupt processing */ | ||||
| 	u16 next_to_use; | ||||
| 	u16 next_to_clean; | ||||
| 
 | ||||
| 	/* used for queue tracking */ | ||||
| 	u32 head; | ||||
| 	u32 tail; | ||||
| 	u32 len; | ||||
| 	u32 bah; | ||||
| 	u32 bal; | ||||
| }; | ||||
| 
 | ||||
| /* ASQ transaction details */ | ||||
| struct i40e_asq_cmd_details { | ||||
| 	void *callback; /* cast from type I40E_ADMINQ_CALLBACK */ | ||||
| 	u64 cookie; | ||||
| 	u16 flags_ena; | ||||
| 	u16 flags_dis; | ||||
| 	bool async; | ||||
| 	bool postpone; | ||||
| }; | ||||
| 
 | ||||
| #define I40E_ADMINQ_DETAILS(R, i)   \ | ||||
| 	(&(((struct i40e_asq_cmd_details *)((R).cmd_buf.va))[i])) | ||||
| 
 | ||||
| /* ARQ event information */ | ||||
| struct i40e_arq_event_info { | ||||
| 	struct i40e_aq_desc desc; | ||||
| 	u16 msg_size; | ||||
| 	u8 *msg_buf; | ||||
| }; | ||||
| 
 | ||||
| /* Admin Queue information */ | ||||
| struct i40e_adminq_info { | ||||
| 	struct i40e_adminq_ring arq;    /* receive queue */ | ||||
| 	struct i40e_adminq_ring asq;    /* send queue */ | ||||
| 	u32 asq_cmd_timeout;            /* send queue cmd write back timeout*/ | ||||
| 	u16 num_arq_entries;            /* receive queue depth */ | ||||
| 	u16 num_asq_entries;            /* send queue depth */ | ||||
| 	u16 arq_buf_size;               /* receive queue buffer size */ | ||||
| 	u16 asq_buf_size;               /* send queue buffer size */ | ||||
| 	u16 fw_maj_ver;                 /* firmware major version */ | ||||
| 	u16 fw_min_ver;                 /* firmware minor version */ | ||||
| 	u16 api_maj_ver;                /* api major version */ | ||||
| 	u16 api_min_ver;                /* api minor version */ | ||||
| 	bool nvm_busy; | ||||
| 	bool nvm_release_on_done; | ||||
| 
 | ||||
| 	struct mutex asq_mutex; /* Send queue lock */ | ||||
| 	struct mutex arq_mutex; /* Receive queue lock */ | ||||
| 
 | ||||
| 	/* last status values on send and receive queues */ | ||||
| 	enum i40e_admin_queue_err asq_last_status; | ||||
| 	enum i40e_admin_queue_err arq_last_status; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * i40e_aq_rc_to_posix - convert errors to user-land codes | ||||
|  * aq_rc: AdminQ error code to convert | ||||
|  **/ | ||||
| static inline int i40e_aq_rc_to_posix(u16 aq_rc) | ||||
| { | ||||
| 	int aq_to_posix[] = { | ||||
| 		0,           /* I40E_AQ_RC_OK */ | ||||
| 		-EPERM,      /* I40E_AQ_RC_EPERM */ | ||||
| 		-ENOENT,     /* I40E_AQ_RC_ENOENT */ | ||||
| 		-ESRCH,      /* I40E_AQ_RC_ESRCH */ | ||||
| 		-EINTR,      /* I40E_AQ_RC_EINTR */ | ||||
| 		-EIO,        /* I40E_AQ_RC_EIO */ | ||||
| 		-ENXIO,      /* I40E_AQ_RC_ENXIO */ | ||||
| 		-E2BIG,      /* I40E_AQ_RC_E2BIG */ | ||||
| 		-EAGAIN,     /* I40E_AQ_RC_EAGAIN */ | ||||
| 		-ENOMEM,     /* I40E_AQ_RC_ENOMEM */ | ||||
| 		-EACCES,     /* I40E_AQ_RC_EACCES */ | ||||
| 		-EFAULT,     /* I40E_AQ_RC_EFAULT */ | ||||
| 		-EBUSY,      /* I40E_AQ_RC_EBUSY */ | ||||
| 		-EEXIST,     /* I40E_AQ_RC_EEXIST */ | ||||
| 		-EINVAL,     /* I40E_AQ_RC_EINVAL */ | ||||
| 		-ENOTTY,     /* I40E_AQ_RC_ENOTTY */ | ||||
| 		-ENOSPC,     /* I40E_AQ_RC_ENOSPC */ | ||||
| 		-ENOSYS,     /* I40E_AQ_RC_ENOSYS */ | ||||
| 		-ERANGE,     /* I40E_AQ_RC_ERANGE */ | ||||
| 		-EPIPE,      /* I40E_AQ_RC_EFLUSHED */ | ||||
| 		-ESPIPE,     /* I40E_AQ_RC_BAD_ADDR */ | ||||
| 		-EROFS,      /* I40E_AQ_RC_EMODE */ | ||||
| 		-EFBIG,      /* I40E_AQ_RC_EFBIG */ | ||||
| 	}; | ||||
| 
 | ||||
| 	return aq_to_posix[aq_rc]; | ||||
| } | ||||
| 
 | ||||
| /* general information */ | ||||
| #define I40E_AQ_LARGE_BUF	512 | ||||
| #define I40E_ASQ_CMD_TIMEOUT	100000  /* usecs */ | ||||
| 
 | ||||
| void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, | ||||
| 				       u16 opcode); | ||||
| 
 | ||||
| #endif /* _I40E_ADMINQ_H_ */ | ||||
							
								
								
									
										2197
									
								
								drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2197
									
								
								drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										58
									
								
								drivers/net/ethernet/intel/i40evf/i40e_alloc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								drivers/net/ethernet/intel/i40evf/i40e_alloc.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #ifndef _I40E_ALLOC_H_ | ||||
| #define _I40E_ALLOC_H_ | ||||
| 
 | ||||
| struct i40e_hw; | ||||
| 
 | ||||
| /* Memory allocation types */ | ||||
| enum i40e_memory_type { | ||||
| 	i40e_mem_arq_buf = 0,		/* ARQ indirect command buffer */ | ||||
| 	i40e_mem_asq_buf = 1, | ||||
| 	i40e_mem_atq_buf = 2,		/* ATQ indirect command buffer */ | ||||
| 	i40e_mem_arq_ring = 3,		/* ARQ descriptor ring */ | ||||
| 	i40e_mem_atq_ring = 4,		/* ATQ descriptor ring */ | ||||
| 	i40e_mem_pd = 5,		/* Page Descriptor */ | ||||
| 	i40e_mem_bp = 6,		/* Backing Page - 4KB */ | ||||
| 	i40e_mem_bp_jumbo = 7,		/* Backing Page - > 4KB */ | ||||
| 	i40e_mem_reserved | ||||
| }; | ||||
| 
 | ||||
| /* prototype for functions used for dynamic memory allocation */ | ||||
| i40e_status i40e_allocate_dma_mem(struct i40e_hw *hw, | ||||
| 					    struct i40e_dma_mem *mem, | ||||
| 					    enum i40e_memory_type type, | ||||
| 					    u64 size, u32 alignment); | ||||
| i40e_status i40e_free_dma_mem(struct i40e_hw *hw, | ||||
| 					struct i40e_dma_mem *mem); | ||||
| i40e_status i40e_allocate_virt_mem(struct i40e_hw *hw, | ||||
| 					     struct i40e_virt_mem *mem, | ||||
| 					     u32 size); | ||||
| i40e_status i40e_free_virt_mem(struct i40e_hw *hw, | ||||
| 					 struct i40e_virt_mem *mem); | ||||
| 
 | ||||
| #endif /* _I40E_ALLOC_H_ */ | ||||
							
								
								
									
										628
									
								
								drivers/net/ethernet/intel/i40evf/i40e_common.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										628
									
								
								drivers/net/ethernet/intel/i40evf/i40e_common.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,628 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #include "i40e_type.h" | ||||
| #include "i40e_adminq.h" | ||||
| #include "i40e_prototype.h" | ||||
| #include "i40e_virtchnl.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * i40e_set_mac_type - Sets MAC type | ||||
|  * @hw: pointer to the HW structure | ||||
|  * | ||||
|  * This function sets the mac type of the adapter based on the | ||||
|  * vendor ID and device ID stored in the hw structure. | ||||
|  **/ | ||||
| i40e_status i40e_set_mac_type(struct i40e_hw *hw) | ||||
| { | ||||
| 	i40e_status status = 0; | ||||
| 
 | ||||
| 	if (hw->vendor_id == PCI_VENDOR_ID_INTEL) { | ||||
| 		switch (hw->device_id) { | ||||
| 		case I40E_DEV_ID_SFP_XL710: | ||||
| 		case I40E_DEV_ID_QEMU: | ||||
| 		case I40E_DEV_ID_KX_A: | ||||
| 		case I40E_DEV_ID_KX_B: | ||||
| 		case I40E_DEV_ID_KX_C: | ||||
| 		case I40E_DEV_ID_QSFP_A: | ||||
| 		case I40E_DEV_ID_QSFP_B: | ||||
| 		case I40E_DEV_ID_QSFP_C: | ||||
| 			hw->mac.type = I40E_MAC_XL710; | ||||
| 			break; | ||||
| 		case I40E_DEV_ID_VF: | ||||
| 		case I40E_DEV_ID_VF_HV: | ||||
| 			hw->mac.type = I40E_MAC_VF; | ||||
| 			break; | ||||
| 		default: | ||||
| 			hw->mac.type = I40E_MAC_GENERIC; | ||||
| 			break; | ||||
| 		} | ||||
| 	} else { | ||||
| 		status = I40E_ERR_DEVICE_NOT_SUPPORTED; | ||||
| 	} | ||||
| 
 | ||||
| 	hw_dbg(hw, "i40e_set_mac_type found mac: %d, returns: %d\n", | ||||
| 		  hw->mac.type, status); | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_debug_aq | ||||
|  * @hw: debug mask related to admin queue | ||||
|  * @mask: debug mask | ||||
|  * @desc: pointer to admin queue descriptor | ||||
|  * @buffer: pointer to command buffer | ||||
|  * @buf_len: max length of buffer | ||||
|  * | ||||
|  * Dumps debug log about adminq command with descriptor contents. | ||||
|  **/ | ||||
| void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, | ||||
| 		   void *buffer, u16 buf_len) | ||||
| { | ||||
| 	struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc; | ||||
| 	u16 len = le16_to_cpu(aq_desc->datalen); | ||||
| 	u8 *aq_buffer = (u8 *)buffer; | ||||
| 	u32 data[4]; | ||||
| 	u32 i = 0; | ||||
| 
 | ||||
| 	if ((!(mask & hw->debug_mask)) || (desc == NULL)) | ||||
| 		return; | ||||
| 
 | ||||
| 	i40e_debug(hw, mask, | ||||
| 		   "AQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n", | ||||
| 		   aq_desc->opcode, aq_desc->flags, aq_desc->datalen, | ||||
| 		   aq_desc->retval); | ||||
| 	i40e_debug(hw, mask, "\tcookie (h,l) 0x%08X 0x%08X\n", | ||||
| 		   aq_desc->cookie_high, aq_desc->cookie_low); | ||||
| 	i40e_debug(hw, mask, "\tparam (0,1)  0x%08X 0x%08X\n", | ||||
| 		   aq_desc->params.internal.param0, | ||||
| 		   aq_desc->params.internal.param1); | ||||
| 	i40e_debug(hw, mask, "\taddr (h,l)   0x%08X 0x%08X\n", | ||||
| 		   aq_desc->params.external.addr_high, | ||||
| 		   aq_desc->params.external.addr_low); | ||||
| 
 | ||||
| 	if ((buffer != NULL) && (aq_desc->datalen != 0)) { | ||||
| 		memset(data, 0, sizeof(data)); | ||||
| 		i40e_debug(hw, mask, "AQ CMD Buffer:\n"); | ||||
| 		if (buf_len < len) | ||||
| 			len = buf_len; | ||||
| 		for (i = 0; i < len; i++) { | ||||
| 			data[((i % 16) / 4)] |= | ||||
| 				((u32)aq_buffer[i]) << (8 * (i % 4)); | ||||
| 			if ((i % 16) == 15) { | ||||
| 				i40e_debug(hw, mask, | ||||
| 					   "\t0x%04X  %08X %08X %08X %08X\n", | ||||
| 					   i - 15, data[0], data[1], data[2], | ||||
| 					   data[3]); | ||||
| 				memset(data, 0, sizeof(data)); | ||||
| 			} | ||||
| 		} | ||||
| 		if ((i % 16) != 0) | ||||
| 			i40e_debug(hw, mask, "\t0x%04X  %08X %08X %08X %08X\n", | ||||
| 				   i - (i % 16), data[0], data[1], data[2], | ||||
| 				   data[3]); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_check_asq_alive | ||||
|  * @hw: pointer to the hw struct | ||||
|  * | ||||
|  * Returns true if Queue is enabled else false. | ||||
|  **/ | ||||
| bool i40evf_check_asq_alive(struct i40e_hw *hw) | ||||
| { | ||||
| 	if (hw->aq.asq.len) | ||||
| 		return !!(rd32(hw, hw->aq.asq.len) & | ||||
| 			  I40E_PF_ATQLEN_ATQENABLE_MASK); | ||||
| 	else | ||||
| 		return false; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_aq_queue_shutdown | ||||
|  * @hw: pointer to the hw struct | ||||
|  * @unloading: is the driver unloading itself | ||||
|  * | ||||
|  * Tell the Firmware that we're shutting down the AdminQ and whether | ||||
|  * or not the driver is unloading as well. | ||||
|  **/ | ||||
| i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, | ||||
| 					     bool unloading) | ||||
| { | ||||
| 	struct i40e_aq_desc desc; | ||||
| 	struct i40e_aqc_queue_shutdown *cmd = | ||||
| 		(struct i40e_aqc_queue_shutdown *)&desc.params.raw; | ||||
| 	i40e_status status; | ||||
| 
 | ||||
| 	i40evf_fill_default_direct_cmd_desc(&desc, | ||||
| 					  i40e_aqc_opc_queue_shutdown); | ||||
| 
 | ||||
| 	if (unloading) | ||||
| 		cmd->driver_unloading = cpu_to_le32(I40E_AQ_DRIVER_UNLOADING); | ||||
| 	status = i40evf_asq_send_command(hw, &desc, NULL, 0, NULL); | ||||
| 
 | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* The i40evf_ptype_lookup table is used to convert from the 8-bit ptype in the
 | ||||
|  * hardware to a bit-field that can be used by SW to more easily determine the | ||||
|  * packet type. | ||||
|  * | ||||
|  * Macros are used to shorten the table lines and make this table human | ||||
|  * readable. | ||||
|  * | ||||
|  * We store the PTYPE in the top byte of the bit field - this is just so that | ||||
|  * we can check that the table doesn't have a row missing, as the index into | ||||
|  * the table should be the PTYPE. | ||||
|  * | ||||
|  * Typical work flow: | ||||
|  * | ||||
|  * IF NOT i40evf_ptype_lookup[ptype].known | ||||
|  * THEN | ||||
|  *      Packet is unknown | ||||
|  * ELSE IF i40evf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP | ||||
|  *      Use the rest of the fields to look at the tunnels, inner protocols, etc | ||||
|  * ELSE | ||||
|  *      Use the enum i40e_rx_l2_ptype to decode the packet type | ||||
|  * ENDIF | ||||
|  */ | ||||
| 
 | ||||
| /* macro to make the table lines short */ | ||||
| #define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\ | ||||
| 	{	PTYPE, \ | ||||
| 		1, \ | ||||
| 		I40E_RX_PTYPE_OUTER_##OUTER_IP, \ | ||||
| 		I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \ | ||||
| 		I40E_RX_PTYPE_##OUTER_FRAG, \ | ||||
| 		I40E_RX_PTYPE_TUNNEL_##T, \ | ||||
| 		I40E_RX_PTYPE_TUNNEL_END_##TE, \ | ||||
| 		I40E_RX_PTYPE_##TEF, \ | ||||
| 		I40E_RX_PTYPE_INNER_PROT_##I, \ | ||||
| 		I40E_RX_PTYPE_PAYLOAD_LAYER_##PL } | ||||
| 
 | ||||
| #define I40E_PTT_UNUSED_ENTRY(PTYPE) \ | ||||
| 		{ PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } | ||||
| 
 | ||||
| /* shorter macros makes the table fit but are terse */ | ||||
| #define I40E_RX_PTYPE_NOF		I40E_RX_PTYPE_NOT_FRAG | ||||
| #define I40E_RX_PTYPE_FRG		I40E_RX_PTYPE_FRAG | ||||
| #define I40E_RX_PTYPE_INNER_PROT_TS	I40E_RX_PTYPE_INNER_PROT_TIMESYNC | ||||
| 
 | ||||
| /* Lookup table mapping the HW PTYPE to the bit field for decoding */ | ||||
| struct i40e_rx_ptype_decoded i40evf_ptype_lookup[] = { | ||||
| 	/* L2 Packet types */ | ||||
| 	I40E_PTT_UNUSED_ENTRY(0), | ||||
| 	I40E_PTT(1,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), | ||||
| 	I40E_PTT(2,  L2, NONE, NOF, NONE, NONE, NOF, TS,   PAY2), | ||||
| 	I40E_PTT(3,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), | ||||
| 	I40E_PTT_UNUSED_ENTRY(4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(5), | ||||
| 	I40E_PTT(6,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), | ||||
| 	I40E_PTT(7,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), | ||||
| 	I40E_PTT_UNUSED_ENTRY(8), | ||||
| 	I40E_PTT_UNUSED_ENTRY(9), | ||||
| 	I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), | ||||
| 	I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), | ||||
| 	I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 
 | ||||
| 	/* Non Tunneled IPv4 */ | ||||
| 	I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(25), | ||||
| 	I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv4 --> IPv4 */ | ||||
| 	I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(32), | ||||
| 	I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv4 --> IPv6 */ | ||||
| 	I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(39), | ||||
| 	I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv4 --> GRE/NAT */ | ||||
| 	I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), | ||||
| 
 | ||||
| 	/* IPv4 --> GRE/NAT --> IPv4 */ | ||||
| 	I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(47), | ||||
| 	I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv4 --> GRE/NAT --> IPv6 */ | ||||
| 	I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(54), | ||||
| 	I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv4 --> GRE/NAT --> MAC */ | ||||
| 	I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), | ||||
| 
 | ||||
| 	/* IPv4 --> GRE/NAT --> MAC --> IPv4 */ | ||||
| 	I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(62), | ||||
| 	I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv4 --> GRE/NAT -> MAC --> IPv6 */ | ||||
| 	I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(69), | ||||
| 	I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv4 --> GRE/NAT --> MAC/VLAN */ | ||||
| 	I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), | ||||
| 
 | ||||
| 	/* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */ | ||||
| 	I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(77), | ||||
| 	I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */ | ||||
| 	I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(84), | ||||
| 	I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* Non Tunneled IPv6 */ | ||||
| 	I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP,  PAY3), | ||||
| 	I40E_PTT_UNUSED_ENTRY(91), | ||||
| 	I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv6 --> IPv4 */ | ||||
| 	I40E_PTT(95,  IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(96,  IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(97,  IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(98), | ||||
| 	I40E_PTT(99,  IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv6 --> IPv6 */ | ||||
| 	I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(105), | ||||
| 	I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv6 --> GRE/NAT */ | ||||
| 	I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), | ||||
| 
 | ||||
| 	/* IPv6 --> GRE/NAT -> IPv4 */ | ||||
| 	I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(113), | ||||
| 	I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv6 --> GRE/NAT -> IPv6 */ | ||||
| 	I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(120), | ||||
| 	I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv6 --> GRE/NAT -> MAC */ | ||||
| 	I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), | ||||
| 
 | ||||
| 	/* IPv6 --> GRE/NAT -> MAC -> IPv4 */ | ||||
| 	I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(128), | ||||
| 	I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv6 --> GRE/NAT -> MAC -> IPv6 */ | ||||
| 	I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(135), | ||||
| 	I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv6 --> GRE/NAT -> MAC/VLAN */ | ||||
| 	I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), | ||||
| 
 | ||||
| 	/* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */ | ||||
| 	I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(143), | ||||
| 	I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */ | ||||
| 	I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), | ||||
| 	I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), | ||||
| 	I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP,  PAY4), | ||||
| 	I40E_PTT_UNUSED_ENTRY(150), | ||||
| 	I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP,  PAY4), | ||||
| 	I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), | ||||
| 	I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), | ||||
| 
 | ||||
| 	/* unused entries */ | ||||
| 	I40E_PTT_UNUSED_ENTRY(154), | ||||
| 	I40E_PTT_UNUSED_ENTRY(155), | ||||
| 	I40E_PTT_UNUSED_ENTRY(156), | ||||
| 	I40E_PTT_UNUSED_ENTRY(157), | ||||
| 	I40E_PTT_UNUSED_ENTRY(158), | ||||
| 	I40E_PTT_UNUSED_ENTRY(159), | ||||
| 
 | ||||
| 	I40E_PTT_UNUSED_ENTRY(160), | ||||
| 	I40E_PTT_UNUSED_ENTRY(161), | ||||
| 	I40E_PTT_UNUSED_ENTRY(162), | ||||
| 	I40E_PTT_UNUSED_ENTRY(163), | ||||
| 	I40E_PTT_UNUSED_ENTRY(164), | ||||
| 	I40E_PTT_UNUSED_ENTRY(165), | ||||
| 	I40E_PTT_UNUSED_ENTRY(166), | ||||
| 	I40E_PTT_UNUSED_ENTRY(167), | ||||
| 	I40E_PTT_UNUSED_ENTRY(168), | ||||
| 	I40E_PTT_UNUSED_ENTRY(169), | ||||
| 
 | ||||
| 	I40E_PTT_UNUSED_ENTRY(170), | ||||
| 	I40E_PTT_UNUSED_ENTRY(171), | ||||
| 	I40E_PTT_UNUSED_ENTRY(172), | ||||
| 	I40E_PTT_UNUSED_ENTRY(173), | ||||
| 	I40E_PTT_UNUSED_ENTRY(174), | ||||
| 	I40E_PTT_UNUSED_ENTRY(175), | ||||
| 	I40E_PTT_UNUSED_ENTRY(176), | ||||
| 	I40E_PTT_UNUSED_ENTRY(177), | ||||
| 	I40E_PTT_UNUSED_ENTRY(178), | ||||
| 	I40E_PTT_UNUSED_ENTRY(179), | ||||
| 
 | ||||
| 	I40E_PTT_UNUSED_ENTRY(180), | ||||
| 	I40E_PTT_UNUSED_ENTRY(181), | ||||
| 	I40E_PTT_UNUSED_ENTRY(182), | ||||
| 	I40E_PTT_UNUSED_ENTRY(183), | ||||
| 	I40E_PTT_UNUSED_ENTRY(184), | ||||
| 	I40E_PTT_UNUSED_ENTRY(185), | ||||
| 	I40E_PTT_UNUSED_ENTRY(186), | ||||
| 	I40E_PTT_UNUSED_ENTRY(187), | ||||
| 	I40E_PTT_UNUSED_ENTRY(188), | ||||
| 	I40E_PTT_UNUSED_ENTRY(189), | ||||
| 
 | ||||
| 	I40E_PTT_UNUSED_ENTRY(190), | ||||
| 	I40E_PTT_UNUSED_ENTRY(191), | ||||
| 	I40E_PTT_UNUSED_ENTRY(192), | ||||
| 	I40E_PTT_UNUSED_ENTRY(193), | ||||
| 	I40E_PTT_UNUSED_ENTRY(194), | ||||
| 	I40E_PTT_UNUSED_ENTRY(195), | ||||
| 	I40E_PTT_UNUSED_ENTRY(196), | ||||
| 	I40E_PTT_UNUSED_ENTRY(197), | ||||
| 	I40E_PTT_UNUSED_ENTRY(198), | ||||
| 	I40E_PTT_UNUSED_ENTRY(199), | ||||
| 
 | ||||
| 	I40E_PTT_UNUSED_ENTRY(200), | ||||
| 	I40E_PTT_UNUSED_ENTRY(201), | ||||
| 	I40E_PTT_UNUSED_ENTRY(202), | ||||
| 	I40E_PTT_UNUSED_ENTRY(203), | ||||
| 	I40E_PTT_UNUSED_ENTRY(204), | ||||
| 	I40E_PTT_UNUSED_ENTRY(205), | ||||
| 	I40E_PTT_UNUSED_ENTRY(206), | ||||
| 	I40E_PTT_UNUSED_ENTRY(207), | ||||
| 	I40E_PTT_UNUSED_ENTRY(208), | ||||
| 	I40E_PTT_UNUSED_ENTRY(209), | ||||
| 
 | ||||
| 	I40E_PTT_UNUSED_ENTRY(210), | ||||
| 	I40E_PTT_UNUSED_ENTRY(211), | ||||
| 	I40E_PTT_UNUSED_ENTRY(212), | ||||
| 	I40E_PTT_UNUSED_ENTRY(213), | ||||
| 	I40E_PTT_UNUSED_ENTRY(214), | ||||
| 	I40E_PTT_UNUSED_ENTRY(215), | ||||
| 	I40E_PTT_UNUSED_ENTRY(216), | ||||
| 	I40E_PTT_UNUSED_ENTRY(217), | ||||
| 	I40E_PTT_UNUSED_ENTRY(218), | ||||
| 	I40E_PTT_UNUSED_ENTRY(219), | ||||
| 
 | ||||
| 	I40E_PTT_UNUSED_ENTRY(220), | ||||
| 	I40E_PTT_UNUSED_ENTRY(221), | ||||
| 	I40E_PTT_UNUSED_ENTRY(222), | ||||
| 	I40E_PTT_UNUSED_ENTRY(223), | ||||
| 	I40E_PTT_UNUSED_ENTRY(224), | ||||
| 	I40E_PTT_UNUSED_ENTRY(225), | ||||
| 	I40E_PTT_UNUSED_ENTRY(226), | ||||
| 	I40E_PTT_UNUSED_ENTRY(227), | ||||
| 	I40E_PTT_UNUSED_ENTRY(228), | ||||
| 	I40E_PTT_UNUSED_ENTRY(229), | ||||
| 
 | ||||
| 	I40E_PTT_UNUSED_ENTRY(230), | ||||
| 	I40E_PTT_UNUSED_ENTRY(231), | ||||
| 	I40E_PTT_UNUSED_ENTRY(232), | ||||
| 	I40E_PTT_UNUSED_ENTRY(233), | ||||
| 	I40E_PTT_UNUSED_ENTRY(234), | ||||
| 	I40E_PTT_UNUSED_ENTRY(235), | ||||
| 	I40E_PTT_UNUSED_ENTRY(236), | ||||
| 	I40E_PTT_UNUSED_ENTRY(237), | ||||
| 	I40E_PTT_UNUSED_ENTRY(238), | ||||
| 	I40E_PTT_UNUSED_ENTRY(239), | ||||
| 
 | ||||
| 	I40E_PTT_UNUSED_ENTRY(240), | ||||
| 	I40E_PTT_UNUSED_ENTRY(241), | ||||
| 	I40E_PTT_UNUSED_ENTRY(242), | ||||
| 	I40E_PTT_UNUSED_ENTRY(243), | ||||
| 	I40E_PTT_UNUSED_ENTRY(244), | ||||
| 	I40E_PTT_UNUSED_ENTRY(245), | ||||
| 	I40E_PTT_UNUSED_ENTRY(246), | ||||
| 	I40E_PTT_UNUSED_ENTRY(247), | ||||
| 	I40E_PTT_UNUSED_ENTRY(248), | ||||
| 	I40E_PTT_UNUSED_ENTRY(249), | ||||
| 
 | ||||
| 	I40E_PTT_UNUSED_ENTRY(250), | ||||
| 	I40E_PTT_UNUSED_ENTRY(251), | ||||
| 	I40E_PTT_UNUSED_ENTRY(252), | ||||
| 	I40E_PTT_UNUSED_ENTRY(253), | ||||
| 	I40E_PTT_UNUSED_ENTRY(254), | ||||
| 	I40E_PTT_UNUSED_ENTRY(255) | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * i40e_aq_send_msg_to_pf | ||||
|  * @hw: pointer to the hardware structure | ||||
|  * @v_opcode: opcodes for VF-PF communication | ||||
|  * @v_retval: return error code | ||||
|  * @msg: pointer to the msg buffer | ||||
|  * @msglen: msg length | ||||
|  * @cmd_details: pointer to command details | ||||
|  * | ||||
|  * Send message to PF driver using admin queue. By default, this message | ||||
|  * is sent asynchronously, i.e. i40evf_asq_send_command() does not wait for | ||||
|  * completion before returning. | ||||
|  **/ | ||||
| i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, | ||||
| 				enum i40e_virtchnl_ops v_opcode, | ||||
| 				i40e_status v_retval, | ||||
| 				u8 *msg, u16 msglen, | ||||
| 				struct i40e_asq_cmd_details *cmd_details) | ||||
| { | ||||
| 	struct i40e_aq_desc desc; | ||||
| 	struct i40e_asq_cmd_details details; | ||||
| 	i40e_status status; | ||||
| 
 | ||||
| 	i40evf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_send_msg_to_pf); | ||||
| 	desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_SI); | ||||
| 	desc.cookie_high = cpu_to_le32(v_opcode); | ||||
| 	desc.cookie_low = cpu_to_le32(v_retval); | ||||
| 	if (msglen) { | ||||
| 		desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | ||||
| 						| I40E_AQ_FLAG_RD)); | ||||
| 		if (msglen > I40E_AQ_LARGE_BUF) | ||||
| 			desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB); | ||||
| 		desc.datalen = cpu_to_le16(msglen); | ||||
| 	} | ||||
| 	if (!cmd_details) { | ||||
| 		memset(&details, 0, sizeof(details)); | ||||
| 		details.async = true; | ||||
| 		cmd_details = &details; | ||||
| 	} | ||||
| 	status = i40evf_asq_send_command(hw, &desc, msg, msglen, cmd_details); | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40e_vf_parse_hw_config | ||||
|  * @hw: pointer to the hardware structure | ||||
|  * @msg: pointer to the virtual channel VF resource structure | ||||
|  * | ||||
|  * Given a VF resource message from the PF, populate the hw struct | ||||
|  * with appropriate information. | ||||
|  **/ | ||||
| void i40e_vf_parse_hw_config(struct i40e_hw *hw, | ||||
| 			     struct i40e_virtchnl_vf_resource *msg) | ||||
| { | ||||
| 	struct i40e_virtchnl_vsi_resource *vsi_res; | ||||
| 	int i; | ||||
| 
 | ||||
| 	vsi_res = &msg->vsi_res[0]; | ||||
| 
 | ||||
| 	hw->dev_caps.num_vsis = msg->num_vsis; | ||||
| 	hw->dev_caps.num_rx_qp = msg->num_queue_pairs; | ||||
| 	hw->dev_caps.num_tx_qp = msg->num_queue_pairs; | ||||
| 	hw->dev_caps.num_msix_vectors_vf = msg->max_vectors; | ||||
| 	hw->dev_caps.dcb = msg->vf_offload_flags & | ||||
| 			   I40E_VIRTCHNL_VF_OFFLOAD_L2; | ||||
| 	hw->dev_caps.fcoe = (msg->vf_offload_flags & | ||||
| 			     I40E_VIRTCHNL_VF_OFFLOAD_FCOE) ? 1 : 0; | ||||
| 	for (i = 0; i < msg->num_vsis; i++) { | ||||
| 		if (vsi_res->vsi_type == I40E_VSI_SRIOV) { | ||||
| 			memcpy(hw->mac.perm_addr, vsi_res->default_mac_addr, | ||||
| 			       ETH_ALEN); | ||||
| 			memcpy(hw->mac.addr, vsi_res->default_mac_addr, | ||||
| 			       ETH_ALEN); | ||||
| 		} | ||||
| 		vsi_res++; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40e_vf_reset | ||||
|  * @hw: pointer to the hardware structure | ||||
|  * | ||||
|  * Send a VF_RESET message to the PF. Does not wait for response from PF | ||||
|  * as none will be forthcoming. Immediately after calling this function, | ||||
|  * the admin queue should be shut down and (optionally) reinitialized. | ||||
|  **/ | ||||
| i40e_status i40e_vf_reset(struct i40e_hw *hw) | ||||
| { | ||||
| 	return i40e_aq_send_msg_to_pf(hw, I40E_VIRTCHNL_OP_RESET_VF, | ||||
| 				      0, NULL, 0, NULL); | ||||
| } | ||||
							
								
								
									
										236
									
								
								drivers/net/ethernet/intel/i40evf/i40e_hmc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								drivers/net/ethernet/intel/i40evf/i40e_hmc.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,236 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #ifndef _I40E_HMC_H_ | ||||
| #define _I40E_HMC_H_ | ||||
| 
 | ||||
| #define I40E_HMC_MAX_BP_COUNT 512 | ||||
| 
 | ||||
| /* forward-declare the HW struct for the compiler */ | ||||
| struct i40e_hw; | ||||
| 
 | ||||
| #define I40E_HMC_INFO_SIGNATURE		0x484D5347 /* HMSG */ | ||||
| #define I40E_HMC_PD_CNT_IN_SD		512 | ||||
| #define I40E_HMC_DIRECT_BP_SIZE		0x200000 /* 2M */ | ||||
| #define I40E_HMC_PAGED_BP_SIZE		4096 | ||||
| #define I40E_HMC_PD_BP_BUF_ALIGNMENT	4096 | ||||
| #define I40E_FIRST_VF_FPM_ID		16 | ||||
| 
 | ||||
| struct i40e_hmc_obj_info { | ||||
| 	u64 base;	/* base addr in FPM */ | ||||
| 	u32 max_cnt;	/* max count available for this hmc func */ | ||||
| 	u32 cnt;	/* count of objects driver actually wants to create */ | ||||
| 	u64 size;	/* size in bytes of one object */ | ||||
| }; | ||||
| 
 | ||||
| enum i40e_sd_entry_type { | ||||
| 	I40E_SD_TYPE_INVALID = 0, | ||||
| 	I40E_SD_TYPE_PAGED   = 1, | ||||
| 	I40E_SD_TYPE_DIRECT  = 2 | ||||
| }; | ||||
| 
 | ||||
| struct i40e_hmc_bp { | ||||
| 	enum i40e_sd_entry_type entry_type; | ||||
| 	struct i40e_dma_mem addr; /* populate to be used by hw */ | ||||
| 	u32 sd_pd_index; | ||||
| 	u32 ref_cnt; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_hmc_pd_entry { | ||||
| 	struct i40e_hmc_bp bp; | ||||
| 	u32 sd_index; | ||||
| 	bool valid; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_hmc_pd_table { | ||||
| 	struct i40e_dma_mem pd_page_addr; /* populate to be used by hw */ | ||||
| 	struct i40e_hmc_pd_entry  *pd_entry; /* [512] for sw book keeping */ | ||||
| 	struct i40e_virt_mem pd_entry_virt_mem; /* virt mem for pd_entry */ | ||||
| 
 | ||||
| 	u32 ref_cnt; | ||||
| 	u32 sd_index; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_hmc_sd_entry { | ||||
| 	enum i40e_sd_entry_type entry_type; | ||||
| 	bool valid; | ||||
| 
 | ||||
| 	union { | ||||
| 		struct i40e_hmc_pd_table pd_table; | ||||
| 		struct i40e_hmc_bp bp; | ||||
| 	} u; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_hmc_sd_table { | ||||
| 	struct i40e_virt_mem addr; /* used to track sd_entry allocations */ | ||||
| 	u32 sd_cnt; | ||||
| 	u32 ref_cnt; | ||||
| 	struct i40e_hmc_sd_entry *sd_entry; /* (sd_cnt*512) entries max */ | ||||
| }; | ||||
| 
 | ||||
| struct i40e_hmc_info { | ||||
| 	u32 signature; | ||||
| 	/* equals to pci func num for PF and dynamically allocated for VFs */ | ||||
| 	u8 hmc_fn_id; | ||||
| 	u16 first_sd_index; /* index of the first available SD */ | ||||
| 
 | ||||
| 	/* hmc objects */ | ||||
| 	struct i40e_hmc_obj_info *hmc_obj; | ||||
| 	struct i40e_virt_mem hmc_obj_virt_mem; | ||||
| 	struct i40e_hmc_sd_table sd_table; | ||||
| }; | ||||
| 
 | ||||
| #define I40E_INC_SD_REFCNT(sd_table)	((sd_table)->ref_cnt++) | ||||
| #define I40E_INC_PD_REFCNT(pd_table)	((pd_table)->ref_cnt++) | ||||
| #define I40E_INC_BP_REFCNT(bp)		((bp)->ref_cnt++) | ||||
| 
 | ||||
| #define I40E_DEC_SD_REFCNT(sd_table)	((sd_table)->ref_cnt--) | ||||
| #define I40E_DEC_PD_REFCNT(pd_table)	((pd_table)->ref_cnt--) | ||||
| #define I40E_DEC_BP_REFCNT(bp)		((bp)->ref_cnt--) | ||||
| 
 | ||||
| /**
 | ||||
|  * I40E_SET_PF_SD_ENTRY - marks the sd entry as valid in the hardware | ||||
|  * @hw: pointer to our hw struct | ||||
|  * @pa: pointer to physical address | ||||
|  * @sd_index: segment descriptor index | ||||
|  * @type: if sd entry is direct or paged | ||||
|  **/ | ||||
| #define I40E_SET_PF_SD_ENTRY(hw, pa, sd_index, type)			\ | ||||
| {									\ | ||||
| 	u32 val1, val2, val3;						\ | ||||
| 	val1 = (u32)(upper_32_bits(pa));				\ | ||||
| 	val2 = (u32)(pa) | (I40E_HMC_MAX_BP_COUNT <<			\ | ||||
| 		 I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) |		\ | ||||
| 		((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) <<		\ | ||||
| 		I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) |			\ | ||||
| 		(1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT);		\ | ||||
| 	val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT);	\ | ||||
| 	wr32((hw), I40E_PFHMC_SDDATAHIGH, val1);			\ | ||||
| 	wr32((hw), I40E_PFHMC_SDDATALOW, val2);				\ | ||||
| 	wr32((hw), I40E_PFHMC_SDCMD, val3);				\ | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * I40E_CLEAR_PF_SD_ENTRY - marks the sd entry as invalid in the hardware | ||||
|  * @hw: pointer to our hw struct | ||||
|  * @sd_index: segment descriptor index | ||||
|  * @type: if sd entry is direct or paged | ||||
|  **/ | ||||
| #define I40E_CLEAR_PF_SD_ENTRY(hw, sd_index, type)			\ | ||||
| {									\ | ||||
| 	u32 val2, val3;							\ | ||||
| 	val2 = (I40E_HMC_MAX_BP_COUNT <<				\ | ||||
| 		I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) |		\ | ||||
| 		((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) <<		\ | ||||
| 		I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT);			\ | ||||
| 	val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT);	\ | ||||
| 	wr32((hw), I40E_PFHMC_SDDATAHIGH, 0);				\ | ||||
| 	wr32((hw), I40E_PFHMC_SDDATALOW, val2);				\ | ||||
| 	wr32((hw), I40E_PFHMC_SDCMD, val3);				\ | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * I40E_INVALIDATE_PF_HMC_PD - Invalidates the pd cache in the hardware | ||||
|  * @hw: pointer to our hw struct | ||||
|  * @sd_idx: segment descriptor index | ||||
|  * @pd_idx: page descriptor index | ||||
|  **/ | ||||
| #define I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, pd_idx)			\ | ||||
| 	wr32((hw), I40E_PFHMC_PDINV,					\ | ||||
| 	    (((sd_idx) << I40E_PFHMC_PDINV_PMSDIDX_SHIFT) |		\ | ||||
| 	     ((pd_idx) << I40E_PFHMC_PDINV_PMPDIDX_SHIFT))) | ||||
| 
 | ||||
| /**
 | ||||
|  * I40E_FIND_SD_INDEX_LIMIT - finds segment descriptor index limit | ||||
|  * @hmc_info: pointer to the HMC configuration information structure | ||||
|  * @type: type of HMC resources we're searching | ||||
|  * @index: starting index for the object | ||||
|  * @cnt: number of objects we're trying to create | ||||
|  * @sd_idx: pointer to return index of the segment descriptor in question | ||||
|  * @sd_limit: pointer to return the maximum number of segment descriptors | ||||
|  * | ||||
|  * This function calculates the segment descriptor index and index limit | ||||
|  * for the resource defined by i40e_hmc_rsrc_type. | ||||
|  **/ | ||||
| #define I40E_FIND_SD_INDEX_LIMIT(hmc_info, type, index, cnt, sd_idx, sd_limit)\ | ||||
| {									\ | ||||
| 	u64 fpm_addr, fpm_limit;					\ | ||||
| 	fpm_addr = (hmc_info)->hmc_obj[(type)].base +			\ | ||||
| 		   (hmc_info)->hmc_obj[(type)].size * (index);		\ | ||||
| 	fpm_limit = fpm_addr + (hmc_info)->hmc_obj[(type)].size * (cnt);\ | ||||
| 	*(sd_idx) = (u32)(fpm_addr / I40E_HMC_DIRECT_BP_SIZE);		\ | ||||
| 	*(sd_limit) = (u32)((fpm_limit - 1) / I40E_HMC_DIRECT_BP_SIZE);	\ | ||||
| 	/* add one more to the limit to correct our range */		\ | ||||
| 	*(sd_limit) += 1;						\ | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * I40E_FIND_PD_INDEX_LIMIT - finds page descriptor index limit | ||||
|  * @hmc_info: pointer to the HMC configuration information struct | ||||
|  * @type: HMC resource type we're examining | ||||
|  * @idx: starting index for the object | ||||
|  * @cnt: number of objects we're trying to create | ||||
|  * @pd_index: pointer to return page descriptor index | ||||
|  * @pd_limit: pointer to return page descriptor index limit | ||||
|  * | ||||
|  * Calculates the page descriptor index and index limit for the resource | ||||
|  * defined by i40e_hmc_rsrc_type. | ||||
|  **/ | ||||
| #define I40E_FIND_PD_INDEX_LIMIT(hmc_info, type, idx, cnt, pd_index, pd_limit)\ | ||||
| {									\ | ||||
| 	u64 fpm_adr, fpm_limit;						\ | ||||
| 	fpm_adr = (hmc_info)->hmc_obj[(type)].base +			\ | ||||
| 		  (hmc_info)->hmc_obj[(type)].size * (idx);		\ | ||||
| 	fpm_limit = fpm_adr + (hmc_info)->hmc_obj[(type)].size * (cnt);	\ | ||||
| 	*(pd_index) = (u32)(fpm_adr / I40E_HMC_PAGED_BP_SIZE);		\ | ||||
| 	*(pd_limit) = (u32)((fpm_limit - 1) / I40E_HMC_PAGED_BP_SIZE);	\ | ||||
| 	/* add one more to the limit to correct our range */		\ | ||||
| 	*(pd_limit) += 1;						\ | ||||
| } | ||||
| i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw, | ||||
| 					      struct i40e_hmc_info *hmc_info, | ||||
| 					      u32 sd_index, | ||||
| 					      enum i40e_sd_entry_type type, | ||||
| 					      u64 direct_mode_sz); | ||||
| 
 | ||||
| i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, | ||||
| 					      struct i40e_hmc_info *hmc_info, | ||||
| 					      u32 pd_index); | ||||
| i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, | ||||
| 					struct i40e_hmc_info *hmc_info, | ||||
| 					u32 idx); | ||||
| i40e_status i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info, | ||||
| 					     u32 idx); | ||||
| i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw, | ||||
| 					    struct i40e_hmc_info *hmc_info, | ||||
| 					    u32 idx, bool is_pf); | ||||
| i40e_status i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info, | ||||
| 					       u32 idx); | ||||
| i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw, | ||||
| 					      struct i40e_hmc_info *hmc_info, | ||||
| 					      u32 idx, bool is_pf); | ||||
| 
 | ||||
| #endif /* _I40E_HMC_H_ */ | ||||
							
								
								
									
										181
									
								
								drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,181 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #ifndef _I40E_LAN_HMC_H_ | ||||
| #define _I40E_LAN_HMC_H_ | ||||
| 
 | ||||
| /* forward-declare the HW struct for the compiler */ | ||||
| struct i40e_hw; | ||||
| 
 | ||||
| /* HMC element context information */ | ||||
| 
 | ||||
| /* Rx queue context data
 | ||||
|  * | ||||
|  * The sizes of the variables may be larger than needed due to crossing byte | ||||
|  * boundaries. If we do not have the width of the variable set to the correct | ||||
|  * size then we could end up shifting bits off the top of the variable when the | ||||
|  * variable is at the top of a byte and crosses over into the next byte. | ||||
|  */ | ||||
| struct i40e_hmc_obj_rxq { | ||||
| 	u16 head; | ||||
| 	u16 cpuid; /* bigger than needed, see above for reason */ | ||||
| 	u64 base; | ||||
| 	u16 qlen; | ||||
| #define I40E_RXQ_CTX_DBUFF_SHIFT 7 | ||||
| 	u16 dbuff; /* bigger than needed, see above for reason */ | ||||
| #define I40E_RXQ_CTX_HBUFF_SHIFT 6 | ||||
| 	u16 hbuff; /* bigger than needed, see above for reason */ | ||||
| 	u8  dtype; | ||||
| 	u8  dsize; | ||||
| 	u8  crcstrip; | ||||
| 	u8  fc_ena; | ||||
| 	u8  l2tsel; | ||||
| 	u8  hsplit_0; | ||||
| 	u8  hsplit_1; | ||||
| 	u8  showiv; | ||||
| 	u32 rxmax; /* bigger than needed, see above for reason */ | ||||
| 	u8  tphrdesc_ena; | ||||
| 	u8  tphwdesc_ena; | ||||
| 	u8  tphdata_ena; | ||||
| 	u8  tphhead_ena; | ||||
| 	u16 lrxqthresh; /* bigger than needed, see above for reason */ | ||||
| 	u8  prefena;	/* NOTE: normally must be set to 1 at init */ | ||||
| }; | ||||
| 
 | ||||
| /* Tx queue context data
 | ||||
| * | ||||
| * The sizes of the variables may be larger than needed due to crossing byte | ||||
| * boundaries. If we do not have the width of the variable set to the correct | ||||
| * size then we could end up shifting bits off the top of the variable when the | ||||
| * variable is at the top of a byte and crosses over into the next byte. | ||||
| */ | ||||
| struct i40e_hmc_obj_txq { | ||||
| 	u16 head; | ||||
| 	u8  new_context; | ||||
| 	u64 base; | ||||
| 	u8  fc_ena; | ||||
| 	u8  timesync_ena; | ||||
| 	u8  fd_ena; | ||||
| 	u8  alt_vlan_ena; | ||||
| 	u16 thead_wb; | ||||
| 	u8  cpuid; | ||||
| 	u8  head_wb_ena; | ||||
| 	u16 qlen; | ||||
| 	u8  tphrdesc_ena; | ||||
| 	u8  tphrpacket_ena; | ||||
| 	u8  tphwdesc_ena; | ||||
| 	u64 head_wb_addr; | ||||
| 	u32 crc; | ||||
| 	u16 rdylist; | ||||
| 	u8  rdylist_act; | ||||
| }; | ||||
| 
 | ||||
| /* for hsplit_0 field of Rx HMC context */ | ||||
| enum i40e_hmc_obj_rx_hsplit_0 { | ||||
| 	I40E_HMC_OBJ_RX_HSPLIT_0_NO_SPLIT      = 0, | ||||
| 	I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2      = 1, | ||||
| 	I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP      = 2, | ||||
| 	I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP = 4, | ||||
| 	I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP    = 8, | ||||
| }; | ||||
| 
 | ||||
| /* fcoe_cntx and fcoe_filt are for debugging purpose only */ | ||||
| struct i40e_hmc_obj_fcoe_cntx { | ||||
| 	u32 rsv[32]; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_hmc_obj_fcoe_filt { | ||||
| 	u32 rsv[8]; | ||||
| }; | ||||
| 
 | ||||
| /* Context sizes for LAN objects */ | ||||
| enum i40e_hmc_lan_object_size { | ||||
| 	I40E_HMC_LAN_OBJ_SZ_8   = 0x3, | ||||
| 	I40E_HMC_LAN_OBJ_SZ_16  = 0x4, | ||||
| 	I40E_HMC_LAN_OBJ_SZ_32  = 0x5, | ||||
| 	I40E_HMC_LAN_OBJ_SZ_64  = 0x6, | ||||
| 	I40E_HMC_LAN_OBJ_SZ_128 = 0x7, | ||||
| 	I40E_HMC_LAN_OBJ_SZ_256 = 0x8, | ||||
| 	I40E_HMC_LAN_OBJ_SZ_512 = 0x9, | ||||
| }; | ||||
| 
 | ||||
| #define I40E_HMC_L2OBJ_BASE_ALIGNMENT 512 | ||||
| #define I40E_HMC_OBJ_SIZE_TXQ         128 | ||||
| #define I40E_HMC_OBJ_SIZE_RXQ         32 | ||||
| #define I40E_HMC_OBJ_SIZE_FCOE_CNTX   128 | ||||
| #define I40E_HMC_OBJ_SIZE_FCOE_FILT   64 | ||||
| 
 | ||||
| enum i40e_hmc_lan_rsrc_type { | ||||
| 	I40E_HMC_LAN_FULL  = 0, | ||||
| 	I40E_HMC_LAN_TX    = 1, | ||||
| 	I40E_HMC_LAN_RX    = 2, | ||||
| 	I40E_HMC_FCOE_CTX  = 3, | ||||
| 	I40E_HMC_FCOE_FILT = 4, | ||||
| 	I40E_HMC_LAN_MAX   = 5 | ||||
| }; | ||||
| 
 | ||||
| enum i40e_hmc_model { | ||||
| 	I40E_HMC_MODEL_DIRECT_PREFERRED = 0, | ||||
| 	I40E_HMC_MODEL_DIRECT_ONLY      = 1, | ||||
| 	I40E_HMC_MODEL_PAGED_ONLY       = 2, | ||||
| 	I40E_HMC_MODEL_UNKNOWN, | ||||
| }; | ||||
| 
 | ||||
| struct i40e_hmc_lan_create_obj_info { | ||||
| 	struct i40e_hmc_info *hmc_info; | ||||
| 	u32 rsrc_type; | ||||
| 	u32 start_idx; | ||||
| 	u32 count; | ||||
| 	enum i40e_sd_entry_type entry_type; | ||||
| 	u64 direct_mode_sz; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_hmc_lan_delete_obj_info { | ||||
| 	struct i40e_hmc_info *hmc_info; | ||||
| 	u32 rsrc_type; | ||||
| 	u32 start_idx; | ||||
| 	u32 count; | ||||
| }; | ||||
| 
 | ||||
| i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num, | ||||
| 					u32 rxq_num, u32 fcoe_cntx_num, | ||||
| 					u32 fcoe_filt_num); | ||||
| i40e_status i40e_configure_lan_hmc(struct i40e_hw *hw, | ||||
| 					     enum i40e_hmc_model model); | ||||
| i40e_status i40e_shutdown_lan_hmc(struct i40e_hw *hw); | ||||
| 
 | ||||
| i40e_status i40e_clear_lan_tx_queue_context(struct i40e_hw *hw, | ||||
| 						      u16 queue); | ||||
| i40e_status i40e_set_lan_tx_queue_context(struct i40e_hw *hw, | ||||
| 						    u16 queue, | ||||
| 						    struct i40e_hmc_obj_txq *s); | ||||
| i40e_status i40e_clear_lan_rx_queue_context(struct i40e_hw *hw, | ||||
| 						      u16 queue); | ||||
| i40e_status i40e_set_lan_rx_queue_context(struct i40e_hw *hw, | ||||
| 						    u16 queue, | ||||
| 						    struct i40e_hmc_obj_rxq *s); | ||||
| 
 | ||||
| #endif /* _I40E_LAN_HMC_H_ */ | ||||
							
								
								
									
										75
									
								
								drivers/net/ethernet/intel/i40evf/i40e_osdep.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								drivers/net/ethernet/intel/i40evf/i40e_osdep.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,75 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #ifndef _I40E_OSDEP_H_ | ||||
| #define _I40E_OSDEP_H_ | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| #include <linux/if_ether.h> | ||||
| #include <linux/if_vlan.h> | ||||
| #include <linux/tcp.h> | ||||
| #include <linux/pci.h> | ||||
| 
 | ||||
| /* get readq/writeq support for 32 bit kernels, use the low-first version */ | ||||
| #include <asm-generic/io-64-nonatomic-lo-hi.h> | ||||
| 
 | ||||
| /* File to be the magic between shared code and
 | ||||
|  * actual OS primitives | ||||
|  */ | ||||
| 
 | ||||
| #define hw_dbg(hw, S, A...)	do {} while (0) | ||||
| 
 | ||||
| #define wr32(a, reg, value)	writel((value), ((a)->hw_addr + (reg))) | ||||
| #define rd32(a, reg)		readl((a)->hw_addr + (reg)) | ||||
| 
 | ||||
| #define wr64(a, reg, value)	writeq((value), ((a)->hw_addr + (reg))) | ||||
| #define rd64(a, reg)		readq((a)->hw_addr + (reg)) | ||||
| #define i40e_flush(a)		readl((a)->hw_addr + I40E_VFGEN_RSTAT) | ||||
| 
 | ||||
| /* memory allocation tracking */ | ||||
| struct i40e_dma_mem { | ||||
| 	void *va; | ||||
| 	dma_addr_t pa; | ||||
| 	u32 size; | ||||
| } __packed; | ||||
| 
 | ||||
| #define i40e_allocate_dma_mem(h, m, unused, s, a) \ | ||||
| 	i40evf_allocate_dma_mem_d(h, m, s, a) | ||||
| #define i40e_free_dma_mem(h, m) i40evf_free_dma_mem_d(h, m) | ||||
| 
 | ||||
| struct i40e_virt_mem { | ||||
| 	void *va; | ||||
| 	u32 size; | ||||
| } __packed; | ||||
| #define i40e_allocate_virt_mem(h, m, s) i40evf_allocate_virt_mem_d(h, m, s) | ||||
| #define i40e_free_virt_mem(h, m) i40evf_free_virt_mem_d(h, m) | ||||
| 
 | ||||
| #define i40e_debug(h, m, s, ...)  i40evf_debug_d(h, m, s, ##__VA_ARGS__) | ||||
| extern void i40evf_debug_d(void *hw, u32 mask, char *fmt_str, ...) | ||||
| 	__attribute__ ((format(gnu_printf, 3, 4))); | ||||
| 
 | ||||
| typedef enum i40e_status_code i40e_status; | ||||
| #endif /* _I40E_OSDEP_H_ */ | ||||
							
								
								
									
										92
									
								
								drivers/net/ethernet/intel/i40evf/i40e_prototype.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								drivers/net/ethernet/intel/i40evf/i40e_prototype.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #ifndef _I40E_PROTOTYPE_H_ | ||||
| #define _I40E_PROTOTYPE_H_ | ||||
| 
 | ||||
| #include "i40e_type.h" | ||||
| #include "i40e_alloc.h" | ||||
| #include "i40e_virtchnl.h" | ||||
| 
 | ||||
| /* Prototypes for shared code functions that are not in
 | ||||
|  * the standard function pointer structures.  These are | ||||
|  * mostly because they are needed even before the init | ||||
|  * has happened and will assist in the early SW and FW | ||||
|  * setup. | ||||
|  */ | ||||
| 
 | ||||
| /* adminq functions */ | ||||
| i40e_status i40evf_init_adminq(struct i40e_hw *hw); | ||||
| i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw); | ||||
| void i40e_adminq_init_ring_data(struct i40e_hw *hw); | ||||
| i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, | ||||
| 					     struct i40e_arq_event_info *e, | ||||
| 					     u16 *events_pending); | ||||
| i40e_status i40evf_asq_send_command(struct i40e_hw *hw, | ||||
| 				struct i40e_aq_desc *desc, | ||||
| 				void *buff, /* can be NULL */ | ||||
| 				u16  buff_size, | ||||
| 				struct i40e_asq_cmd_details *cmd_details); | ||||
| bool i40evf_asq_done(struct i40e_hw *hw); | ||||
| 
 | ||||
| /* debug function for adminq */ | ||||
| void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, | ||||
| 		     void *desc, void *buffer, u16 buf_len); | ||||
| 
 | ||||
| void i40e_idle_aq(struct i40e_hw *hw); | ||||
| void i40evf_resume_aq(struct i40e_hw *hw); | ||||
| bool i40evf_check_asq_alive(struct i40e_hw *hw); | ||||
| i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, | ||||
| 					     bool unloading); | ||||
| 
 | ||||
| i40e_status i40e_set_mac_type(struct i40e_hw *hw); | ||||
| 
 | ||||
| extern struct i40e_rx_ptype_decoded i40evf_ptype_lookup[]; | ||||
| 
 | ||||
| static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) | ||||
| { | ||||
| 	return i40evf_ptype_lookup[ptype]; | ||||
| } | ||||
| 
 | ||||
| /* prototype for functions used for SW locks */ | ||||
| 
 | ||||
| /* i40e_common for VF drivers*/ | ||||
| void i40e_vf_parse_hw_config(struct i40e_hw *hw, | ||||
| 			     struct i40e_virtchnl_vf_resource *msg); | ||||
| i40e_status i40e_vf_reset(struct i40e_hw *hw); | ||||
| i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, | ||||
| 				enum i40e_virtchnl_ops v_opcode, | ||||
| 				i40e_status v_retval, | ||||
| 				u8 *msg, u16 msglen, | ||||
| 				struct i40e_asq_cmd_details *cmd_details); | ||||
| i40e_status i40e_set_filter_control(struct i40e_hw *hw, | ||||
| 				struct i40e_filter_control_settings *settings); | ||||
| i40e_status i40e_aq_add_rem_control_packet_filter(struct i40e_hw *hw, | ||||
| 				u8 *mac_addr, u16 ethtype, u16 flags, | ||||
| 				u16 vsi_seid, u16 queue, bool is_add, | ||||
| 				struct i40e_control_filter_stats *stats, | ||||
| 				struct i40e_asq_cmd_details *cmd_details); | ||||
| #endif /* _I40E_PROTOTYPE_H_ */ | ||||
							
								
								
									
										3369
									
								
								drivers/net/ethernet/intel/i40evf/i40e_register.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3369
									
								
								drivers/net/ethernet/intel/i40evf/i40e_register.h
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										100
									
								
								drivers/net/ethernet/intel/i40evf/i40e_status.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								drivers/net/ethernet/intel/i40evf/i40e_status.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #ifndef _I40E_STATUS_H_ | ||||
| #define _I40E_STATUS_H_ | ||||
| 
 | ||||
| /* Error Codes */ | ||||
| enum i40e_status_code { | ||||
| 	I40E_SUCCESS				= 0, | ||||
| 	I40E_ERR_NVM				= -1, | ||||
| 	I40E_ERR_NVM_CHECKSUM			= -2, | ||||
| 	I40E_ERR_PHY				= -3, | ||||
| 	I40E_ERR_CONFIG				= -4, | ||||
| 	I40E_ERR_PARAM				= -5, | ||||
| 	I40E_ERR_MAC_TYPE			= -6, | ||||
| 	I40E_ERR_UNKNOWN_PHY			= -7, | ||||
| 	I40E_ERR_LINK_SETUP			= -8, | ||||
| 	I40E_ERR_ADAPTER_STOPPED		= -9, | ||||
| 	I40E_ERR_INVALID_MAC_ADDR		= -10, | ||||
| 	I40E_ERR_DEVICE_NOT_SUPPORTED		= -11, | ||||
| 	I40E_ERR_MASTER_REQUESTS_PENDING	= -12, | ||||
| 	I40E_ERR_INVALID_LINK_SETTINGS		= -13, | ||||
| 	I40E_ERR_AUTONEG_NOT_COMPLETE		= -14, | ||||
| 	I40E_ERR_RESET_FAILED			= -15, | ||||
| 	I40E_ERR_SWFW_SYNC			= -16, | ||||
| 	I40E_ERR_NO_AVAILABLE_VSI		= -17, | ||||
| 	I40E_ERR_NO_MEMORY			= -18, | ||||
| 	I40E_ERR_BAD_PTR			= -19, | ||||
| 	I40E_ERR_RING_FULL			= -20, | ||||
| 	I40E_ERR_INVALID_PD_ID			= -21, | ||||
| 	I40E_ERR_INVALID_QP_ID			= -22, | ||||
| 	I40E_ERR_INVALID_CQ_ID			= -23, | ||||
| 	I40E_ERR_INVALID_CEQ_ID			= -24, | ||||
| 	I40E_ERR_INVALID_AEQ_ID			= -25, | ||||
| 	I40E_ERR_INVALID_SIZE			= -26, | ||||
| 	I40E_ERR_INVALID_ARP_INDEX		= -27, | ||||
| 	I40E_ERR_INVALID_FPM_FUNC_ID		= -28, | ||||
| 	I40E_ERR_QP_INVALID_MSG_SIZE		= -29, | ||||
| 	I40E_ERR_QP_TOOMANY_WRS_POSTED		= -30, | ||||
| 	I40E_ERR_INVALID_FRAG_COUNT		= -31, | ||||
| 	I40E_ERR_QUEUE_EMPTY			= -32, | ||||
| 	I40E_ERR_INVALID_ALIGNMENT		= -33, | ||||
| 	I40E_ERR_FLUSHED_QUEUE			= -34, | ||||
| 	I40E_ERR_INVALID_PUSH_PAGE_INDEX	= -35, | ||||
| 	I40E_ERR_INVALID_IMM_DATA_SIZE		= -36, | ||||
| 	I40E_ERR_TIMEOUT			= -37, | ||||
| 	I40E_ERR_OPCODE_MISMATCH		= -38, | ||||
| 	I40E_ERR_CQP_COMPL_ERROR		= -39, | ||||
| 	I40E_ERR_INVALID_VF_ID			= -40, | ||||
| 	I40E_ERR_INVALID_HMCFN_ID		= -41, | ||||
| 	I40E_ERR_BACKING_PAGE_ERROR		= -42, | ||||
| 	I40E_ERR_NO_PBLCHUNKS_AVAILABLE		= -43, | ||||
| 	I40E_ERR_INVALID_PBLE_INDEX		= -44, | ||||
| 	I40E_ERR_INVALID_SD_INDEX		= -45, | ||||
| 	I40E_ERR_INVALID_PAGE_DESC_INDEX	= -46, | ||||
| 	I40E_ERR_INVALID_SD_TYPE		= -47, | ||||
| 	I40E_ERR_MEMCPY_FAILED			= -48, | ||||
| 	I40E_ERR_INVALID_HMC_OBJ_INDEX		= -49, | ||||
| 	I40E_ERR_INVALID_HMC_OBJ_COUNT		= -50, | ||||
| 	I40E_ERR_INVALID_SRQ_ARM_LIMIT		= -51, | ||||
| 	I40E_ERR_SRQ_ENABLED			= -52, | ||||
| 	I40E_ERR_ADMIN_QUEUE_ERROR		= -53, | ||||
| 	I40E_ERR_ADMIN_QUEUE_TIMEOUT		= -54, | ||||
| 	I40E_ERR_BUF_TOO_SHORT			= -55, | ||||
| 	I40E_ERR_ADMIN_QUEUE_FULL		= -56, | ||||
| 	I40E_ERR_ADMIN_QUEUE_NO_WORK		= -57, | ||||
| 	I40E_ERR_BAD_IWARP_CQE			= -58, | ||||
| 	I40E_ERR_NVM_BLANK_MODE			= -59, | ||||
| 	I40E_ERR_NOT_IMPLEMENTED		= -60, | ||||
| 	I40E_ERR_PE_DOORBELL_NOT_ENABLED	= -61, | ||||
| 	I40E_ERR_DIAG_TEST_FAILED		= -62, | ||||
| 	I40E_ERR_NOT_READY			= -63, | ||||
| 	I40E_NOT_SUPPORTED			= -64, | ||||
| 	I40E_ERR_FIRMWARE_API_VERSION		= -65, | ||||
| }; | ||||
| 
 | ||||
| #endif /* _I40E_STATUS_H_ */ | ||||
							
								
								
									
										1672
									
								
								drivers/net/ethernet/intel/i40evf/i40e_txrx.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1672
									
								
								drivers/net/ethernet/intel/i40evf/i40e_txrx.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										291
									
								
								drivers/net/ethernet/intel/i40evf/i40e_txrx.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								drivers/net/ethernet/intel/i40evf/i40e_txrx.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,291 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #ifndef _I40E_TXRX_H_ | ||||
| #define _I40E_TXRX_H_ | ||||
| 
 | ||||
| /* Interrupt Throttling and Rate Limiting Goodies */ | ||||
| 
 | ||||
| #define I40E_MAX_ITR               0x0FF0  /* reg uses 2 usec resolution */ | ||||
| #define I40E_MIN_ITR               0x0004  /* reg uses 2 usec resolution */ | ||||
| #define I40E_MAX_IRATE             0x03F | ||||
| #define I40E_MIN_IRATE             0x001 | ||||
| #define I40E_IRATE_USEC_RESOLUTION 4 | ||||
| #define I40E_ITR_100K              0x0005 | ||||
| #define I40E_ITR_20K               0x0019 | ||||
| #define I40E_ITR_8K                0x003E | ||||
| #define I40E_ITR_4K                0x007A | ||||
| #define I40E_ITR_RX_DEF            I40E_ITR_8K | ||||
| #define I40E_ITR_TX_DEF            I40E_ITR_4K | ||||
| #define I40E_ITR_DYNAMIC           0x8000  /* use top bit as a flag */ | ||||
| #define I40E_MIN_INT_RATE          250     /* ~= 1000000 / (I40E_MAX_ITR * 2) */ | ||||
| #define I40E_MAX_INT_RATE          500000  /* == 1000000 / (I40E_MIN_ITR * 2) */ | ||||
| #define I40E_DEFAULT_IRQ_WORK      256 | ||||
| #define ITR_TO_REG(setting) ((setting & ~I40E_ITR_DYNAMIC) >> 1) | ||||
| #define ITR_IS_DYNAMIC(setting) (!!(setting & I40E_ITR_DYNAMIC)) | ||||
| #define ITR_REG_TO_USEC(itr_reg) (itr_reg << 1) | ||||
| 
 | ||||
| #define I40E_QUEUE_END_OF_LIST 0x7FF | ||||
| 
 | ||||
| /* this enum matches hardware bits and is meant to be used by DYN_CTLN
 | ||||
|  * registers and QINT registers or more generally anywhere in the manual | ||||
|  * mentioning ITR_INDX, ITR_NONE cannot be used as an index 'n' into any | ||||
|  * register but instead is a special value meaning "don't update" ITR0/1/2. | ||||
|  */ | ||||
| enum i40e_dyn_idx_t { | ||||
| 	I40E_IDX_ITR0 = 0, | ||||
| 	I40E_IDX_ITR1 = 1, | ||||
| 	I40E_IDX_ITR2 = 2, | ||||
| 	I40E_ITR_NONE = 3	/* ITR_NONE must not be used as an index */ | ||||
| }; | ||||
| 
 | ||||
| /* these are indexes into ITRN registers */ | ||||
| #define I40E_RX_ITR    I40E_IDX_ITR0 | ||||
| #define I40E_TX_ITR    I40E_IDX_ITR1 | ||||
| #define I40E_PE_ITR    I40E_IDX_ITR2 | ||||
| 
 | ||||
| /* Supported RSS offloads */ | ||||
| #define I40E_DEFAULT_RSS_HENA ( \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | \ | ||||
| 	((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD)) | ||||
| 
 | ||||
| /* Supported Rx Buffer Sizes */ | ||||
| #define I40E_RXBUFFER_512   512    /* Used for packet split */ | ||||
| #define I40E_RXBUFFER_2048  2048 | ||||
| #define I40E_RXBUFFER_3072  3072   /* For FCoE MTU of 2158 */ | ||||
| #define I40E_RXBUFFER_4096  4096 | ||||
| #define I40E_RXBUFFER_8192  8192 | ||||
| #define I40E_MAX_RXBUFFER   9728  /* largest size for single descriptor */ | ||||
| 
 | ||||
| /* NOTE: netdev_alloc_skb reserves up to 64 bytes, NET_IP_ALIGN means we
 | ||||
|  * reserve 2 more, and skb_shared_info adds an additional 384 bytes more, | ||||
|  * this adds up to 512 bytes of extra data meaning the smallest allocation | ||||
|  * we could have is 1K. | ||||
|  * i.e. RXBUFFER_512 --> size-1024 slab | ||||
|  */ | ||||
| #define I40E_RX_HDR_SIZE  I40E_RXBUFFER_512 | ||||
| 
 | ||||
| /* How many Rx Buffers do we bundle into one write to the hardware ? */ | ||||
| #define I40E_RX_BUFFER_WRITE	16	/* Must be power of 2 */ | ||||
| #define I40E_RX_NEXT_DESC(r, i, n)		\ | ||||
| 	do {					\ | ||||
| 		(i)++;				\ | ||||
| 		if ((i) == (r)->count)		\ | ||||
| 			i = 0;			\ | ||||
| 		(n) = I40E_RX_DESC((r), (i));	\ | ||||
| 	} while (0) | ||||
| 
 | ||||
| #define I40E_RX_NEXT_DESC_PREFETCH(r, i, n)		\ | ||||
| 	do {						\ | ||||
| 		I40E_RX_NEXT_DESC((r), (i), (n));	\ | ||||
| 		prefetch((n));				\ | ||||
| 	} while (0) | ||||
| 
 | ||||
| #define i40e_rx_desc i40e_32byte_rx_desc | ||||
| 
 | ||||
| #define I40E_MIN_TX_LEN		17 | ||||
| #define I40E_MAX_DATA_PER_TXD	8192 | ||||
| 
 | ||||
| /* Tx Descriptors needed, worst case */ | ||||
| #define TXD_USE_COUNT(S) DIV_ROUND_UP((S), I40E_MAX_DATA_PER_TXD) | ||||
| #define DESC_NEEDED (MAX_SKB_FRAGS + 4) | ||||
| #define I40E_MIN_DESC_PENDING	4 | ||||
| 
 | ||||
| #define I40E_TX_FLAGS_CSUM		(u32)(1) | ||||
| #define I40E_TX_FLAGS_HW_VLAN		(u32)(1 << 1) | ||||
| #define I40E_TX_FLAGS_SW_VLAN		(u32)(1 << 2) | ||||
| #define I40E_TX_FLAGS_TSO		(u32)(1 << 3) | ||||
| #define I40E_TX_FLAGS_IPV4		(u32)(1 << 4) | ||||
| #define I40E_TX_FLAGS_IPV6		(u32)(1 << 5) | ||||
| #define I40E_TX_FLAGS_FCCRC		(u32)(1 << 6) | ||||
| #define I40E_TX_FLAGS_FSO		(u32)(1 << 7) | ||||
| #define I40E_TX_FLAGS_FD_SB		(u32)(1 << 9) | ||||
| #define I40E_TX_FLAGS_VLAN_MASK		0xffff0000 | ||||
| #define I40E_TX_FLAGS_VLAN_PRIO_MASK	0xe0000000 | ||||
| #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT	29 | ||||
| #define I40E_TX_FLAGS_VLAN_SHIFT	16 | ||||
| 
 | ||||
| struct i40e_tx_buffer { | ||||
| 	struct i40e_tx_desc *next_to_watch; | ||||
| 	unsigned long time_stamp; | ||||
| 	union { | ||||
| 		struct sk_buff *skb; | ||||
| 		void *raw_buf; | ||||
| 	}; | ||||
| 	unsigned int bytecount; | ||||
| 	unsigned short gso_segs; | ||||
| 	DEFINE_DMA_UNMAP_ADDR(dma); | ||||
| 	DEFINE_DMA_UNMAP_LEN(len); | ||||
| 	u32 tx_flags; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_rx_buffer { | ||||
| 	struct sk_buff *skb; | ||||
| 	dma_addr_t dma; | ||||
| 	struct page *page; | ||||
| 	dma_addr_t page_dma; | ||||
| 	unsigned int page_offset; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_queue_stats { | ||||
| 	u64 packets; | ||||
| 	u64 bytes; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_tx_queue_stats { | ||||
| 	u64 restart_queue; | ||||
| 	u64 tx_busy; | ||||
| 	u64 tx_done_old; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_rx_queue_stats { | ||||
| 	u64 non_eop_descs; | ||||
| 	u64 alloc_page_failed; | ||||
| 	u64 alloc_buff_failed; | ||||
| }; | ||||
| 
 | ||||
| enum i40e_ring_state_t { | ||||
| 	__I40E_TX_FDIR_INIT_DONE, | ||||
| 	__I40E_TX_XPS_INIT_DONE, | ||||
| 	__I40E_TX_DETECT_HANG, | ||||
| 	__I40E_HANG_CHECK_ARMED, | ||||
| 	__I40E_RX_PS_ENABLED, | ||||
| 	__I40E_RX_16BYTE_DESC_ENABLED, | ||||
| }; | ||||
| 
 | ||||
| #define ring_is_ps_enabled(ring) \ | ||||
| 	test_bit(__I40E_RX_PS_ENABLED, &(ring)->state) | ||||
| #define set_ring_ps_enabled(ring) \ | ||||
| 	set_bit(__I40E_RX_PS_ENABLED, &(ring)->state) | ||||
| #define clear_ring_ps_enabled(ring) \ | ||||
| 	clear_bit(__I40E_RX_PS_ENABLED, &(ring)->state) | ||||
| #define check_for_tx_hang(ring) \ | ||||
| 	test_bit(__I40E_TX_DETECT_HANG, &(ring)->state) | ||||
| #define set_check_for_tx_hang(ring) \ | ||||
| 	set_bit(__I40E_TX_DETECT_HANG, &(ring)->state) | ||||
| #define clear_check_for_tx_hang(ring) \ | ||||
| 	clear_bit(__I40E_TX_DETECT_HANG, &(ring)->state) | ||||
| #define ring_is_16byte_desc_enabled(ring) \ | ||||
| 	test_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state) | ||||
| #define set_ring_16byte_desc_enabled(ring) \ | ||||
| 	set_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state) | ||||
| #define clear_ring_16byte_desc_enabled(ring) \ | ||||
| 	clear_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state) | ||||
| 
 | ||||
| /* struct that defines a descriptor ring, associated with a VSI */ | ||||
| struct i40e_ring { | ||||
| 	struct i40e_ring *next;		/* pointer to next ring in q_vector */ | ||||
| 	void *desc;			/* Descriptor ring memory */ | ||||
| 	struct device *dev;		/* Used for DMA mapping */ | ||||
| 	struct net_device *netdev;	/* netdev ring maps to */ | ||||
| 	union { | ||||
| 		struct i40e_tx_buffer *tx_bi; | ||||
| 		struct i40e_rx_buffer *rx_bi; | ||||
| 	}; | ||||
| 	unsigned long state; | ||||
| 	u16 queue_index;		/* Queue number of ring */ | ||||
| 	u8 dcb_tc;			/* Traffic class of ring */ | ||||
| 	u8 __iomem *tail; | ||||
| 
 | ||||
| 	u16 count;			/* Number of descriptors */ | ||||
| 	u16 reg_idx;			/* HW register index of the ring */ | ||||
| 	u16 rx_hdr_len; | ||||
| 	u16 rx_buf_len; | ||||
| 	u8  dtype; | ||||
| #define I40E_RX_DTYPE_NO_SPLIT      0 | ||||
| #define I40E_RX_DTYPE_SPLIT_ALWAYS  1 | ||||
| #define I40E_RX_DTYPE_HEADER_SPLIT  2 | ||||
| 	u8  hsplit; | ||||
| #define I40E_RX_SPLIT_L2      0x1 | ||||
| #define I40E_RX_SPLIT_IP      0x2 | ||||
| #define I40E_RX_SPLIT_TCP_UDP 0x4 | ||||
| #define I40E_RX_SPLIT_SCTP    0x8 | ||||
| 
 | ||||
| 	/* used in interrupt processing */ | ||||
| 	u16 next_to_use; | ||||
| 	u16 next_to_clean; | ||||
| 
 | ||||
| 	u8 atr_sample_rate; | ||||
| 	u8 atr_count; | ||||
| 
 | ||||
| 	bool ring_active;		/* is ring online or not */ | ||||
| 
 | ||||
| 	/* stats structs */ | ||||
| 	struct i40e_queue_stats	stats; | ||||
| 	struct u64_stats_sync syncp; | ||||
| 	union { | ||||
| 		struct i40e_tx_queue_stats tx_stats; | ||||
| 		struct i40e_rx_queue_stats rx_stats; | ||||
| 	}; | ||||
| 
 | ||||
| 	unsigned int size;		/* length of descriptor ring in bytes */ | ||||
| 	dma_addr_t dma;			/* physical address of ring */ | ||||
| 
 | ||||
| 	struct i40e_vsi *vsi;		/* Backreference to associated VSI */ | ||||
| 	struct i40e_q_vector *q_vector;	/* Backreference to associated vector */ | ||||
| 
 | ||||
| 	struct rcu_head rcu;		/* to avoid race on free */ | ||||
| } ____cacheline_internodealigned_in_smp; | ||||
| 
 | ||||
| enum i40e_latency_range { | ||||
| 	I40E_LOWEST_LATENCY = 0, | ||||
| 	I40E_LOW_LATENCY = 1, | ||||
| 	I40E_BULK_LATENCY = 2, | ||||
| }; | ||||
| 
 | ||||
| struct i40e_ring_container { | ||||
| 	/* array of pointers to rings */ | ||||
| 	struct i40e_ring *ring; | ||||
| 	unsigned int total_bytes;	/* total bytes processed this int */ | ||||
| 	unsigned int total_packets;	/* total packets processed this int */ | ||||
| 	u16 count; | ||||
| 	enum i40e_latency_range latency_range; | ||||
| 	u16 itr; | ||||
| }; | ||||
| 
 | ||||
| /* iterator for handling rings in ring container */ | ||||
| #define i40e_for_each_ring(pos, head) \ | ||||
| 	for (pos = (head).ring; pos != NULL; pos = pos->next) | ||||
| 
 | ||||
| void i40evf_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count); | ||||
| netdev_tx_t i40evf_xmit_frame(struct sk_buff *skb, struct net_device *netdev); | ||||
| void i40evf_clean_tx_ring(struct i40e_ring *tx_ring); | ||||
| void i40evf_clean_rx_ring(struct i40e_ring *rx_ring); | ||||
| int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring); | ||||
| int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring); | ||||
| void i40evf_free_tx_resources(struct i40e_ring *tx_ring); | ||||
| void i40evf_free_rx_resources(struct i40e_ring *rx_ring); | ||||
| int i40evf_napi_poll(struct napi_struct *napi, int budget); | ||||
| #endif /* _I40E_TXRX_H_ */ | ||||
							
								
								
									
										1237
									
								
								drivers/net/ethernet/intel/i40evf/i40e_type.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1237
									
								
								drivers/net/ethernet/intel/i40evf/i40e_type.h
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										363
									
								
								drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,363 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #ifndef _I40E_VIRTCHNL_H_ | ||||
| #define _I40E_VIRTCHNL_H_ | ||||
| 
 | ||||
| #include "i40e_type.h" | ||||
| 
 | ||||
| /* Description:
 | ||||
|  * This header file describes the VF-PF communication protocol used | ||||
|  * by the various i40e drivers. | ||||
|  * | ||||
|  * Admin queue buffer usage: | ||||
|  * desc->opcode is always i40e_aqc_opc_send_msg_to_pf | ||||
|  * flags, retval, datalen, and data addr are all used normally. | ||||
|  * Firmware copies the cookie fields when sending messages between the PF and | ||||
|  * VF, but uses all other fields internally. Due to this limitation, we | ||||
|  * must send all messages as "indirect", i.e. using an external buffer. | ||||
|  * | ||||
|  * All the vsi indexes are relative to the VF. Each VF can have maximum of | ||||
|  * three VSIs. All the queue indexes are relative to the VSI.  Each VF can | ||||
|  * have a maximum of sixteen queues for all of its VSIs. | ||||
|  * | ||||
|  * The PF is required to return a status code in v_retval for all messages | ||||
|  * except RESET_VF, which does not require any response. The return value is of | ||||
|  * i40e_status_code type, defined in the i40e_type.h. | ||||
|  * | ||||
|  * In general, VF driver initialization should roughly follow the order of these | ||||
|  * opcodes. The VF driver must first validate the API version of the PF driver, | ||||
|  * then request a reset, then get resources, then configure queues and | ||||
|  * interrupts. After these operations are complete, the VF driver may start | ||||
|  * its queues, optionally add MAC and VLAN filters, and process traffic. | ||||
|  */ | ||||
| 
 | ||||
| /* Opcodes for VF-PF communication. These are placed in the v_opcode field
 | ||||
|  * of the virtchnl_msg structure. | ||||
|  */ | ||||
| enum i40e_virtchnl_ops { | ||||
| /* VF sends req. to pf for the following
 | ||||
|  * ops. | ||||
|  */ | ||||
| 	I40E_VIRTCHNL_OP_UNKNOWN = 0, | ||||
| 	I40E_VIRTCHNL_OP_VERSION = 1, /* must ALWAYS be 1 */ | ||||
| 	I40E_VIRTCHNL_OP_RESET_VF, | ||||
| 	I40E_VIRTCHNL_OP_GET_VF_RESOURCES, | ||||
| 	I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE, | ||||
| 	I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE, | ||||
| 	I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, | ||||
| 	I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, | ||||
| 	I40E_VIRTCHNL_OP_ENABLE_QUEUES, | ||||
| 	I40E_VIRTCHNL_OP_DISABLE_QUEUES, | ||||
| 	I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, | ||||
| 	I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS, | ||||
| 	I40E_VIRTCHNL_OP_ADD_VLAN, | ||||
| 	I40E_VIRTCHNL_OP_DEL_VLAN, | ||||
| 	I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, | ||||
| 	I40E_VIRTCHNL_OP_GET_STATS, | ||||
| 	I40E_VIRTCHNL_OP_FCOE, | ||||
| /* PF sends status change events to vfs using
 | ||||
|  * the following op. | ||||
|  */ | ||||
| 	I40E_VIRTCHNL_OP_EVENT, | ||||
| }; | ||||
| 
 | ||||
| /* Virtual channel message descriptor. This overlays the admin queue
 | ||||
|  * descriptor. All other data is passed in external buffers. | ||||
|  */ | ||||
| 
 | ||||
| struct i40e_virtchnl_msg { | ||||
| 	u8 pad[8];			 /* AQ flags/opcode/len/retval fields */ | ||||
| 	enum i40e_virtchnl_ops v_opcode; /* avoid confusion with desc->opcode */ | ||||
| 	i40e_status v_retval;  /* ditto for desc->retval */ | ||||
| 	u32 vfid;			 /* used by PF when sending to VF */ | ||||
| }; | ||||
| 
 | ||||
| /* Message descriptions and data structures.*/ | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_VERSION
 | ||||
|  * VF posts its version number to the PF. PF responds with its version number | ||||
|  * in the same format, along with a return code. | ||||
|  * Reply from PF has its major/minor versions also in param0 and param1. | ||||
|  * If there is a major version mismatch, then the VF cannot operate. | ||||
|  * If there is a minor version mismatch, then the VF can operate but should | ||||
|  * add a warning to the system log. | ||||
|  * | ||||
|  * This enum element MUST always be specified as == 1, regardless of other | ||||
|  * changes in the API. The PF must always respond to this message without | ||||
|  * error regardless of version mismatch. | ||||
|  */ | ||||
| #define I40E_VIRTCHNL_VERSION_MAJOR		1 | ||||
| #define I40E_VIRTCHNL_VERSION_MINOR		0 | ||||
| struct i40e_virtchnl_version_info { | ||||
| 	u32 major; | ||||
| 	u32 minor; | ||||
| }; | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_RESET_VF
 | ||||
|  * VF sends this request to PF with no parameters | ||||
|  * PF does NOT respond! VF driver must delay then poll VFGEN_RSTAT register | ||||
|  * until reset completion is indicated. The admin queue must be reinitialized | ||||
|  * after this operation. | ||||
|  * | ||||
|  * When reset is complete, PF must ensure that all queues in all VSIs associated | ||||
|  * with the VF are stopped, all queue configurations in the HMC are set to 0, | ||||
|  * and all MAC and VLAN filters (except the default MAC address) on all VSIs | ||||
|  * are cleared. | ||||
|  */ | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_GET_VF_RESOURCES
 | ||||
|  * VF sends this request to PF with no parameters | ||||
|  * PF responds with an indirect message containing | ||||
|  * i40e_virtchnl_vf_resource and one or more | ||||
|  * i40e_virtchnl_vsi_resource structures. | ||||
|  */ | ||||
| 
 | ||||
| struct i40e_virtchnl_vsi_resource { | ||||
| 	u16 vsi_id; | ||||
| 	u16 num_queue_pairs; | ||||
| 	enum i40e_vsi_type vsi_type; | ||||
| 	u16 qset_handle; | ||||
| 	u8 default_mac_addr[ETH_ALEN]; | ||||
| }; | ||||
| /* VF offload flags */ | ||||
| #define I40E_VIRTCHNL_VF_OFFLOAD_L2	0x00000001 | ||||
| #define I40E_VIRTCHNL_VF_OFFLOAD_FCOE	0x00000004 | ||||
| #define I40E_VIRTCHNL_VF_OFFLOAD_VLAN	0x00010000 | ||||
| 
 | ||||
| struct i40e_virtchnl_vf_resource { | ||||
| 	u16 num_vsis; | ||||
| 	u16 num_queue_pairs; | ||||
| 	u16 max_vectors; | ||||
| 	u16 max_mtu; | ||||
| 
 | ||||
| 	u32 vf_offload_flags; | ||||
| 	u32 max_fcoe_contexts; | ||||
| 	u32 max_fcoe_filters; | ||||
| 
 | ||||
| 	struct i40e_virtchnl_vsi_resource vsi_res[1]; | ||||
| }; | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE
 | ||||
|  * VF sends this message to set up parameters for one TX queue. | ||||
|  * External data buffer contains one instance of i40e_virtchnl_txq_info. | ||||
|  * PF configures requested queue and returns a status code. | ||||
|  */ | ||||
| 
 | ||||
| /* Tx queue config info */ | ||||
| struct i40e_virtchnl_txq_info { | ||||
| 	u16 vsi_id; | ||||
| 	u16 queue_id; | ||||
| 	u16 ring_len;		/* number of descriptors, multiple of 8 */ | ||||
| 	u16 headwb_enabled; | ||||
| 	u64 dma_ring_addr; | ||||
| 	u64 dma_headwb_addr; | ||||
| }; | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE
 | ||||
|  * VF sends this message to set up parameters for one RX queue. | ||||
|  * External data buffer contains one instance of i40e_virtchnl_rxq_info. | ||||
|  * PF configures requested queue and returns a status code. | ||||
|  */ | ||||
| 
 | ||||
| /* Rx queue config info */ | ||||
| struct i40e_virtchnl_rxq_info { | ||||
| 	u16 vsi_id; | ||||
| 	u16 queue_id; | ||||
| 	u32 ring_len;		/* number of descriptors, multiple of 32 */ | ||||
| 	u16 hdr_size; | ||||
| 	u16 splithdr_enabled; | ||||
| 	u32 databuffer_size; | ||||
| 	u32 max_pkt_size; | ||||
| 	u64 dma_ring_addr; | ||||
| 	enum i40e_hmc_obj_rx_hsplit_0 rx_split_pos; | ||||
| }; | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES
 | ||||
|  * VF sends this message to set parameters for all active TX and RX queues | ||||
|  * associated with the specified VSI. | ||||
|  * PF configures queues and returns status. | ||||
|  * If the number of queues specified is greater than the number of queues | ||||
|  * associated with the VSI, an error is returned and no queues are configured. | ||||
|  */ | ||||
| struct i40e_virtchnl_queue_pair_info { | ||||
| 	/* NOTE: vsi_id and queue_id should be identical for both queues. */ | ||||
| 	struct i40e_virtchnl_txq_info txq; | ||||
| 	struct i40e_virtchnl_rxq_info rxq; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_virtchnl_vsi_queue_config_info { | ||||
| 	u16 vsi_id; | ||||
| 	u16 num_queue_pairs; | ||||
| 	struct i40e_virtchnl_queue_pair_info qpair[1]; | ||||
| }; | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP
 | ||||
|  * VF uses this message to map vectors to queues. | ||||
|  * The rxq_map and txq_map fields are bitmaps used to indicate which queues | ||||
|  * are to be associated with the specified vector. | ||||
|  * The "other" causes are always mapped to vector 0. | ||||
|  * PF configures interrupt mapping and returns status. | ||||
|  */ | ||||
| struct i40e_virtchnl_vector_map { | ||||
| 	u16 vsi_id; | ||||
| 	u16 vector_id; | ||||
| 	u16 rxq_map; | ||||
| 	u16 txq_map; | ||||
| 	u16 rxitr_idx; | ||||
| 	u16 txitr_idx; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_virtchnl_irq_map_info { | ||||
| 	u16 num_vectors; | ||||
| 	struct i40e_virtchnl_vector_map vecmap[1]; | ||||
| }; | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_ENABLE_QUEUES
 | ||||
|  * I40E_VIRTCHNL_OP_DISABLE_QUEUES | ||||
|  * VF sends these message to enable or disable TX/RX queue pairs. | ||||
|  * The queues fields are bitmaps indicating which queues to act upon. | ||||
|  * (Currently, we only support 16 queues per VF, but we make the field | ||||
|  * u32 to allow for expansion.) | ||||
|  * PF performs requested action and returns status. | ||||
|  */ | ||||
| struct i40e_virtchnl_queue_select { | ||||
| 	u16 vsi_id; | ||||
| 	u16 pad; | ||||
| 	u32 rx_queues; | ||||
| 	u32 tx_queues; | ||||
| }; | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS
 | ||||
|  * VF sends this message in order to add one or more unicast or multicast | ||||
|  * address filters for the specified VSI. | ||||
|  * PF adds the filters and returns status. | ||||
|  */ | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS
 | ||||
|  * VF sends this message in order to remove one or more unicast or multicast | ||||
|  * filters for the specified VSI. | ||||
|  * PF removes the filters and returns status. | ||||
|  */ | ||||
| 
 | ||||
| struct i40e_virtchnl_ether_addr { | ||||
| 	u8 addr[ETH_ALEN]; | ||||
| 	u8 pad[2]; | ||||
| }; | ||||
| 
 | ||||
| struct i40e_virtchnl_ether_addr_list { | ||||
| 	u16 vsi_id; | ||||
| 	u16 num_elements; | ||||
| 	struct i40e_virtchnl_ether_addr list[1]; | ||||
| }; | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_ADD_VLAN
 | ||||
|  * VF sends this message to add one or more VLAN tag filters for receives. | ||||
|  * PF adds the filters and returns status. | ||||
|  * If a port VLAN is configured by the PF, this operation will return an | ||||
|  * error to the VF. | ||||
|  */ | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_DEL_VLAN
 | ||||
|  * VF sends this message to remove one or more VLAN tag filters for receives. | ||||
|  * PF removes the filters and returns status. | ||||
|  * If a port VLAN is configured by the PF, this operation will return an | ||||
|  * error to the VF. | ||||
|  */ | ||||
| 
 | ||||
| struct i40e_virtchnl_vlan_filter_list { | ||||
| 	u16 vsi_id; | ||||
| 	u16 num_elements; | ||||
| 	u16 vlan_id[1]; | ||||
| }; | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE
 | ||||
|  * VF sends VSI id and flags. | ||||
|  * PF returns status code in retval. | ||||
|  * Note: we assume that broadcast accept mode is always enabled. | ||||
|  */ | ||||
| struct i40e_virtchnl_promisc_info { | ||||
| 	u16 vsi_id; | ||||
| 	u16 flags; | ||||
| }; | ||||
| 
 | ||||
| #define I40E_FLAG_VF_UNICAST_PROMISC	0x00000001 | ||||
| #define I40E_FLAG_VF_MULTICAST_PROMISC	0x00000002 | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_GET_STATS
 | ||||
|  * VF sends this message to request stats for the selected VSI. VF uses | ||||
|  * the i40e_virtchnl_queue_select struct to specify the VSI. The queue_id | ||||
|  * field is ignored by the PF. | ||||
|  * | ||||
|  * PF replies with struct i40e_eth_stats in an external buffer. | ||||
|  */ | ||||
| 
 | ||||
| /* I40E_VIRTCHNL_OP_EVENT
 | ||||
|  * PF sends this message to inform the VF driver of events that may affect it. | ||||
|  * No direct response is expected from the VF, though it may generate other | ||||
|  * messages in response to this one. | ||||
|  */ | ||||
| enum i40e_virtchnl_event_codes { | ||||
| 	I40E_VIRTCHNL_EVENT_UNKNOWN = 0, | ||||
| 	I40E_VIRTCHNL_EVENT_LINK_CHANGE, | ||||
| 	I40E_VIRTCHNL_EVENT_RESET_IMPENDING, | ||||
| 	I40E_VIRTCHNL_EVENT_PF_DRIVER_CLOSE, | ||||
| }; | ||||
| #define I40E_PF_EVENT_SEVERITY_INFO		0 | ||||
| #define I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM	255 | ||||
| 
 | ||||
| struct i40e_virtchnl_pf_event { | ||||
| 	enum i40e_virtchnl_event_codes event; | ||||
| 	union { | ||||
| 		struct { | ||||
| 			enum i40e_aq_link_speed link_speed; | ||||
| 			bool link_status; | ||||
| 		} link_event; | ||||
| 	} event_data; | ||||
| 
 | ||||
| 	int severity; | ||||
| }; | ||||
| 
 | ||||
| /* VF reset states - these are written into the RSTAT register:
 | ||||
|  * I40E_VFGEN_RSTAT1 on the PF | ||||
|  * I40E_VFGEN_RSTAT on the VF | ||||
|  * When the PF initiates a reset, it writes 0 | ||||
|  * When the reset is complete, it writes 1 | ||||
|  * When the PF detects that the VF has recovered, it writes 2 | ||||
|  * VF checks this register periodically to determine if a reset has occurred, | ||||
|  * then polls it to know when the reset is complete. | ||||
|  * If either the PF or VF reads the register while the hardware | ||||
|  * is in a reset state, it will return DEADBEEF, which, when masked | ||||
|  * will result in 3. | ||||
|  */ | ||||
| enum i40e_vfr_states { | ||||
| 	I40E_VFR_INPROGRESS = 0, | ||||
| 	I40E_VFR_COMPLETED, | ||||
| 	I40E_VFR_VFACTIVE, | ||||
| 	I40E_VFR_UNKNOWN, | ||||
| }; | ||||
| 
 | ||||
| #endif /* _I40E_VIRTCHNL_H_ */ | ||||
							
								
								
									
										298
									
								
								drivers/net/ethernet/intel/i40evf/i40evf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								drivers/net/ethernet/intel/i40evf/i40evf.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,298 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #ifndef _I40EVF_H_ | ||||
| #define _I40EVF_H_ | ||||
| 
 | ||||
| #include <linux/module.h> | ||||
| #include <linux/pci.h> | ||||
| #include <linux/aer.h> | ||||
| #include <linux/netdevice.h> | ||||
| #include <linux/vmalloc.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/ethtool.h> | ||||
| #include <linux/if_vlan.h> | ||||
| #include <linux/ip.h> | ||||
| #include <linux/tcp.h> | ||||
| #include <linux/sctp.h> | ||||
| #include <linux/ipv6.h> | ||||
| #include <net/ip6_checksum.h> | ||||
| #include <net/udp.h> | ||||
| 
 | ||||
| #include "i40e_type.h" | ||||
| #include "i40e_virtchnl.h" | ||||
| #include "i40e_txrx.h" | ||||
| 
 | ||||
| #define DEFAULT_DEBUG_LEVEL_SHIFT 3 | ||||
| #define PFX "i40evf: " | ||||
| #define DPRINTK(nlevel, klevel, fmt, args...) \ | ||||
| 	((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \ | ||||
| 	printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \ | ||||
| 		__func__ , ## args))) | ||||
| 
 | ||||
| /* dummy struct to make common code less painful */ | ||||
| struct i40e_vsi { | ||||
| 	struct i40evf_adapter *back; | ||||
| 	struct net_device *netdev; | ||||
| 	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; | ||||
| 	u16 seid; | ||||
| 	u16 id; | ||||
| 	unsigned long state; | ||||
| 	int base_vector; | ||||
| 	u16 work_limit; | ||||
| 	/* high bit set means dynamic, use accessor routines to read/write.
 | ||||
| 	 * hardware only supports 2us resolution for the ITR registers. | ||||
| 	 * these values always store the USER setting, and must be converted | ||||
| 	 * before programming to a register. | ||||
| 	 */ | ||||
| 	u16 rx_itr_setting; | ||||
| 	u16 tx_itr_setting; | ||||
| }; | ||||
| 
 | ||||
| /* How many Rx Buffers do we bundle into one write to the hardware ? */ | ||||
| #define I40EVF_RX_BUFFER_WRITE	16	/* Must be power of 2 */ | ||||
| #define I40EVF_DEFAULT_TXD   512 | ||||
| #define I40EVF_DEFAULT_RXD   512 | ||||
| #define I40EVF_MAX_TXD       4096 | ||||
| #define I40EVF_MIN_TXD       64 | ||||
| #define I40EVF_MAX_RXD       4096 | ||||
| #define I40EVF_MIN_RXD       64 | ||||
| #define I40EVF_REQ_DESCRIPTOR_MULTIPLE  32 | ||||
| 
 | ||||
| /* Supported Rx Buffer Sizes */ | ||||
| #define I40EVF_RXBUFFER_64    64     /* Used for packet split */ | ||||
| #define I40EVF_RXBUFFER_128   128    /* Used for packet split */ | ||||
| #define I40EVF_RXBUFFER_256   256    /* Used for packet split */ | ||||
| #define I40EVF_RXBUFFER_2048  2048 | ||||
| #define I40EVF_MAX_RXBUFFER   16384  /* largest size for single descriptor */ | ||||
| #define I40EVF_MAX_AQ_BUF_SIZE    4096 | ||||
| #define I40EVF_AQ_LEN             32 | ||||
| #define I40EVF_AQ_MAX_ERR         10 /* times to try before resetting AQ */ | ||||
| 
 | ||||
| #define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) | ||||
| 
 | ||||
| #define I40E_RX_DESC(R, i) (&(((union i40e_32byte_rx_desc *)((R)->desc))[i])) | ||||
| #define I40E_TX_DESC(R, i) (&(((struct i40e_tx_desc *)((R)->desc))[i])) | ||||
| #define I40E_TX_CTXTDESC(R, i) \ | ||||
| 	(&(((struct i40e_tx_context_desc *)((R)->desc))[i])) | ||||
| #define MAX_RX_QUEUES 8 | ||||
| #define MAX_TX_QUEUES MAX_RX_QUEUES | ||||
| 
 | ||||
| /* MAX_MSIX_Q_VECTORS of these are allocated,
 | ||||
|  * but we only use one per queue-specific vector. | ||||
|  */ | ||||
| struct i40e_q_vector { | ||||
| 	struct i40evf_adapter *adapter; | ||||
| 	struct i40e_vsi *vsi; | ||||
| 	struct napi_struct napi; | ||||
| 	unsigned long reg_idx; | ||||
| 	struct i40e_ring_container rx; | ||||
| 	struct i40e_ring_container tx; | ||||
| 	u32 ring_mask; | ||||
| 	u8 num_ringpairs;	/* total number of ring pairs in vector */ | ||||
| 	int v_idx;	  /* vector index in list */ | ||||
| 	char name[IFNAMSIZ + 9]; | ||||
| 	cpumask_var_t affinity_mask; | ||||
| }; | ||||
| 
 | ||||
| /* Helper macros to switch between ints/sec and what the register uses.
 | ||||
|  * And yes, it's the same math going both ways.  The lowest value | ||||
|  * supported by all of the i40e hardware is 8. | ||||
|  */ | ||||
| #define EITR_INTS_PER_SEC_TO_REG(_eitr) \ | ||||
| 	((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8) | ||||
| #define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG | ||||
| 
 | ||||
| #define I40EVF_DESC_UNUSED(R) \ | ||||
| 	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ | ||||
| 	(R)->next_to_clean - (R)->next_to_use - 1) | ||||
| 
 | ||||
| #define I40EVF_RX_DESC_ADV(R, i)	    \ | ||||
| 	(&(((union i40e_adv_rx_desc *)((R).desc))[i])) | ||||
| #define I40EVF_TX_DESC_ADV(R, i)	    \ | ||||
| 	(&(((union i40e_adv_tx_desc *)((R).desc))[i])) | ||||
| #define I40EVF_TX_CTXTDESC_ADV(R, i)	    \ | ||||
| 	(&(((struct i40e_adv_tx_context_desc *)((R).desc))[i])) | ||||
| 
 | ||||
| #define OTHER_VECTOR 1 | ||||
| #define NONQ_VECS (OTHER_VECTOR) | ||||
| 
 | ||||
| #define MAX_MSIX_Q_VECTORS 4 | ||||
| #define MAX_MSIX_COUNT 5 | ||||
| 
 | ||||
| #define MIN_MSIX_Q_VECTORS 1 | ||||
| #define MIN_MSIX_COUNT (MIN_MSIX_Q_VECTORS + NONQ_VECS) | ||||
| 
 | ||||
| #define I40EVF_QUEUE_END_OF_LIST 0x7FF | ||||
| #define I40EVF_FREE_VECTOR 0x7FFF | ||||
| struct i40evf_mac_filter { | ||||
| 	struct list_head list; | ||||
| 	u8 macaddr[ETH_ALEN]; | ||||
| 	bool remove;		/* filter needs to be removed */ | ||||
| 	bool add;		/* filter needs to be added */ | ||||
| }; | ||||
| 
 | ||||
| struct i40evf_vlan_filter { | ||||
| 	struct list_head list; | ||||
| 	u16 vlan; | ||||
| 	bool remove;		/* filter needs to be removed */ | ||||
| 	bool add;		/* filter needs to be added */ | ||||
| }; | ||||
| 
 | ||||
| /* Driver state. The order of these is important! */ | ||||
| enum i40evf_state_t { | ||||
| 	__I40EVF_STARTUP,		/* driver loaded, probe complete */ | ||||
| 	__I40EVF_REMOVE,		/* driver is being unloaded */ | ||||
| 	__I40EVF_INIT_VERSION_CHECK,	/* aq msg sent, awaiting reply */ | ||||
| 	__I40EVF_INIT_GET_RESOURCES,	/* aq msg sent, awaiting reply */ | ||||
| 	__I40EVF_INIT_SW,		/* got resources, setting up structs */ | ||||
| 	__I40EVF_RESETTING,		/* in reset */ | ||||
| 	/* Below here, watchdog is running */ | ||||
| 	__I40EVF_DOWN,			/* ready, can be opened */ | ||||
| 	__I40EVF_TESTING,		/* in ethtool self-test */ | ||||
| 	__I40EVF_RUNNING,		/* opened, working */ | ||||
| }; | ||||
| 
 | ||||
| enum i40evf_critical_section_t { | ||||
| 	__I40EVF_IN_CRITICAL_TASK,	/* cannot be interrupted */ | ||||
| }; | ||||
| /* make common code happy */ | ||||
| #define __I40E_DOWN __I40EVF_DOWN | ||||
| 
 | ||||
| /* board specific private data structure */ | ||||
| struct i40evf_adapter { | ||||
| 	struct timer_list watchdog_timer; | ||||
| 	struct work_struct reset_task; | ||||
| 	struct work_struct adminq_task; | ||||
| 	struct delayed_work init_task; | ||||
| 	struct i40e_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; | ||||
| 	struct list_head vlan_filter_list; | ||||
| 	char misc_vector_name[IFNAMSIZ + 9]; | ||||
| 
 | ||||
| 	/* TX */ | ||||
| 	struct i40e_ring *tx_rings[I40E_MAX_VSI_QP]; | ||||
| 	u32 tx_timeout_count; | ||||
| 	struct list_head mac_filter_list; | ||||
| 	u32 tx_desc_count; | ||||
| 
 | ||||
| 	/* RX */ | ||||
| 	struct i40e_ring *rx_rings[I40E_MAX_VSI_QP]; | ||||
| 	u64 hw_csum_rx_error; | ||||
| 	u32 rx_desc_count; | ||||
| 	int num_msix_vectors; | ||||
| 	struct msix_entry *msix_entries; | ||||
| 
 | ||||
| 	u32 flags; | ||||
| #define I40EVF_FLAG_RX_CSUM_ENABLED              (u32)(1) | ||||
| #define I40EVF_FLAG_RX_1BUF_CAPABLE              (u32)(1 << 1) | ||||
| #define I40EVF_FLAG_RX_PS_CAPABLE                (u32)(1 << 2) | ||||
| #define I40EVF_FLAG_RX_PS_ENABLED                (u32)(1 << 3) | ||||
| #define I40EVF_FLAG_IN_NETPOLL                   (u32)(1 << 4) | ||||
| #define I40EVF_FLAG_IMIR_ENABLED                 (u32)(1 << 5) | ||||
| #define I40EVF_FLAG_MQ_CAPABLE                   (u32)(1 << 6) | ||||
| #define I40EVF_FLAG_NEED_LINK_UPDATE             (u32)(1 << 7) | ||||
| #define I40EVF_FLAG_PF_COMMS_FAILED              (u32)(1 << 8) | ||||
| #define I40EVF_FLAG_RESET_PENDING                (u32)(1 << 9) | ||||
| #define I40EVF_FLAG_RESET_NEEDED                 (u32)(1 << 10) | ||||
| /* duplcates for common code */ | ||||
| #define I40E_FLAG_FDIR_ATR_ENABLED		 0 | ||||
| #define I40E_FLAG_DCB_ENABLED			 0 | ||||
| #define I40E_FLAG_IN_NETPOLL			 I40EVF_FLAG_IN_NETPOLL | ||||
| #define I40E_FLAG_RX_CSUM_ENABLED                I40EVF_FLAG_RX_CSUM_ENABLED | ||||
| 	/* flags for admin queue service task */ | ||||
| 	u32 aq_required; | ||||
| 	u32 aq_pending; | ||||
| #define I40EVF_FLAG_AQ_ENABLE_QUEUES		(u32)(1) | ||||
| #define I40EVF_FLAG_AQ_DISABLE_QUEUES		(u32)(1 << 1) | ||||
| #define I40EVF_FLAG_AQ_ADD_MAC_FILTER		(u32)(1 << 2) | ||||
| #define I40EVF_FLAG_AQ_ADD_VLAN_FILTER		(u32)(1 << 3) | ||||
| #define I40EVF_FLAG_AQ_DEL_MAC_FILTER		(u32)(1 << 4) | ||||
| #define I40EVF_FLAG_AQ_DEL_VLAN_FILTER		(u32)(1 << 5) | ||||
| #define I40EVF_FLAG_AQ_CONFIGURE_QUEUES		(u32)(1 << 6) | ||||
| #define I40EVF_FLAG_AQ_MAP_VECTORS		(u32)(1 << 7) | ||||
| #define I40EVF_FLAG_AQ_HANDLE_RESET		(u32)(1 << 8) | ||||
| 
 | ||||
| 	/* OS defined structs */ | ||||
| 	struct net_device *netdev; | ||||
| 	struct pci_dev *pdev; | ||||
| 	struct net_device_stats net_stats; | ||||
| 
 | ||||
| 	struct i40e_hw hw; /* defined in i40e_type.h */ | ||||
| 
 | ||||
| 	enum i40evf_state_t state; | ||||
| 	volatile unsigned long crit_section; | ||||
| 
 | ||||
| 	struct work_struct watchdog_task; | ||||
| 	bool netdev_registered; | ||||
| 	bool link_up; | ||||
| 	enum i40e_virtchnl_ops current_op; | ||||
| 	struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */ | ||||
| 	struct i40e_virtchnl_vsi_resource *vsi_res; /* our LAN VSI */ | ||||
| 	u16 msg_enable; | ||||
| 	struct i40e_eth_stats current_stats; | ||||
| 	struct i40e_vsi vsi; | ||||
| 	u32 aq_wait_count; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /* needed by i40evf_ethtool.c */ | ||||
| extern char i40evf_driver_name[]; | ||||
| extern const char i40evf_driver_version[]; | ||||
| 
 | ||||
| int i40evf_up(struct i40evf_adapter *adapter); | ||||
| void i40evf_down(struct i40evf_adapter *adapter); | ||||
| void i40evf_reinit_locked(struct i40evf_adapter *adapter); | ||||
| void i40evf_reset(struct i40evf_adapter *adapter); | ||||
| void i40evf_set_ethtool_ops(struct net_device *netdev); | ||||
| void i40evf_update_stats(struct i40evf_adapter *adapter); | ||||
| void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter); | ||||
| int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter); | ||||
| void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask); | ||||
| 
 | ||||
| void i40e_napi_add_all(struct i40evf_adapter *adapter); | ||||
| void i40e_napi_del_all(struct i40evf_adapter *adapter); | ||||
| 
 | ||||
| int i40evf_send_api_ver(struct i40evf_adapter *adapter); | ||||
| int i40evf_verify_api_ver(struct i40evf_adapter *adapter); | ||||
| int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter); | ||||
| int i40evf_get_vf_config(struct i40evf_adapter *adapter); | ||||
| void i40evf_irq_enable(struct i40evf_adapter *adapter, bool flush); | ||||
| void i40evf_configure_queues(struct i40evf_adapter *adapter); | ||||
| void i40evf_deconfigure_queues(struct i40evf_adapter *adapter); | ||||
| void i40evf_enable_queues(struct i40evf_adapter *adapter); | ||||
| void i40evf_disable_queues(struct i40evf_adapter *adapter); | ||||
| void i40evf_map_queues(struct i40evf_adapter *adapter); | ||||
| void i40evf_add_ether_addrs(struct i40evf_adapter *adapter); | ||||
| void i40evf_del_ether_addrs(struct i40evf_adapter *adapter); | ||||
| void i40evf_add_vlans(struct i40evf_adapter *adapter); | ||||
| void i40evf_del_vlans(struct i40evf_adapter *adapter); | ||||
| void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags); | ||||
| void i40evf_request_stats(struct i40evf_adapter *adapter); | ||||
| void i40evf_request_reset(struct i40evf_adapter *adapter); | ||||
| void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, | ||||
| 				enum i40e_virtchnl_ops v_opcode, | ||||
| 				i40e_status v_retval, u8 *msg, u16 msglen); | ||||
| #endif /* _I40EVF_H_ */ | ||||
							
								
								
									
										704
									
								
								drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										704
									
								
								drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,704 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| /* ethtool support for i40evf */ | ||||
| #include "i40evf.h" | ||||
| 
 | ||||
| #include <linux/uaccess.h> | ||||
| 
 | ||||
| 
 | ||||
| struct i40evf_stats { | ||||
| 	char stat_string[ETH_GSTRING_LEN]; | ||||
| 	int stat_offset; | ||||
| }; | ||||
| 
 | ||||
| #define I40EVF_STAT(_name, _stat) { \ | ||||
| 	.stat_string = _name, \ | ||||
| 	.stat_offset = offsetof(struct i40evf_adapter, _stat) \ | ||||
| } | ||||
| 
 | ||||
| /* All stats are u64, so we don't need to track the size of the field. */ | ||||
| static const struct i40evf_stats i40evf_gstrings_stats[] = { | ||||
| 	I40EVF_STAT("rx_bytes", current_stats.rx_bytes), | ||||
| 	I40EVF_STAT("rx_unicast", current_stats.rx_unicast), | ||||
| 	I40EVF_STAT("rx_multicast", current_stats.rx_multicast), | ||||
| 	I40EVF_STAT("rx_broadcast", current_stats.rx_broadcast), | ||||
| 	I40EVF_STAT("rx_discards", current_stats.rx_discards), | ||||
| 	I40EVF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol), | ||||
| 	I40EVF_STAT("tx_bytes", current_stats.tx_bytes), | ||||
| 	I40EVF_STAT("tx_unicast", current_stats.tx_unicast), | ||||
| 	I40EVF_STAT("tx_multicast", current_stats.tx_multicast), | ||||
| 	I40EVF_STAT("tx_broadcast", current_stats.tx_broadcast), | ||||
| 	I40EVF_STAT("tx_discards", current_stats.tx_discards), | ||||
| 	I40EVF_STAT("tx_errors", current_stats.tx_errors), | ||||
| }; | ||||
| 
 | ||||
| #define I40EVF_GLOBAL_STATS_LEN ARRAY_SIZE(i40evf_gstrings_stats) | ||||
| #define I40EVF_QUEUE_STATS_LEN(_dev) \ | ||||
| 	(((struct i40evf_adapter *) \ | ||||
| 		netdev_priv(_dev))->vsi_res->num_queue_pairs \ | ||||
| 		  * 2 * (sizeof(struct i40e_queue_stats) / sizeof(u64))) | ||||
| #define I40EVF_STATS_LEN(_dev) \ | ||||
| 	(I40EVF_GLOBAL_STATS_LEN + I40EVF_QUEUE_STATS_LEN(_dev)) | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_settings - Get Link Speed and Duplex settings | ||||
|  * @netdev: network interface device structure | ||||
|  * @ecmd: ethtool command | ||||
|  * | ||||
|  * Reports speed/duplex settings. Because this is a VF, we don't know what | ||||
|  * kind of link we really have, so we fake it. | ||||
|  **/ | ||||
| static int i40evf_get_settings(struct net_device *netdev, | ||||
| 			       struct ethtool_cmd *ecmd) | ||||
| { | ||||
| 	/* In the future the VF will be able to query the PF for
 | ||||
| 	 * some information - for now use a dummy value | ||||
| 	 */ | ||||
| 	ecmd->supported = 0; | ||||
| 	ecmd->autoneg = AUTONEG_DISABLE; | ||||
| 	ecmd->transceiver = XCVR_DUMMY1; | ||||
| 	ecmd->port = PORT_NONE; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_sset_count - Get length of string set | ||||
|  * @netdev: network interface device structure | ||||
|  * @sset: id of string set | ||||
|  * | ||||
|  * Reports size of string table. This driver only supports | ||||
|  * strings for statistics. | ||||
|  **/ | ||||
| static int i40evf_get_sset_count(struct net_device *netdev, int sset) | ||||
| { | ||||
| 	if (sset == ETH_SS_STATS) | ||||
| 		return I40EVF_STATS_LEN(netdev); | ||||
| 	else | ||||
| 		return -EINVAL; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_ethtool_stats - report device statistics | ||||
|  * @netdev: network interface device structure | ||||
|  * @stats: ethtool statistics structure | ||||
|  * @data: pointer to data buffer | ||||
|  * | ||||
|  * All statistics are added to the data buffer as an array of u64. | ||||
|  **/ | ||||
| static void i40evf_get_ethtool_stats(struct net_device *netdev, | ||||
| 				     struct ethtool_stats *stats, u64 *data) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	int i, j; | ||||
| 	char *p; | ||||
| 
 | ||||
| 	for (i = 0; i < I40EVF_GLOBAL_STATS_LEN; i++) { | ||||
| 		p = (char *)adapter + i40evf_gstrings_stats[i].stat_offset; | ||||
| 		data[i] =  *(u64 *)p; | ||||
| 	} | ||||
| 	for (j = 0; j < adapter->vsi_res->num_queue_pairs; j++) { | ||||
| 		data[i++] = adapter->tx_rings[j]->stats.packets; | ||||
| 		data[i++] = adapter->tx_rings[j]->stats.bytes; | ||||
| 	} | ||||
| 	for (j = 0; j < adapter->vsi_res->num_queue_pairs; j++) { | ||||
| 		data[i++] = adapter->rx_rings[j]->stats.packets; | ||||
| 		data[i++] = adapter->rx_rings[j]->stats.bytes; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_strings - Get string set | ||||
|  * @netdev: network interface device structure | ||||
|  * @sset: id of string set | ||||
|  * @data: buffer for string data | ||||
|  * | ||||
|  * Builds stats string table. | ||||
|  **/ | ||||
| static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	u8 *p = data; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (sset == ETH_SS_STATS) { | ||||
| 		for (i = 0; i < I40EVF_GLOBAL_STATS_LEN; i++) { | ||||
| 			memcpy(p, i40evf_gstrings_stats[i].stat_string, | ||||
| 			       ETH_GSTRING_LEN); | ||||
| 			p += ETH_GSTRING_LEN; | ||||
| 		} | ||||
| 		for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) { | ||||
| 			snprintf(p, ETH_GSTRING_LEN, "tx-%u.packets", i); | ||||
| 			p += ETH_GSTRING_LEN; | ||||
| 			snprintf(p, ETH_GSTRING_LEN, "tx-%u.bytes", i); | ||||
| 			p += ETH_GSTRING_LEN; | ||||
| 		} | ||||
| 		for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) { | ||||
| 			snprintf(p, ETH_GSTRING_LEN, "rx-%u.packets", i); | ||||
| 			p += ETH_GSTRING_LEN; | ||||
| 			snprintf(p, ETH_GSTRING_LEN, "rx-%u.bytes", i); | ||||
| 			p += ETH_GSTRING_LEN; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_msglevel - Get debug message level | ||||
|  * @netdev: network interface device structure | ||||
|  * | ||||
|  * Returns current debug message level. | ||||
|  **/ | ||||
| static u32 i40evf_get_msglevel(struct net_device *netdev) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	return adapter->msg_enable; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_msglevel - Set debug message level | ||||
|  * @netdev: network interface device structure | ||||
|  * @data: message level | ||||
|  * | ||||
|  * Set current debug message level. Higher values cause the driver to | ||||
|  * be noisier. | ||||
|  **/ | ||||
| static void i40evf_set_msglevel(struct net_device *netdev, u32 data) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	adapter->msg_enable = data; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_drvinfo - Get driver info | ||||
|  * @netdev: network interface device structure | ||||
|  * @drvinfo: ethool driver info structure | ||||
|  * | ||||
|  * Returns information about the driver and device for display to the user. | ||||
|  **/ | ||||
| static void i40evf_get_drvinfo(struct net_device *netdev, | ||||
| 			       struct ethtool_drvinfo *drvinfo) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 
 | ||||
| 	strlcpy(drvinfo->driver, i40evf_driver_name, 32); | ||||
| 	strlcpy(drvinfo->version, i40evf_driver_version, 32); | ||||
| 
 | ||||
| 	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_ringparam - Get ring parameters | ||||
|  * @netdev: network interface device structure | ||||
|  * @ring: ethtool ringparam structure | ||||
|  * | ||||
|  * Returns current ring parameters. TX and RX rings are reported separately, | ||||
|  * but the number of rings is not reported. | ||||
|  **/ | ||||
| static void i40evf_get_ringparam(struct net_device *netdev, | ||||
| 				  struct ethtool_ringparam *ring) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 
 | ||||
| 	ring->rx_max_pending = I40EVF_MAX_RXD; | ||||
| 	ring->tx_max_pending = I40EVF_MAX_TXD; | ||||
| 	ring->rx_pending = adapter->rx_desc_count; | ||||
| 	ring->tx_pending = adapter->tx_desc_count; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_set_ringparam - Set ring parameters | ||||
|  * @netdev: network interface device structure | ||||
|  * @ring: ethtool ringparam structure | ||||
|  * | ||||
|  * Sets ring parameters. TX and RX rings are controlled separately, but the | ||||
|  * number of rings is not specified, so all rings get the same settings. | ||||
|  **/ | ||||
| static int i40evf_set_ringparam(struct net_device *netdev, | ||||
| 				struct ethtool_ringparam *ring) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	u32 new_rx_count, new_tx_count; | ||||
| 
 | ||||
| 	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	new_tx_count = clamp_t(u32, ring->tx_pending, | ||||
| 			       I40EVF_MIN_TXD, | ||||
| 			       I40EVF_MAX_TXD); | ||||
| 	new_tx_count = ALIGN(new_tx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE); | ||||
| 
 | ||||
| 	new_rx_count = clamp_t(u32, ring->rx_pending, | ||||
| 			       I40EVF_MIN_RXD, | ||||
| 			       I40EVF_MAX_RXD); | ||||
| 	new_rx_count = ALIGN(new_rx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE); | ||||
| 
 | ||||
| 	/* if nothing to do return success */ | ||||
| 	if ((new_tx_count == adapter->tx_desc_count) && | ||||
| 	    (new_rx_count == adapter->rx_desc_count)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	adapter->tx_desc_count = new_tx_count; | ||||
| 	adapter->rx_desc_count = new_rx_count; | ||||
| 
 | ||||
| 	if (netif_running(netdev)) | ||||
| 		i40evf_reinit_locked(adapter); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_coalesce - Get interrupt coalescing settings | ||||
|  * @netdev: network interface device structure | ||||
|  * @ec: ethtool coalesce structure | ||||
|  * | ||||
|  * Returns current coalescing settings. This is referred to elsewhere in the | ||||
|  * driver as Interrupt Throttle Rate, as this is how the hardware describes | ||||
|  * this functionality. | ||||
|  **/ | ||||
| static int i40evf_get_coalesce(struct net_device *netdev, | ||||
| 			     struct ethtool_coalesce *ec) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	struct i40e_vsi *vsi = &adapter->vsi; | ||||
| 
 | ||||
| 	ec->tx_max_coalesced_frames = vsi->work_limit; | ||||
| 	ec->rx_max_coalesced_frames = vsi->work_limit; | ||||
| 
 | ||||
| 	if (ITR_IS_DYNAMIC(vsi->rx_itr_setting)) | ||||
| 		ec->use_adaptive_rx_coalesce = 1; | ||||
| 
 | ||||
| 	if (ITR_IS_DYNAMIC(vsi->tx_itr_setting)) | ||||
| 		ec->use_adaptive_tx_coalesce = 1; | ||||
| 
 | ||||
| 	ec->rx_coalesce_usecs = vsi->rx_itr_setting & ~I40E_ITR_DYNAMIC; | ||||
| 	ec->tx_coalesce_usecs = vsi->tx_itr_setting & ~I40E_ITR_DYNAMIC; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_set_coalesce - Set interrupt coalescing settings | ||||
|  * @netdev: network interface device structure | ||||
|  * @ec: ethtool coalesce structure | ||||
|  * | ||||
|  * Change current coalescing settings. | ||||
|  **/ | ||||
| static int i40evf_set_coalesce(struct net_device *netdev, | ||||
| 			     struct ethtool_coalesce *ec) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	struct i40e_hw *hw = &adapter->hw; | ||||
| 	struct i40e_vsi *vsi = &adapter->vsi; | ||||
| 	struct i40e_q_vector *q_vector; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq) | ||||
| 		vsi->work_limit = ec->tx_max_coalesced_frames_irq; | ||||
| 
 | ||||
| 	if ((ec->rx_coalesce_usecs >= (I40E_MIN_ITR << 1)) && | ||||
| 	    (ec->rx_coalesce_usecs <= (I40E_MAX_ITR << 1))) | ||||
| 		vsi->rx_itr_setting = ec->rx_coalesce_usecs; | ||||
| 
 | ||||
| 	else | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if ((ec->tx_coalesce_usecs >= (I40E_MIN_ITR << 1)) && | ||||
| 	    (ec->tx_coalesce_usecs <= (I40E_MAX_ITR << 1))) | ||||
| 		vsi->tx_itr_setting = ec->tx_coalesce_usecs; | ||||
| 	else if (ec->use_adaptive_tx_coalesce) | ||||
| 		vsi->tx_itr_setting = (I40E_ITR_DYNAMIC | | ||||
| 				       ITR_REG_TO_USEC(I40E_ITR_RX_DEF)); | ||||
| 	else | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (ec->use_adaptive_rx_coalesce) | ||||
| 		vsi->rx_itr_setting |= I40E_ITR_DYNAMIC; | ||||
| 	else | ||||
| 		vsi->rx_itr_setting &= ~I40E_ITR_DYNAMIC; | ||||
| 
 | ||||
| 	if (ec->use_adaptive_tx_coalesce) | ||||
| 		vsi->tx_itr_setting |= I40E_ITR_DYNAMIC; | ||||
| 	else | ||||
| 		vsi->tx_itr_setting &= ~I40E_ITR_DYNAMIC; | ||||
| 
 | ||||
| 	for (i = 0; i < adapter->num_msix_vectors - NONQ_VECS; i++) { | ||||
| 		q_vector = adapter->q_vector[i]; | ||||
| 		q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting); | ||||
| 		wr32(hw, I40E_VFINT_ITRN1(0, i), q_vector->rx.itr); | ||||
| 		q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting); | ||||
| 		wr32(hw, I40E_VFINT_ITRN1(1, i), q_vector->tx.itr); | ||||
| 		i40e_flush(hw); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40e_get_rss_hash_opts - Get RSS hash Input Set for each flow type | ||||
|  * @adapter: board private structure | ||||
|  * @cmd: ethtool rxnfc command | ||||
|  * | ||||
|  * Returns Success if the flow is supported, else Invalid Input. | ||||
|  **/ | ||||
| static int i40evf_get_rss_hash_opts(struct i40evf_adapter *adapter, | ||||
| 				    struct ethtool_rxnfc *cmd) | ||||
| { | ||||
| 	struct i40e_hw *hw = &adapter->hw; | ||||
| 	u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) | | ||||
| 		   ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32); | ||||
| 
 | ||||
| 	/* We always hash on IP src and dest addresses */ | ||||
| 	cmd->data = RXH_IP_SRC | RXH_IP_DST; | ||||
| 
 | ||||
| 	switch (cmd->flow_type) { | ||||
| 	case TCP_V4_FLOW: | ||||
| 		if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP)) | ||||
| 			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | ||||
| 		break; | ||||
| 	case UDP_V4_FLOW: | ||||
| 		if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP)) | ||||
| 			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | ||||
| 		break; | ||||
| 
 | ||||
| 	case SCTP_V4_FLOW: | ||||
| 	case AH_ESP_V4_FLOW: | ||||
| 	case AH_V4_FLOW: | ||||
| 	case ESP_V4_FLOW: | ||||
| 	case IPV4_FLOW: | ||||
| 		break; | ||||
| 
 | ||||
| 	case TCP_V6_FLOW: | ||||
| 		if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP)) | ||||
| 			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | ||||
| 		break; | ||||
| 	case UDP_V6_FLOW: | ||||
| 		if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP)) | ||||
| 			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | ||||
| 		break; | ||||
| 
 | ||||
| 	case SCTP_V6_FLOW: | ||||
| 	case AH_ESP_V6_FLOW: | ||||
| 	case AH_V6_FLOW: | ||||
| 	case ESP_V6_FLOW: | ||||
| 	case IPV6_FLOW: | ||||
| 		break; | ||||
| 	default: | ||||
| 		cmd->data = 0; | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_rxnfc - command to get RX flow classification rules | ||||
|  * @netdev: network interface device structure | ||||
|  * @cmd: ethtool rxnfc command | ||||
|  * | ||||
|  * Returns Success if the command is supported. | ||||
|  **/ | ||||
| static int i40evf_get_rxnfc(struct net_device *netdev, | ||||
| 			    struct ethtool_rxnfc *cmd, | ||||
| 			    u32 *rule_locs) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	int ret = -EOPNOTSUPP; | ||||
| 
 | ||||
| 	switch (cmd->cmd) { | ||||
| 	case ETHTOOL_GRXRINGS: | ||||
| 		cmd->data = adapter->vsi_res->num_queue_pairs; | ||||
| 		ret = 0; | ||||
| 		break; | ||||
| 	case ETHTOOL_GRXFH: | ||||
| 		ret = i40evf_get_rss_hash_opts(adapter, cmd); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_set_rss_hash_opt - Enable/Disable flow types for RSS hash | ||||
|  * @adapter: board private structure | ||||
|  * @cmd: ethtool rxnfc command | ||||
|  * | ||||
|  * Returns Success if the flow input set is supported. | ||||
|  **/ | ||||
| static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, | ||||
| 				   struct ethtool_rxnfc *nfc) | ||||
| { | ||||
| 	struct i40e_hw *hw = &adapter->hw; | ||||
| 
 | ||||
| 	u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) | | ||||
| 		   ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32); | ||||
| 
 | ||||
| 	/* RSS does not support anything other than hashing
 | ||||
| 	 * to queues on src and dst IPs and ports | ||||
| 	 */ | ||||
| 	if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | | ||||
| 			  RXH_L4_B_0_1 | RXH_L4_B_2_3)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* We need at least the IP SRC and DEST fields for hashing */ | ||||
| 	if (!(nfc->data & RXH_IP_SRC) || | ||||
| 	    !(nfc->data & RXH_IP_DST)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	switch (nfc->flow_type) { | ||||
| 	case TCP_V4_FLOW: | ||||
| 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { | ||||
| 		case 0: | ||||
| 			hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); | ||||
| 			break; | ||||
| 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3): | ||||
| 			hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); | ||||
| 			break; | ||||
| 		default: | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		break; | ||||
| 	case TCP_V6_FLOW: | ||||
| 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { | ||||
| 		case 0: | ||||
| 			hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); | ||||
| 			break; | ||||
| 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3): | ||||
| 			hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); | ||||
| 			break; | ||||
| 		default: | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		break; | ||||
| 	case UDP_V4_FLOW: | ||||
| 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { | ||||
| 		case 0: | ||||
| 			hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | | ||||
| 				  ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); | ||||
| 			break; | ||||
| 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3): | ||||
| 			hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | | ||||
| 				 ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); | ||||
| 			break; | ||||
| 		default: | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		break; | ||||
| 	case UDP_V6_FLOW: | ||||
| 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { | ||||
| 		case 0: | ||||
| 			hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | | ||||
| 				  ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); | ||||
| 			break; | ||||
| 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3): | ||||
| 			hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | | ||||
| 				 ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); | ||||
| 			break; | ||||
| 		default: | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		break; | ||||
| 	case AH_ESP_V4_FLOW: | ||||
| 	case AH_V4_FLOW: | ||||
| 	case ESP_V4_FLOW: | ||||
| 	case SCTP_V4_FLOW: | ||||
| 		if ((nfc->data & RXH_L4_B_0_1) || | ||||
| 		    (nfc->data & RXH_L4_B_2_3)) | ||||
| 			return -EINVAL; | ||||
| 		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); | ||||
| 		break; | ||||
| 	case AH_ESP_V6_FLOW: | ||||
| 	case AH_V6_FLOW: | ||||
| 	case ESP_V6_FLOW: | ||||
| 	case SCTP_V6_FLOW: | ||||
| 		if ((nfc->data & RXH_L4_B_0_1) || | ||||
| 		    (nfc->data & RXH_L4_B_2_3)) | ||||
| 			return -EINVAL; | ||||
| 		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); | ||||
| 		break; | ||||
| 	case IPV4_FLOW: | ||||
| 		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | | ||||
| 			((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4); | ||||
| 		break; | ||||
| 	case IPV6_FLOW: | ||||
| 		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | | ||||
| 			((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	wr32(hw, I40E_VFQF_HENA(0), (u32)hena); | ||||
| 	wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32)); | ||||
| 	i40e_flush(hw); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_set_rxnfc - command to set RX flow classification rules | ||||
|  * @netdev: network interface device structure | ||||
|  * @cmd: ethtool rxnfc command | ||||
|  * | ||||
|  * Returns Success if the command is supported. | ||||
|  **/ | ||||
| static int i40evf_set_rxnfc(struct net_device *netdev, | ||||
| 			    struct ethtool_rxnfc *cmd) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	int ret = -EOPNOTSUPP; | ||||
| 
 | ||||
| 	switch (cmd->cmd) { | ||||
| 	case ETHTOOL_SRXFH: | ||||
| 		ret = i40evf_set_rss_hash_opt(adapter, cmd); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_channels: get the number of channels supported by the device | ||||
|  * @netdev: network interface device structure | ||||
|  * @ch: channel information structure | ||||
|  * | ||||
|  * For the purposes of our device, we only use combined channels, i.e. a tx/rx | ||||
|  * queue pair. Report one extra channel to match our "other" MSI-X vector. | ||||
|  **/ | ||||
| static void i40evf_get_channels(struct net_device *netdev, | ||||
| 				struct ethtool_channels *ch) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 
 | ||||
| 	/* Report maximum channels */ | ||||
| 	ch->max_combined = adapter->vsi_res->num_queue_pairs; | ||||
| 
 | ||||
| 	ch->max_other = NONQ_VECS; | ||||
| 	ch->other_count = NONQ_VECS; | ||||
| 
 | ||||
| 	ch->combined_count = adapter->vsi_res->num_queue_pairs; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_rxfh_indir_size - get the rx flow hash indirection table size | ||||
|  * @netdev: network interface device structure | ||||
|  * | ||||
|  * Returns the table size. | ||||
|  **/ | ||||
| static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev) | ||||
| { | ||||
| 	return (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_rxfh - get the rx flow hash indirection table | ||||
|  * @netdev: network interface device structure | ||||
|  * @indir: indirection table | ||||
|  * @key: hash key (will be %NULL until get_rxfh_key_size is implemented) | ||||
|  * | ||||
|  * Reads the indirection table directly from the hardware. Always returns 0. | ||||
|  **/ | ||||
| static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	struct i40e_hw *hw = &adapter->hw; | ||||
| 	u32 hlut_val; | ||||
| 	int i, j; | ||||
| 
 | ||||
| 	for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) { | ||||
| 		hlut_val = rd32(hw, I40E_VFQF_HLUT(i)); | ||||
| 		indir[j++] = hlut_val & 0xff; | ||||
| 		indir[j++] = (hlut_val >> 8) & 0xff; | ||||
| 		indir[j++] = (hlut_val >> 16) & 0xff; | ||||
| 		indir[j++] = (hlut_val >> 24) & 0xff; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_set_rxfh - set the rx flow hash indirection table | ||||
|  * @netdev: network interface device structure | ||||
|  * @indir: indirection table | ||||
|  * @key: hash key (will be %NULL until get_rxfh_key_size is implemented) | ||||
|  * | ||||
|  * Returns -EINVAL if the table specifies an inavlid queue id, otherwise | ||||
|  * returns 0 after programming the table. | ||||
|  **/ | ||||
| static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir, | ||||
| 			   const u8 *key) | ||||
| { | ||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||
| 	struct i40e_hw *hw = &adapter->hw; | ||||
| 	u32 hlut_val; | ||||
| 	int i, j; | ||||
| 
 | ||||
| 	for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) { | ||||
| 		hlut_val = indir[j++]; | ||||
| 		hlut_val |= indir[j++] << 8; | ||||
| 		hlut_val |= indir[j++] << 16; | ||||
| 		hlut_val |= indir[j++] << 24; | ||||
| 		wr32(hw, I40E_VFQF_HLUT(i), hlut_val); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct ethtool_ops i40evf_ethtool_ops = { | ||||
| 	.get_settings		= i40evf_get_settings, | ||||
| 	.get_drvinfo		= i40evf_get_drvinfo, | ||||
| 	.get_link		= ethtool_op_get_link, | ||||
| 	.get_ringparam		= i40evf_get_ringparam, | ||||
| 	.set_ringparam		= i40evf_set_ringparam, | ||||
| 	.get_strings		= i40evf_get_strings, | ||||
| 	.get_ethtool_stats	= i40evf_get_ethtool_stats, | ||||
| 	.get_sset_count		= i40evf_get_sset_count, | ||||
| 	.get_msglevel		= i40evf_get_msglevel, | ||||
| 	.set_msglevel		= i40evf_set_msglevel, | ||||
| 	.get_coalesce		= i40evf_get_coalesce, | ||||
| 	.set_coalesce		= i40evf_set_coalesce, | ||||
| 	.get_rxnfc		= i40evf_get_rxnfc, | ||||
| 	.set_rxnfc		= i40evf_set_rxnfc, | ||||
| 	.get_rxfh_indir_size	= i40evf_get_rxfh_indir_size, | ||||
| 	.get_rxfh		= i40evf_get_rxfh, | ||||
| 	.set_rxfh		= i40evf_set_rxfh, | ||||
| 	.get_channels		= i40evf_get_channels, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_set_ethtool_ops - Initialize ethtool ops struct | ||||
|  * @netdev: network interface device structure | ||||
|  * | ||||
|  * Sets ethtool ops struct in our netdev so that ethtool can call | ||||
|  * our functions. | ||||
|  **/ | ||||
| void i40evf_set_ethtool_ops(struct net_device *netdev) | ||||
| { | ||||
| 	netdev->ethtool_ops = &i40evf_ethtool_ops; | ||||
| } | ||||
							
								
								
									
										2527
									
								
								drivers/net/ethernet/intel/i40evf/i40evf_main.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2527
									
								
								drivers/net/ethernet/intel/i40evf/i40evf_main.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										781
									
								
								drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										781
									
								
								drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,781 @@ | |||
| /*******************************************************************************
 | ||||
|  * | ||||
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | ||||
|  * Copyright(c) 2013 - 2014 Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * The full GNU General Public License is included in this distribution in | ||||
|  * the file called "COPYING". | ||||
|  * | ||||
|  * Contact Information: | ||||
|  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||||
|  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||||
|  * | ||||
|  ******************************************************************************/ | ||||
| 
 | ||||
| #include "i40evf.h" | ||||
| #include "i40e_prototype.h" | ||||
| 
 | ||||
| /* busy wait delay in msec */ | ||||
| #define I40EVF_BUSY_WAIT_DELAY 10 | ||||
| #define I40EVF_BUSY_WAIT_COUNT 50 | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_send_pf_msg | ||||
|  * @adapter: adapter structure | ||||
|  * @op: virtual channel opcode | ||||
|  * @msg: pointer to message buffer | ||||
|  * @len: message length | ||||
|  * | ||||
|  * Send message to PF and print status if failure. | ||||
|  **/ | ||||
| static int i40evf_send_pf_msg(struct i40evf_adapter *adapter, | ||||
| 			      enum i40e_virtchnl_ops op, u8 *msg, u16 len) | ||||
| { | ||||
| 	struct i40e_hw *hw = &adapter->hw; | ||||
| 	i40e_status err; | ||||
| 
 | ||||
| 	if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) | ||||
| 		return 0; /* nothing to see here, move along */ | ||||
| 
 | ||||
| 	err = i40e_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL); | ||||
| 	if (err) | ||||
| 		dev_err(&adapter->pdev->dev, "Unable to send opcode %d to PF, error %d, aq status %d\n", | ||||
| 			op, err, hw->aq.asq_last_status); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_send_api_ver | ||||
|  * @adapter: adapter structure | ||||
|  * | ||||
|  * Send API version admin queue message to the PF. The reply is not checked | ||||
|  * in this function. Returns 0 if the message was successfully | ||||
|  * sent, or one of the I40E_ADMIN_QUEUE_ERROR_ statuses if not. | ||||
|  **/ | ||||
| int i40evf_send_api_ver(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_version_info vvi; | ||||
| 
 | ||||
| 	vvi.major = I40E_VIRTCHNL_VERSION_MAJOR; | ||||
| 	vvi.minor = I40E_VIRTCHNL_VERSION_MINOR; | ||||
| 
 | ||||
| 	return i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_VERSION, (u8 *)&vvi, | ||||
| 				  sizeof(vvi)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_verify_api_ver | ||||
|  * @adapter: adapter structure | ||||
|  * | ||||
|  * Compare API versions with the PF. Must be called after admin queue is | ||||
|  * initialized. Returns 0 if API versions match, -EIO if they do not, | ||||
|  * I40E_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty, and any errors | ||||
|  * from the firmware are propagated. | ||||
|  **/ | ||||
| int i40evf_verify_api_ver(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_version_info *pf_vvi; | ||||
| 	struct i40e_hw *hw = &adapter->hw; | ||||
| 	struct i40e_arq_event_info event; | ||||
| 	i40e_status err; | ||||
| 
 | ||||
| 	event.msg_size = I40EVF_MAX_AQ_BUF_SIZE; | ||||
| 	event.msg_buf = kzalloc(event.msg_size, GFP_KERNEL); | ||||
| 	if (!event.msg_buf) { | ||||
| 		err = -ENOMEM; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	err = i40evf_clean_arq_element(hw, &event, NULL); | ||||
| 	if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) | ||||
| 		goto out_alloc; | ||||
| 
 | ||||
| 	err = (i40e_status)le32_to_cpu(event.desc.cookie_low); | ||||
| 	if (err) | ||||
| 		goto out_alloc; | ||||
| 
 | ||||
| 	if ((enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high) != | ||||
| 	    I40E_VIRTCHNL_OP_VERSION) { | ||||
| 		dev_info(&adapter->pdev->dev, "Invalid reply type %d from PF\n", | ||||
| 			 le32_to_cpu(event.desc.cookie_high)); | ||||
| 		err = -EIO; | ||||
| 		goto out_alloc; | ||||
| 	} | ||||
| 
 | ||||
| 	pf_vvi = (struct i40e_virtchnl_version_info *)event.msg_buf; | ||||
| 	if ((pf_vvi->major != I40E_VIRTCHNL_VERSION_MAJOR) || | ||||
| 	    (pf_vvi->minor != I40E_VIRTCHNL_VERSION_MINOR)) | ||||
| 		err = -EIO; | ||||
| 
 | ||||
| out_alloc: | ||||
| 	kfree(event.msg_buf); | ||||
| out: | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_send_vf_config_msg | ||||
|  * @adapter: adapter structure | ||||
|  * | ||||
|  * Send VF configuration request admin queue message to the PF. The reply | ||||
|  * is not checked in this function. Returns 0 if the message was | ||||
|  * successfully sent, or one of the I40E_ADMIN_QUEUE_ERROR_ statuses if not. | ||||
|  **/ | ||||
| int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	return i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, | ||||
| 				  NULL, 0); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_get_vf_config | ||||
|  * @hw: pointer to the hardware structure | ||||
|  * @len: length of buffer | ||||
|  * | ||||
|  * Get VF configuration from PF and populate hw structure. Must be called after | ||||
|  * admin queue is initialized. Busy waits until response is received from PF, | ||||
|  * with maximum timeout. Response from PF is returned in the buffer for further | ||||
|  * processing by the caller. | ||||
|  **/ | ||||
| int i40evf_get_vf_config(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_hw *hw = &adapter->hw; | ||||
| 	struct i40e_arq_event_info event; | ||||
| 	u16 len; | ||||
| 	i40e_status err; | ||||
| 
 | ||||
| 	len =  sizeof(struct i40e_virtchnl_vf_resource) + | ||||
| 		I40E_MAX_VF_VSI * sizeof(struct i40e_virtchnl_vsi_resource); | ||||
| 	event.msg_size = len; | ||||
| 	event.msg_buf = kzalloc(event.msg_size, GFP_KERNEL); | ||||
| 	if (!event.msg_buf) { | ||||
| 		err = -ENOMEM; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	err = i40evf_clean_arq_element(hw, &event, NULL); | ||||
| 	if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) | ||||
| 		goto out_alloc; | ||||
| 
 | ||||
| 	err = (i40e_status)le32_to_cpu(event.desc.cookie_low); | ||||
| 	if (err) { | ||||
| 		dev_err(&adapter->pdev->dev, | ||||
| 			"%s: Error returned from PF, %d, %d\n", __func__, | ||||
| 			le32_to_cpu(event.desc.cookie_high), | ||||
| 			le32_to_cpu(event.desc.cookie_low)); | ||||
| 		err = -EIO; | ||||
| 		goto out_alloc; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high) != | ||||
| 	    I40E_VIRTCHNL_OP_GET_VF_RESOURCES) { | ||||
| 		dev_err(&adapter->pdev->dev, | ||||
| 			"%s: Invalid response from PF, %d, %d\n", __func__, | ||||
| 			le32_to_cpu(event.desc.cookie_high), | ||||
| 			le32_to_cpu(event.desc.cookie_low)); | ||||
| 		err = -EIO; | ||||
| 		goto out_alloc; | ||||
| 	} | ||||
| 	memcpy(adapter->vf_res, event.msg_buf, min(event.msg_size, len)); | ||||
| 
 | ||||
| 	i40e_vf_parse_hw_config(hw, adapter->vf_res); | ||||
| out_alloc: | ||||
| 	kfree(event.msg_buf); | ||||
| out: | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_configure_queues | ||||
|  * @adapter: adapter structure | ||||
|  * | ||||
|  * Request that the PF set up our (previously allocated) queues. | ||||
|  **/ | ||||
| void i40evf_configure_queues(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_vsi_queue_config_info *vqci; | ||||
| 	struct i40e_virtchnl_queue_pair_info *vqpi; | ||||
| 	int pairs = adapter->vsi_res->num_queue_pairs; | ||||
| 	int i, len; | ||||
| 
 | ||||
| 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { | ||||
| 		/* bail because we already have a command pending */ | ||||
| 		dev_err(&adapter->pdev->dev, "%s: command %d pending\n", | ||||
| 			__func__, adapter->current_op); | ||||
| 		return; | ||||
| 	} | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES; | ||||
| 	len = sizeof(struct i40e_virtchnl_vsi_queue_config_info) + | ||||
| 		       (sizeof(struct i40e_virtchnl_queue_pair_info) * pairs); | ||||
| 	vqci = kzalloc(len, GFP_ATOMIC); | ||||
| 	if (!vqci) | ||||
| 		return; | ||||
| 
 | ||||
| 	vqci->vsi_id = adapter->vsi_res->vsi_id; | ||||
| 	vqci->num_queue_pairs = pairs; | ||||
| 	vqpi = vqci->qpair; | ||||
| 	/* Size check is not needed here - HW max is 16 queue pairs, and we
 | ||||
| 	 * can fit info for 31 of them into the AQ buffer before it overflows. | ||||
| 	 */ | ||||
| 	for (i = 0; i < pairs; i++) { | ||||
| 		vqpi->txq.vsi_id = vqci->vsi_id; | ||||
| 		vqpi->txq.queue_id = i; | ||||
| 		vqpi->txq.ring_len = adapter->tx_rings[i]->count; | ||||
| 		vqpi->txq.dma_ring_addr = adapter->tx_rings[i]->dma; | ||||
| 		vqpi->txq.headwb_enabled = 1; | ||||
| 		vqpi->txq.dma_headwb_addr = vqpi->txq.dma_ring_addr + | ||||
| 		    (vqpi->txq.ring_len * sizeof(struct i40e_tx_desc)); | ||||
| 
 | ||||
| 		vqpi->rxq.vsi_id = vqci->vsi_id; | ||||
| 		vqpi->rxq.queue_id = i; | ||||
| 		vqpi->rxq.ring_len = adapter->rx_rings[i]->count; | ||||
| 		vqpi->rxq.dma_ring_addr = adapter->rx_rings[i]->dma; | ||||
| 		vqpi->rxq.max_pkt_size = adapter->netdev->mtu | ||||
| 					+ ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN; | ||||
| 		vqpi->rxq.databuffer_size = adapter->rx_rings[i]->rx_buf_len; | ||||
| 		vqpi++; | ||||
| 	} | ||||
| 
 | ||||
| 	adapter->aq_pending |= I40EVF_FLAG_AQ_CONFIGURE_QUEUES; | ||||
| 	adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_QUEUES; | ||||
| 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, | ||||
| 			   (u8 *)vqci, len); | ||||
| 	kfree(vqci); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_enable_queues | ||||
|  * @adapter: adapter structure | ||||
|  * | ||||
|  * Request that the PF enable all of our queues. | ||||
|  **/ | ||||
| void i40evf_enable_queues(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_queue_select vqs; | ||||
| 
 | ||||
| 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { | ||||
| 		/* bail because we already have a command pending */ | ||||
| 		dev_err(&adapter->pdev->dev, "%s: command %d pending\n", | ||||
| 			__func__, adapter->current_op); | ||||
| 		return; | ||||
| 	} | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_ENABLE_QUEUES; | ||||
| 	vqs.vsi_id = adapter->vsi_res->vsi_id; | ||||
| 	vqs.tx_queues = (1 << adapter->vsi_res->num_queue_pairs) - 1; | ||||
| 	vqs.rx_queues = vqs.tx_queues; | ||||
| 	adapter->aq_pending |= I40EVF_FLAG_AQ_ENABLE_QUEUES; | ||||
| 	adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_QUEUES; | ||||
| 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ENABLE_QUEUES, | ||||
| 			   (u8 *)&vqs, sizeof(vqs)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_disable_queues | ||||
|  * @adapter: adapter structure | ||||
|  * | ||||
|  * Request that the PF disable all of our queues. | ||||
|  **/ | ||||
| void i40evf_disable_queues(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_queue_select vqs; | ||||
| 
 | ||||
| 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { | ||||
| 		/* bail because we already have a command pending */ | ||||
| 		dev_err(&adapter->pdev->dev, "%s: command %d pending\n", | ||||
| 			__func__, adapter->current_op); | ||||
| 		return; | ||||
| 	} | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_DISABLE_QUEUES; | ||||
| 	vqs.vsi_id = adapter->vsi_res->vsi_id; | ||||
| 	vqs.tx_queues = (1 << adapter->vsi_res->num_queue_pairs) - 1; | ||||
| 	vqs.rx_queues = vqs.tx_queues; | ||||
| 	adapter->aq_pending |= I40EVF_FLAG_AQ_DISABLE_QUEUES; | ||||
| 	adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_QUEUES; | ||||
| 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DISABLE_QUEUES, | ||||
| 			   (u8 *)&vqs, sizeof(vqs)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_map_queues | ||||
|  * @adapter: adapter structure | ||||
|  * | ||||
|  * Request that the PF map queues to interrupt vectors. Misc causes, including | ||||
|  * admin queue, are always mapped to vector 0. | ||||
|  **/ | ||||
| void i40evf_map_queues(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_irq_map_info *vimi; | ||||
| 	int v_idx, q_vectors, len; | ||||
| 	struct i40e_q_vector *q_vector; | ||||
| 
 | ||||
| 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { | ||||
| 		/* bail because we already have a command pending */ | ||||
| 		dev_err(&adapter->pdev->dev, "%s: command %d pending\n", | ||||
| 			__func__, adapter->current_op); | ||||
| 		return; | ||||
| 	} | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP; | ||||
| 
 | ||||
| 	q_vectors = adapter->num_msix_vectors - NONQ_VECS; | ||||
| 
 | ||||
| 	len = sizeof(struct i40e_virtchnl_irq_map_info) + | ||||
| 	      (adapter->num_msix_vectors * | ||||
| 		sizeof(struct i40e_virtchnl_vector_map)); | ||||
| 	vimi = kzalloc(len, GFP_ATOMIC); | ||||
| 	if (!vimi) | ||||
| 		return; | ||||
| 
 | ||||
| 	vimi->num_vectors = adapter->num_msix_vectors; | ||||
| 	/* Queue vectors first */ | ||||
| 	for (v_idx = 0; v_idx < q_vectors; v_idx++) { | ||||
| 		q_vector = adapter->q_vector[v_idx]; | ||||
| 		vimi->vecmap[v_idx].vsi_id = adapter->vsi_res->vsi_id; | ||||
| 		vimi->vecmap[v_idx].vector_id = v_idx + NONQ_VECS; | ||||
| 		vimi->vecmap[v_idx].txq_map = q_vector->ring_mask; | ||||
| 		vimi->vecmap[v_idx].rxq_map = q_vector->ring_mask; | ||||
| 	} | ||||
| 	/* Misc vector last - this is only for AdminQ messages */ | ||||
| 	vimi->vecmap[v_idx].vsi_id = adapter->vsi_res->vsi_id; | ||||
| 	vimi->vecmap[v_idx].vector_id = 0; | ||||
| 	vimi->vecmap[v_idx].txq_map = 0; | ||||
| 	vimi->vecmap[v_idx].rxq_map = 0; | ||||
| 
 | ||||
| 	adapter->aq_pending |= I40EVF_FLAG_AQ_MAP_VECTORS; | ||||
| 	adapter->aq_required &= ~I40EVF_FLAG_AQ_MAP_VECTORS; | ||||
| 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, | ||||
| 			   (u8 *)vimi, len); | ||||
| 	kfree(vimi); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_add_ether_addrs | ||||
|  * @adapter: adapter structure | ||||
|  * @addrs: the MAC address filters to add (contiguous) | ||||
|  * @count: number of filters | ||||
|  * | ||||
|  * Request that the PF add one or more addresses to our filters. | ||||
|  **/ | ||||
| void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_ether_addr_list *veal; | ||||
| 	int len, i = 0, count = 0; | ||||
| 	struct i40evf_mac_filter *f; | ||||
| 
 | ||||
| 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { | ||||
| 		/* bail because we already have a command pending */ | ||||
| 		dev_err(&adapter->pdev->dev, "%s: command %d pending\n", | ||||
| 			__func__, adapter->current_op); | ||||
| 		return; | ||||
| 	} | ||||
| 	list_for_each_entry(f, &adapter->mac_filter_list, list) { | ||||
| 		if (f->add) | ||||
| 			count++; | ||||
| 	} | ||||
| 	if (!count) { | ||||
| 		adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER; | ||||
| 		return; | ||||
| 	} | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS; | ||||
| 
 | ||||
| 	len = sizeof(struct i40e_virtchnl_ether_addr_list) + | ||||
| 	      (count * sizeof(struct i40e_virtchnl_ether_addr)); | ||||
| 	if (len > I40EVF_MAX_AQ_BUF_SIZE) { | ||||
| 		dev_warn(&adapter->pdev->dev, "%s: Too many MAC address changes in one request\n", | ||||
| 			__func__); | ||||
| 		count = (I40EVF_MAX_AQ_BUF_SIZE - | ||||
| 			 sizeof(struct i40e_virtchnl_ether_addr_list)) / | ||||
| 			sizeof(struct i40e_virtchnl_ether_addr); | ||||
| 		len = I40EVF_MAX_AQ_BUF_SIZE; | ||||
| 	} | ||||
| 
 | ||||
| 	veal = kzalloc(len, GFP_ATOMIC); | ||||
| 	if (!veal) | ||||
| 		return; | ||||
| 
 | ||||
| 	veal->vsi_id = adapter->vsi_res->vsi_id; | ||||
| 	veal->num_elements = count; | ||||
| 	list_for_each_entry(f, &adapter->mac_filter_list, list) { | ||||
| 		if (f->add) { | ||||
| 			ether_addr_copy(veal->list[i].addr, f->macaddr); | ||||
| 			i++; | ||||
| 			f->add = false; | ||||
| 		} | ||||
| 	} | ||||
| 	adapter->aq_pending |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; | ||||
| 	adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER; | ||||
| 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, | ||||
| 			   (u8 *)veal, len); | ||||
| 	kfree(veal); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_del_ether_addrs | ||||
|  * @adapter: adapter structure | ||||
|  * @addrs: the MAC address filters to remove (contiguous) | ||||
|  * @count: number of filtes | ||||
|  * | ||||
|  * Request that the PF remove one or more addresses from our filters. | ||||
|  **/ | ||||
| void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_ether_addr_list *veal; | ||||
| 	struct i40evf_mac_filter *f, *ftmp; | ||||
| 	int len, i = 0, count = 0; | ||||
| 
 | ||||
| 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { | ||||
| 		/* bail because we already have a command pending */ | ||||
| 		dev_err(&adapter->pdev->dev, "%s: command %d pending\n", | ||||
| 			__func__, adapter->current_op); | ||||
| 		return; | ||||
| 	} | ||||
| 	list_for_each_entry(f, &adapter->mac_filter_list, list) { | ||||
| 		if (f->remove) | ||||
| 			count++; | ||||
| 	} | ||||
| 	if (!count) { | ||||
| 		adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER; | ||||
| 		return; | ||||
| 	} | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS; | ||||
| 
 | ||||
| 	len = sizeof(struct i40e_virtchnl_ether_addr_list) + | ||||
| 	      (count * sizeof(struct i40e_virtchnl_ether_addr)); | ||||
| 	if (len > I40EVF_MAX_AQ_BUF_SIZE) { | ||||
| 		dev_warn(&adapter->pdev->dev, "%s: Too many MAC address changes in one request\n", | ||||
| 			__func__); | ||||
| 		count = (I40EVF_MAX_AQ_BUF_SIZE - | ||||
| 			 sizeof(struct i40e_virtchnl_ether_addr_list)) / | ||||
| 			sizeof(struct i40e_virtchnl_ether_addr); | ||||
| 		len = I40EVF_MAX_AQ_BUF_SIZE; | ||||
| 	} | ||||
| 	veal = kzalloc(len, GFP_ATOMIC); | ||||
| 	if (!veal) | ||||
| 		return; | ||||
| 
 | ||||
| 	veal->vsi_id = adapter->vsi_res->vsi_id; | ||||
| 	veal->num_elements = count; | ||||
| 	list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { | ||||
| 		if (f->remove) { | ||||
| 			ether_addr_copy(veal->list[i].addr, f->macaddr); | ||||
| 			i++; | ||||
| 			list_del(&f->list); | ||||
| 			kfree(f); | ||||
| 		} | ||||
| 	} | ||||
| 	adapter->aq_pending |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; | ||||
| 	adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER; | ||||
| 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS, | ||||
| 			   (u8 *)veal, len); | ||||
| 	kfree(veal); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_add_vlans | ||||
|  * @adapter: adapter structure | ||||
|  * @vlans: the VLANs to add | ||||
|  * @count: number of VLANs | ||||
|  * | ||||
|  * Request that the PF add one or more VLAN filters to our VSI. | ||||
|  **/ | ||||
| void i40evf_add_vlans(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_vlan_filter_list *vvfl; | ||||
| 	int len, i = 0, count = 0; | ||||
| 	struct i40evf_vlan_filter *f; | ||||
| 
 | ||||
| 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { | ||||
| 		/* bail because we already have a command pending */ | ||||
| 		dev_err(&adapter->pdev->dev, "%s: command %d pending\n", | ||||
| 			__func__, adapter->current_op); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	list_for_each_entry(f, &adapter->vlan_filter_list, list) { | ||||
| 		if (f->add) | ||||
| 			count++; | ||||
| 	} | ||||
| 	if (!count) { | ||||
| 		adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER; | ||||
| 		return; | ||||
| 	} | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_ADD_VLAN; | ||||
| 
 | ||||
| 	len = sizeof(struct i40e_virtchnl_vlan_filter_list) + | ||||
| 	      (count * sizeof(u16)); | ||||
| 	if (len > I40EVF_MAX_AQ_BUF_SIZE) { | ||||
| 		dev_warn(&adapter->pdev->dev, "%s: Too many VLAN changes in one request\n", | ||||
| 			__func__); | ||||
| 		count = (I40EVF_MAX_AQ_BUF_SIZE - | ||||
| 			 sizeof(struct i40e_virtchnl_vlan_filter_list)) / | ||||
| 			sizeof(u16); | ||||
| 		len = I40EVF_MAX_AQ_BUF_SIZE; | ||||
| 	} | ||||
| 	vvfl = kzalloc(len, GFP_ATOMIC); | ||||
| 	if (!vvfl) | ||||
| 		return; | ||||
| 
 | ||||
| 	vvfl->vsi_id = adapter->vsi_res->vsi_id; | ||||
| 	vvfl->num_elements = count; | ||||
| 	list_for_each_entry(f, &adapter->vlan_filter_list, list) { | ||||
| 		if (f->add) { | ||||
| 			vvfl->vlan_id[i] = f->vlan; | ||||
| 			i++; | ||||
| 			f->add = false; | ||||
| 		} | ||||
| 	} | ||||
| 	adapter->aq_pending |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; | ||||
| 	adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER; | ||||
| 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len); | ||||
| 	kfree(vvfl); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_del_vlans | ||||
|  * @adapter: adapter structure | ||||
|  * @vlans: the VLANs to remove | ||||
|  * @count: number of VLANs | ||||
|  * | ||||
|  * Request that the PF remove one or more VLAN filters from our VSI. | ||||
|  **/ | ||||
| void i40evf_del_vlans(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_vlan_filter_list *vvfl; | ||||
| 	struct i40evf_vlan_filter *f, *ftmp; | ||||
| 	int len, i = 0, count = 0; | ||||
| 
 | ||||
| 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { | ||||
| 		/* bail because we already have a command pending */ | ||||
| 		dev_err(&adapter->pdev->dev, "%s: command %d pending\n", | ||||
| 			__func__, adapter->current_op); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	list_for_each_entry(f, &adapter->vlan_filter_list, list) { | ||||
| 		if (f->remove) | ||||
| 			count++; | ||||
| 	} | ||||
| 	if (!count) { | ||||
| 		adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER; | ||||
| 		return; | ||||
| 	} | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_DEL_VLAN; | ||||
| 
 | ||||
| 	len = sizeof(struct i40e_virtchnl_vlan_filter_list) + | ||||
| 	      (count * sizeof(u16)); | ||||
| 	if (len > I40EVF_MAX_AQ_BUF_SIZE) { | ||||
| 		dev_warn(&adapter->pdev->dev, "%s: Too many VLAN changes in one request\n", | ||||
| 			__func__); | ||||
| 		count = (I40EVF_MAX_AQ_BUF_SIZE - | ||||
| 			 sizeof(struct i40e_virtchnl_vlan_filter_list)) / | ||||
| 			sizeof(u16); | ||||
| 		len = I40EVF_MAX_AQ_BUF_SIZE; | ||||
| 	} | ||||
| 	vvfl = kzalloc(len, GFP_ATOMIC); | ||||
| 	if (!vvfl) | ||||
| 		return; | ||||
| 
 | ||||
| 	vvfl->vsi_id = adapter->vsi_res->vsi_id; | ||||
| 	vvfl->num_elements = count; | ||||
| 	list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { | ||||
| 		if (f->remove) { | ||||
| 			vvfl->vlan_id[i] = f->vlan; | ||||
| 			i++; | ||||
| 			list_del(&f->list); | ||||
| 			kfree(f); | ||||
| 		} | ||||
| 	} | ||||
| 	adapter->aq_pending |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; | ||||
| 	adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER; | ||||
| 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len); | ||||
| 	kfree(vvfl); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_set_promiscuous | ||||
|  * @adapter: adapter structure | ||||
|  * @flags: bitmask to control unicast/multicast promiscuous. | ||||
|  * | ||||
|  * Request that the PF enable promiscuous mode for our VSI. | ||||
|  **/ | ||||
| void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags) | ||||
| { | ||||
| 	struct i40e_virtchnl_promisc_info vpi; | ||||
| 
 | ||||
| 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { | ||||
| 		/* bail because we already have a command pending */ | ||||
| 		dev_err(&adapter->pdev->dev, "%s: command %d pending\n", | ||||
| 			__func__, adapter->current_op); | ||||
| 		return; | ||||
| 	} | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE; | ||||
| 	vpi.vsi_id = adapter->vsi_res->vsi_id; | ||||
| 	vpi.flags = flags; | ||||
| 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, | ||||
| 			   (u8 *)&vpi, sizeof(vpi)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_request_stats | ||||
|  * @adapter: adapter structure | ||||
|  * | ||||
|  * Request VSI statistics from PF. | ||||
|  **/ | ||||
| void i40evf_request_stats(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	struct i40e_virtchnl_queue_select vqs; | ||||
| 	if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { | ||||
| 		/* no error message, this isn't crucial */ | ||||
| 		return; | ||||
| 	} | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_GET_STATS; | ||||
| 	vqs.vsi_id = adapter->vsi_res->vsi_id; | ||||
| 	/* queue maps are ignored for this message - only the vsi is used */ | ||||
| 	if (i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_GET_STATS, | ||||
| 			       (u8 *)&vqs, sizeof(vqs))) | ||||
| 		/* if the request failed, don't lock out others */ | ||||
| 		adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; | ||||
| } | ||||
| /**
 | ||||
|  * i40evf_request_reset | ||||
|  * @adapter: adapter structure | ||||
|  * | ||||
|  * Request that the PF reset this VF. No response is expected. | ||||
|  **/ | ||||
| void i40evf_request_reset(struct i40evf_adapter *adapter) | ||||
| { | ||||
| 	/* Don't check CURRENT_OP - this is always higher priority */ | ||||
| 	i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_RESET_VF, NULL, 0); | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * i40evf_virtchnl_completion | ||||
|  * @adapter: adapter structure | ||||
|  * @v_opcode: opcode sent by PF | ||||
|  * @v_retval: retval sent by PF | ||||
|  * @msg: message sent by PF | ||||
|  * @msglen: message length | ||||
|  * | ||||
|  * Asynchronous completion function for admin queue messages. Rather than busy | ||||
|  * wait, we fire off our requests and assume that no errors will be returned. | ||||
|  * This function handles the reply messages. | ||||
|  **/ | ||||
| void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, | ||||
| 				enum i40e_virtchnl_ops v_opcode, | ||||
| 				i40e_status v_retval, | ||||
| 				u8 *msg, u16 msglen) | ||||
| { | ||||
| 	struct net_device *netdev = adapter->netdev; | ||||
| 
 | ||||
| 	if (v_opcode == I40E_VIRTCHNL_OP_EVENT) { | ||||
| 		struct i40e_virtchnl_pf_event *vpe = | ||||
| 			(struct i40e_virtchnl_pf_event *)msg; | ||||
| 		switch (vpe->event) { | ||||
| 		case I40E_VIRTCHNL_EVENT_LINK_CHANGE: | ||||
| 			adapter->link_up = | ||||
| 				vpe->event_data.link_event.link_status; | ||||
| 			if (adapter->link_up && !netif_carrier_ok(netdev)) { | ||||
| 				dev_info(&adapter->pdev->dev, "NIC Link is Up\n"); | ||||
| 				netif_carrier_on(netdev); | ||||
| 				netif_tx_wake_all_queues(netdev); | ||||
| 			} else if (!adapter->link_up) { | ||||
| 				dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); | ||||
| 				netif_carrier_off(netdev); | ||||
| 				netif_tx_stop_all_queues(netdev); | ||||
| 			} | ||||
| 			break; | ||||
| 		case I40E_VIRTCHNL_EVENT_RESET_IMPENDING: | ||||
| 			dev_info(&adapter->pdev->dev, "PF reset warning received\n"); | ||||
| 			if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) { | ||||
| 				adapter->flags |= I40EVF_FLAG_RESET_PENDING; | ||||
| 				dev_info(&adapter->pdev->dev, "Scheduling reset task\n"); | ||||
| 				schedule_work(&adapter->reset_task); | ||||
| 			} | ||||
| 			break; | ||||
| 		default: | ||||
| 			dev_err(&adapter->pdev->dev, | ||||
| 				"%s: Unknown event %d from pf\n", | ||||
| 				__func__, vpe->event); | ||||
| 			break; | ||||
| 
 | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 	if (v_opcode != adapter->current_op) { | ||||
| 		dev_err(&adapter->pdev->dev, "%s: Pending op is %d, received %d\n", | ||||
| 			__func__, adapter->current_op, v_opcode); | ||||
| 		/* We're probably completely screwed at this point, but clear
 | ||||
| 		 * the current op and try to carry on.... | ||||
| 		 */ | ||||
| 		adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; | ||||
| 		return; | ||||
| 	} | ||||
| 	if (v_retval) { | ||||
| 		dev_err(&adapter->pdev->dev, "%s: PF returned error %d to our request %d\n", | ||||
| 			__func__, v_retval, v_opcode); | ||||
| 	} | ||||
| 	switch (v_opcode) { | ||||
| 	case I40E_VIRTCHNL_OP_GET_STATS: { | ||||
| 		struct i40e_eth_stats *stats = | ||||
| 			(struct i40e_eth_stats *)msg; | ||||
| 		adapter->net_stats.rx_packets = stats->rx_unicast + | ||||
| 						 stats->rx_multicast + | ||||
| 						 stats->rx_broadcast; | ||||
| 		adapter->net_stats.tx_packets = stats->tx_unicast + | ||||
| 						 stats->tx_multicast + | ||||
| 						 stats->tx_broadcast; | ||||
| 		adapter->net_stats.rx_bytes = stats->rx_bytes; | ||||
| 		adapter->net_stats.tx_bytes = stats->tx_bytes; | ||||
| 		adapter->net_stats.tx_errors = stats->tx_errors; | ||||
| 		adapter->net_stats.rx_dropped = stats->rx_discards; | ||||
| 		adapter->net_stats.tx_dropped = stats->tx_discards; | ||||
| 		adapter->current_stats = *stats; | ||||
| 		} | ||||
| 		break; | ||||
| 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: | ||||
| 		adapter->aq_pending &= ~(I40EVF_FLAG_AQ_ADD_MAC_FILTER); | ||||
| 		break; | ||||
| 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: | ||||
| 		adapter->aq_pending &= ~(I40EVF_FLAG_AQ_DEL_MAC_FILTER); | ||||
| 		break; | ||||
| 	case I40E_VIRTCHNL_OP_ADD_VLAN: | ||||
| 		adapter->aq_pending &= ~(I40EVF_FLAG_AQ_ADD_VLAN_FILTER); | ||||
| 		break; | ||||
| 	case I40E_VIRTCHNL_OP_DEL_VLAN: | ||||
| 		adapter->aq_pending &= ~(I40EVF_FLAG_AQ_DEL_VLAN_FILTER); | ||||
| 		break; | ||||
| 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES: | ||||
| 		adapter->aq_pending &= ~(I40EVF_FLAG_AQ_ENABLE_QUEUES); | ||||
| 		/* enable transmits */ | ||||
| 		i40evf_irq_enable(adapter, true); | ||||
| 		netif_tx_start_all_queues(adapter->netdev); | ||||
| 		netif_carrier_on(adapter->netdev); | ||||
| 		break; | ||||
| 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES: | ||||
| 		adapter->aq_pending &= ~(I40EVF_FLAG_AQ_DISABLE_QUEUES); | ||||
| 		break; | ||||
| 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: | ||||
| 		adapter->aq_pending &= ~(I40EVF_FLAG_AQ_CONFIGURE_QUEUES); | ||||
| 		break; | ||||
| 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: | ||||
| 		adapter->aq_pending &= ~(I40EVF_FLAG_AQ_MAP_VECTORS); | ||||
| 		break; | ||||
| 	default: | ||||
| 		dev_warn(&adapter->pdev->dev, "%s: Received unexpected message %d from PF\n", | ||||
| 			__func__, v_opcode); | ||||
| 		break; | ||||
| 	} /* switch v_opcode */ | ||||
| 	adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 awab228
						awab228