255 lines
		
	
	
	
		
			7.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			255 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); | ||
|  | } |