diff options
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_common.c')
| -rw-r--r-- | drivers/net/ixgbe/ixgbe_common.c | 244 | 
1 files changed, 242 insertions, 2 deletions
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index b894b42a741..777051f54e5 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1292,7 +1292,7 @@ static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw)  		udelay(5);  		ixgbe_standby_eeprom(hw); -	}; +	}  	/*  	 * On some parts, SPI write time could vary from 0-20mSec on 3.3V @@ -1374,7 +1374,7 @@ static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data,  		 * EEPROM  		 */  		mask = mask >> 1; -	}; +	}  	/* We leave the "DI" bit set to "0" when we leave this routine. */  	eec &= ~IXGBE_EEC_DI; @@ -3267,3 +3267,243 @@ s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps)  	return 0;  } + +/** + * ixgbe_set_rxpba_generic - Initialize RX packet buffer + * @hw: pointer to hardware structure + * @num_pb: number of packet buffers to allocate + * @headroom: reserve n KB of headroom + * @strategy: packet buffer allocation strategy + **/ +void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, +			     int num_pb, +			     u32 headroom, +			     int strategy) +{ +	u32 pbsize = hw->mac.rx_pb_size; +	int i = 0; +	u32 rxpktsize, txpktsize, txpbthresh; + +	/* Reserve headroom */ +	pbsize -= headroom; + +	if (!num_pb) +		num_pb = 1; + +	/* Divide remaining packet buffer space amongst the number +	 * of packet buffers requested using supplied strategy. +	 */ +	switch (strategy) { +	case (PBA_STRATEGY_WEIGHTED): +		/* pba_80_48 strategy weight first half of packet buffer with +		 * 5/8 of the packet buffer space. +		 */ +		rxpktsize = ((pbsize * 5 * 2) / (num_pb * 8)); +		pbsize -= rxpktsize * (num_pb / 2); +		rxpktsize <<= IXGBE_RXPBSIZE_SHIFT; +		for (; i < (num_pb / 2); i++) +			IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); +		/* Fall through to configure remaining packet buffers */ +	case (PBA_STRATEGY_EQUAL): +		/* Divide the remaining Rx packet buffer evenly among the TCs */ +		rxpktsize = (pbsize / (num_pb - i)) << IXGBE_RXPBSIZE_SHIFT; +		for (; i < num_pb; i++) +			IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); +		break; +	default: +		break; +	} + +	/* +	 * Setup Tx packet buffer and threshold equally for all TCs +	 * TXPBTHRESH register is set in K so divide by 1024 and subtract +	 * 10 since the largest packet we support is just over 9K. +	 */ +	txpktsize = IXGBE_TXPBSIZE_MAX / num_pb; +	txpbthresh = (txpktsize / 1024) - IXGBE_TXPKT_SIZE_MAX; +	for (i = 0; i < num_pb; i++) { +		IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), txpktsize); +		IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), txpbthresh); +	} + +	/* Clear unused TCs, if any, to zero buffer size*/ +	for (; i < IXGBE_MAX_PB; i++) { +		IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); +		IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), 0); +		IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), 0); +	} +} + +/** + *  ixgbe_calculate_checksum - Calculate checksum for buffer + *  @buffer: pointer to EEPROM + *  @length: size of EEPROM to calculate a checksum for + *  Calculates the checksum for some buffer on a specified length.  The + *  checksum calculated is returned. + **/ +static u8 ixgbe_calculate_checksum(u8 *buffer, u32 length) +{ +	u32 i; +	u8 sum = 0; + +	if (!buffer) +		return 0; + +	for (i = 0; i < length; i++) +		sum += buffer[i]; + +	return (u8) (0 - sum); +} + +/** + *  ixgbe_host_interface_command - Issue command to manageability block + *  @hw: pointer to the HW structure + *  @buffer: contains the command to write and where the return status will + *           be placed + *  @lenght: lenght of buffer, must be multiple of 4 bytes + * + *  Communicates with the manageability block.  On success return 0 + *  else return IXGBE_ERR_HOST_INTERFACE_COMMAND. + **/ +static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u8 *buffer, +					u32 length) +{ +	u32 hicr, i; +	u32 hdr_size = sizeof(struct ixgbe_hic_hdr); +	u8 buf_len, dword_len; + +	s32 ret_val = 0; + +	if (length == 0 || length & 0x3 || +	    length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) { +		hw_dbg(hw, "Buffer length failure.\n"); +		ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; +		goto out; +	} + +	/* Check that the host interface is enabled. */ +	hicr = IXGBE_READ_REG(hw, IXGBE_HICR); +	if ((hicr & IXGBE_HICR_EN) == 0) { +		hw_dbg(hw, "IXGBE_HOST_EN bit disabled.\n"); +		ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; +		goto out; +	} + +	/* Calculate length in DWORDs */ +	dword_len = length >> 2; + +	/* +	 * The device driver writes the relevant command block +	 * into the ram area. +	 */ +	for (i = 0; i < dword_len; i++) +		IXGBE_WRITE_REG_ARRAY(hw, IXGBE_FLEX_MNG, +				      i, *((u32 *)buffer + i)); + +	/* Setting this bit tells the ARC that a new command is pending. */ +	IXGBE_WRITE_REG(hw, IXGBE_HICR, hicr | IXGBE_HICR_C); + +	for (i = 0; i < IXGBE_HI_COMMAND_TIMEOUT; i++) { +		hicr = IXGBE_READ_REG(hw, IXGBE_HICR); +		if (!(hicr & IXGBE_HICR_C)) +			break; +		usleep_range(1000, 2000); +	} + +	/* Check command successful completion. */ +	if (i == IXGBE_HI_COMMAND_TIMEOUT || +	    (!(IXGBE_READ_REG(hw, IXGBE_HICR) & IXGBE_HICR_SV))) { +		hw_dbg(hw, "Command has failed with no status valid.\n"); +		ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; +		goto out; +	} + +	/* Calculate length in DWORDs */ +	dword_len = hdr_size >> 2; + +	/* first pull in the header so we know the buffer length */ +	for (i = 0; i < dword_len; i++) +		*((u32 *)buffer + i) = +			IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, i); + +	/* If there is any thing in data position pull it in */ +	buf_len = ((struct ixgbe_hic_hdr *)buffer)->buf_len; +	if (buf_len == 0) +		goto out; + +	if (length < (buf_len + hdr_size)) { +		hw_dbg(hw, "Buffer not large enough for reply message.\n"); +		ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; +		goto out; +	} + +	/* Calculate length in DWORDs, add one for odd lengths */ +	dword_len = (buf_len + 1) >> 2; + +	/* Pull in the rest of the buffer (i is where we left off)*/ +	for (; i < buf_len; i++) +		*((u32 *)buffer + i) = +			IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, i); + +out: +	return ret_val; +} + +/** + *  ixgbe_set_fw_drv_ver_generic - Sends driver version to firmware + *  @hw: pointer to the HW structure + *  @maj: driver version major number + *  @min: driver version minor number + *  @build: driver version build number + *  @sub: driver version sub build number + * + *  Sends driver version number to firmware through the manageability + *  block.  On success return 0 + *  else returns IXGBE_ERR_SWFW_SYNC when encountering an error acquiring + *  semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. + **/ +s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, +				 u8 build, u8 sub) +{ +	struct ixgbe_hic_drv_info fw_cmd; +	int i; +	s32 ret_val = 0; + +	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM) != 0) { +		ret_val = IXGBE_ERR_SWFW_SYNC; +		goto out; +	} + +	fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO; +	fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN; +	fw_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; +	fw_cmd.port_num = (u8)hw->bus.func; +	fw_cmd.ver_maj = maj; +	fw_cmd.ver_min = min; +	fw_cmd.ver_build = build; +	fw_cmd.ver_sub = sub; +	fw_cmd.hdr.checksum = 0; +	fw_cmd.hdr.checksum = ixgbe_calculate_checksum((u8 *)&fw_cmd, +				(FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len)); +	fw_cmd.pad = 0; +	fw_cmd.pad2 = 0; + +	for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { +		ret_val = ixgbe_host_interface_command(hw, (u8 *)&fw_cmd, +						       sizeof(fw_cmd)); +		if (ret_val != 0) +			continue; + +		if (fw_cmd.hdr.cmd_or_resp.ret_status == +		    FW_CEM_RESP_STATUS_SUCCESS) +			ret_val = 0; +		else +			ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; + +		break; +	} + +	hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM); +out: +	return ret_val; +}  |