 d358aa9a7a
			
		
	
	
	d358aa9a7a
	
	
	
		
			
			This patch implements the hardware specific init and management. Signed-off-by: Mitch Williams <mitch.a.williams@intel.com> Signed-off-by: Greg Rose <gregory.v.rose@intel.com> Tested-by: Sibai Li <sibai.li@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
		
			
				
	
	
		
			254 lines
		
	
	
	
		
			7.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
	
		
			7.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*******************************************************************************
 | |
|  *
 | |
|  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
 | |
|  * Copyright(c) 2013 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.
 | |
|  *
 | |
|  * 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_SFP_XL710_DEVICE_ID:
 | |
| 		case I40E_SFP_X710_DEVICE_ID:
 | |
| 		case I40E_QEMU_DEVICE_ID:
 | |
| 		case I40E_KX_A_DEVICE_ID:
 | |
| 		case I40E_KX_B_DEVICE_ID:
 | |
| 		case I40E_KX_C_DEVICE_ID:
 | |
| 		case I40E_KX_D_DEVICE_ID:
 | |
| 		case I40E_QSFP_A_DEVICE_ID:
 | |
| 		case I40E_QSFP_B_DEVICE_ID:
 | |
| 		case I40E_QSFP_C_DEVICE_ID:
 | |
| 			hw->mac.type = I40E_MAC_XL710;
 | |
| 			break;
 | |
| 		case I40E_VF_DEVICE_ID:
 | |
| 		case I40E_VF_HV_DEVICE_ID:
 | |
| 			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
 | |
|  *
 | |
|  * 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)
 | |
| {
 | |
| 	struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
 | |
| 	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");
 | |
| 		for (i = 0; i < le16_to_cpu(aq_desc->datalen); 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)
 | |
| {
 | |
| 	return !!(rd32(hw, hw->aq.asq.len) & I40E_PF_ATQLEN_ATQENABLE_MASK);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * 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;
 | |
| 	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) {
 | |
| 		struct i40e_asq_cmd_details details;
 | |
| 		memset(&details, 0, sizeof(details));
 | |
| 		details.async = true;
 | |
| 		cmd_details = &details;
 | |
| 	}
 | |
| 	status = i40evf_asq_send_command(hw, (struct i40e_aq_desc *)&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);
 | |
| }
 |