// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 1999 - 2018 Intel Corporation. */
#include "vf.h"
#include "ixgbevf.h"
/* On Hyper-V, to reset, we need to read from this offset
* from the PCI config space. This is the mechanism used on
* Hyper-V to support PF/VF communication.
*/
#define IXGBE_HV_RESET_OFFSET 0x201
static inline s32 ixgbevf_write_msg_read_ack(struct ixgbe_hw *hw, u32 *msg,
u32 *retmsg, u16 size)
{
struct ixgbe_mbx_info *mbx = &hw->mbx;
s32 retval = mbx->ops.write_posted(hw, msg, size);
if (retval)
return retval;
return mbx->ops.read_posted(hw, retmsg, size);
}
/**
* ixgbevf_start_hw_vf - Prepare hardware for Tx/Rx
* @hw: pointer to hardware structure
*
* Starts the hardware by filling the bus info structure and media type, clears
* all on chip counters, initializes receive address registers, multicast
* table, VLAN filter table, calls routine to set up link and flow control
* settings, and leaves transmit and receive units disabled and uninitialized
**/
static s32 ixgbevf_start_hw_vf(struct ixgbe_hw *hw)
{
/* Clear adapter stopped flag */
hw->adapter_stopped = false;
return 0;
}
/**
* ixgbevf_init_hw_vf - virtual function hardware initialization
* @hw: pointer to hardware structure
*
* Initialize the hardware by resetting the hardware and then starting
* the hardware
**/
static s32 ixgbevf_init_hw_vf(struct ixgbe_hw *hw)
{
s32 status = hw->mac.ops.start_hw(hw);
hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
return status;
}
/**
* ixgbevf_reset_hw_vf - Performs hardware reset
* @hw: pointer to hardware structure
*
* Resets the hardware by resetting the transmit and receive units, masks and
* clears all interrupts.
**/
static s32 ixgbevf_reset_hw_vf(struct ixgbe_hw *hw)
{
struct ixgbe_mbx_info *mbx = &hw->mbx;
u32 timeout = IXGBE_VF_INIT_TIMEOUT;
s32 ret_val = IXGBE_ERR_INVALID_MAC_ADDR;
u32 msgbuf[IXGBE_VF_PERMADDR_MSG_LEN];
u8 *addr = (u8 *)(&msgbuf[1]);
/* Call adapter stop to disable tx/rx and clear interrupts */
hw->mac.ops.stop_adapter(hw);
/* reset the api version */
hw->api_version = ixgbe_mbox_api_10;
IXGBE_WRITE_REG(hw, IXGBE_VFCTRL, IXGBE_CTRL_RST);
IXGBE_WRITE_FLUSH(hw);
/* we cannot reset while the RSTI / RSTD bits are asserted */
while (!mbx->ops.check_for_rst(hw) && timeout) {
timeout--;
udelay(5);
}
if (!timeout)
return IXGBE_ERR_RESET_FAILED;
/* mailbox timeout can now become active */
mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT;
msgbuf[0] = IXGBE_VF_RESET;
mbx->ops.write_posted(hw, msgbuf, 1);
mdelay(10);
/* set our "perm_addr" based on info provided by PF
* also set up the mc_filter_type which is piggy backed
* on the mac address in word 3
*/
ret_val = mbx->ops.read_posted(hw, msgbuf, IXGBE_VF_PERMADDR_MSG_LEN);
if (ret_val)
return ret_val;
/* New versions of the PF may NACK the reset return message
* to indicate that no MAC address has yet been assigned for
* the VF.
*/
if (msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK) &&
msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_NACK))
return IXGBE_ERR_INVALID_MAC_ADDR;
if (msgbuf[0] == (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK))
ether_addr_copy(hw->mac.perm_addr, addr);
hw->mac.mc_filter_type = msgbuf[IXGBE_VF_MC_TYPE_WORD];
return 0;
}
/**
* Hyper-V variant; the VF/PF communication is through the PCI
* config space.
* @hw: pointer to private hardware struct
*/
static s32 ixgbevf_hv_reset_hw_vf(struct ixgbe_hw *hw)
{
#if IS_ENABLED(CONFIG_PCI_MMCONFIG)
struct ixgbevf_adapter *adapter = hw->back;
int i;
for (i = 0; i < 6; i++)
pci_read_config_byte(adapter->pdev,
(i + IXGBE_HV_RESET_OFFSET),
&hw->mac.perm_addr[i]);
return 0;
#else
pr_err("PCI_MMCONFIG needs to be enabled for Hyper-V\n");
return -EOPNOTSUPP;
#endif
}
/**
* ixgbevf_stop_hw_vf - Generic stop Tx/Rx units
* @hw: pointer to hardware structure
*
* Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts,
* disables transmit and receive units. The adapter_stopped flag is used by
* the shared code and drivers to determine if the adapter is in a stopped
* state and should not touch the hardware.
**/
static s32 ixgbevf_stop_hw_vf(struct ixgbe_hw *hw)
{
u32 number_of_queues;
u32 reg_val;
u16 i;
/* Set the adapter_stopped flag so other driver functions stop touching
* the hardware
*/
hw->adapter_stopped = true;
/* Disable the receive unit by stopped each queue */
number_of_queues = hw->mac.max_rx_queues;
for (i = 0; i < number_of_queues; i++) {
reg_val