596 lines
16 KiB
C
596 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright(c) 2022 - 2024 Mucse Corporation. */
|
|
|
|
#include "rnpgbevf_mbx.h"
|
|
#include "rnpgbevf.h"
|
|
|
|
static s32 rnpgbevf_poll_for_msg(struct rnpgbevf_hw *hw, bool to_cm3);
|
|
static s32 rnpgbevf_poll_for_ack(struct rnpgbevf_hw *hw, bool to_cm3);
|
|
/**
|
|
* rnpgbevf_read_posted_mbx - Wait for message notification and receive message
|
|
* @hw: pointer to the HW structure
|
|
* @msg: The message buffer
|
|
* @size: Length of buffer
|
|
* @to_cm3: to cm3 or not
|
|
*
|
|
* returns 0 if it successfully received a message notification and
|
|
* copied it into the receive buffer.
|
|
**/
|
|
static s32 rnpgbevf_read_posted_mbx(struct rnpgbevf_hw *hw, u32 *msg, u16 size,
|
|
bool to_cm3)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
s32 ret_val = -RNPGBE_ERR_MBX;
|
|
|
|
if (!mbx->ops.read)
|
|
goto out;
|
|
|
|
ret_val = rnpgbevf_poll_for_msg(hw, to_cm3);
|
|
|
|
/* if ack received read message, otherwise we timed out */
|
|
if (!ret_val)
|
|
ret_val = mbx->ops.read(hw, msg, size, to_cm3);
|
|
|
|
out:
|
|
return ret_val;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_write_posted_mbx - Write a message to the mailbox, wait for ack
|
|
* @hw: pointer to the HW structure
|
|
* @msg: The message buffer
|
|
* @size: Length of buffer
|
|
* @to_cm3: to cm3 or not
|
|
*
|
|
* returns 0 if it successfully copied message into the buffer and
|
|
* received an ack to that message within delay * timeout period
|
|
**/
|
|
static s32 rnpgbevf_write_posted_mbx(struct rnpgbevf_hw *hw, u32 *msg, u16 size,
|
|
bool to_cm3)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
s32 ret_val = -RNPGBE_ERR_MBX;
|
|
|
|
/* exit if either we can't write or there isn't a defined timeout */
|
|
if (!mbx->ops.write || !mbx->timeout)
|
|
goto out;
|
|
|
|
/* send msg */
|
|
ret_val = mbx->ops.write(hw, msg, size, to_cm3);
|
|
|
|
/* if msg sent wait until we receive an ack */
|
|
if (!ret_val)
|
|
ret_val = rnpgbevf_poll_for_ack(hw, to_cm3);
|
|
out:
|
|
return ret_val;
|
|
}
|
|
|
|
static inline u16 rnpgbevf_mbx_get_req(struct rnpgbevf_hw *hw, int reg)
|
|
{
|
|
/* memory barrier */
|
|
mb();
|
|
return mbx_rd32(hw, reg) & 0xffff;
|
|
}
|
|
|
|
static inline u16 rnpgbevf_mbx_get_ack(struct rnpgbevf_hw *hw, int reg)
|
|
{
|
|
/* memory barrier */
|
|
mb();
|
|
return (mbx_rd32(hw, reg) >> 16) & 0xffff;
|
|
}
|
|
|
|
static inline void rnpgbevf_mbx_inc_vfreq(struct rnpgbevf_hw *hw, bool to_cm3)
|
|
{
|
|
u16 req;
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u8 vfnum = VFNUM(mbx, hw->vfnum);
|
|
int reg =
|
|
to_cm3 ? VF2CPU_COUNTER(mbx, vfnum) : VF2PF_COUNTER(mbx, vfnum);
|
|
u32 v = mbx_rd32(hw, reg);
|
|
|
|
req = (v & 0xffff);
|
|
req++;
|
|
v &= ~(0x0000ffff);
|
|
v |= req;
|
|
/* memory barrier */
|
|
mb();
|
|
mbx_wr32(hw, reg, v);
|
|
|
|
/* update stats */
|
|
hw->mbx.stats.msgs_tx++;
|
|
}
|
|
|
|
static inline void rnpgbevf_mbx_inc_vfack(struct rnpgbevf_hw *hw, bool to_cm3)
|
|
{
|
|
u16 ack;
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u8 vfnum = VFNUM(mbx, hw->vfnum);
|
|
int reg =
|
|
to_cm3 ? VF2CPU_COUNTER(mbx, vfnum) : VF2PF_COUNTER(mbx, vfnum);
|
|
u32 v = mbx_rd32(hw, reg);
|
|
|
|
ack = (v >> 16) & 0xffff;
|
|
ack++;
|
|
v &= ~(0xffff0000);
|
|
v |= (ack << 16);
|
|
/* memory barrier */
|
|
mb();
|
|
mbx_wr32(hw, reg, v);
|
|
|
|
/* update stats */
|
|
hw->mbx.stats.msgs_rx++;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_check_for_msg_vf - checks to see if the PF has sent mail
|
|
* @hw: pointer to the HW structure
|
|
* @to_cm3: to cm3 or not
|
|
*
|
|
* returns 0 if the PF has set the Status bit or else ERR_MBX
|
|
**/
|
|
static s32 rnpgbevf_check_for_msg_vf(struct rnpgbevf_hw *hw, bool to_cm3)
|
|
{
|
|
s32 ret_val = RNPGBE_ERR_MBX;
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u8 vfnum = VFNUM(mbx, hw->vfnum);
|
|
|
|
if (to_cm3) {
|
|
if (rnpgbevf_mbx_get_req(hw, CPU2VF_COUNTER(mbx, vfnum)) !=
|
|
hw->mbx.cpu_req) {
|
|
ret_val = 0;
|
|
hw->mbx.stats.reqs++;
|
|
}
|
|
} else {
|
|
if (rnpgbevf_mbx_get_req(hw, PF2VF_COUNTER(mbx, vfnum)) !=
|
|
hw->mbx.pf_req) {
|
|
ret_val = 0;
|
|
hw->mbx.stats.reqs++;
|
|
}
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_poll_for_msg - Wait for message notification
|
|
* @hw: pointer to the HW structure
|
|
* @to_cm3: to cm3 or not
|
|
*
|
|
* returns 0 if it successfully received a message notification
|
|
**/
|
|
static s32 rnpgbevf_poll_for_msg(struct rnpgbevf_hw *hw, bool to_cm3)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
int countdown = mbx->timeout;
|
|
|
|
while (countdown && mbx->ops.check_for_msg(hw, to_cm3)) {
|
|
countdown--;
|
|
udelay(mbx->udelay);
|
|
}
|
|
|
|
return countdown ? 0 : RNPGBE_ERR_MBX;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_poll_for_ack - Wait for message acknowledgment
|
|
* @hw: pointer to the HW structure
|
|
* @to_cm3: to cm3 or not
|
|
*
|
|
* returns 0 if it successfully received a message acknowledgment
|
|
**/
|
|
static s32 rnpgbevf_poll_for_ack(struct rnpgbevf_hw *hw, bool to_cm3)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
int countdown = mbx->timeout;
|
|
|
|
while (countdown && mbx->ops.check_for_ack(hw, to_cm3)) {
|
|
countdown--;
|
|
udelay(mbx->udelay);
|
|
}
|
|
|
|
/* if we failed, all future posted messages fail until reset */
|
|
if (!countdown) {
|
|
mbx->timeout = 0;
|
|
dbg("%s timeout\n", __func__);
|
|
}
|
|
|
|
return countdown ? 0 : RNPGBE_ERR_MBX;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_check_for_rst_msg_vf - checks to see if the PF has ACK'd
|
|
* @hw: pointer to the HW structure
|
|
* @to_cm3: to cm3 or not
|
|
*
|
|
* returns 0 if the PF has set the ACK bit or else ERR_MBX
|
|
**/
|
|
static s32 rnpgbevf_check_for_rst_msg_vf(struct rnpgbevf_hw *hw, bool to_cm3)
|
|
{
|
|
struct rnpgbevf_adapter *adapter = hw->back;
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
s32 ret_val = RNPGBE_ERR_MBX;
|
|
u8 vfnum = VFNUM(mbx, hw->vfnum);
|
|
u32 DATA_REG = (to_cm3) ? CPU_VF_SHM_DATA(mbx, vfnum) :
|
|
PF_VF_SHM_DATA(mbx, vfnum);
|
|
u32 data;
|
|
int ret = 1;
|
|
|
|
ret_val = rnpgbevf_check_for_msg_vf(hw, to_cm3);
|
|
if (!ret_val) {
|
|
mbx->ops.read(hw, &data, 1, 0);
|
|
data &= ~RNPGBE_PF_VFNUM_MASK;
|
|
/* add other mailbox setup */
|
|
if (((data) & (~RNPGBE_VT_MSGTYPE_CTS)) ==
|
|
RNPGBE_PF_CONTROL_PRING_MSG) {
|
|
} else if ((data) == RNPGBE_PF_SET_FCS) {
|
|
// to-do
|
|
data = mbx_rd32(hw, DATA_REG + 4);
|
|
if (data) {
|
|
adapter->priv_flags |= RNPVF_PRIV_FLAG_FCS_ON;
|
|
adapter->netdev->features |= NETIF_F_RXFCS;
|
|
} else {
|
|
adapter->priv_flags &=
|
|
(~RNPVF_PRIV_FLAG_FCS_ON);
|
|
adapter->netdev->features &= (~NETIF_F_RXFCS);
|
|
}
|
|
|
|
if ((adapter->priv_flags & RNPVF_PRIV_FLAG_FCS_ON) &&
|
|
(adapter->netdev->features & NETIF_F_RXCSUM)) {
|
|
adapter->netdev->features &= (~NETIF_F_RXCSUM);
|
|
} else {
|
|
/* set back rx-chksum status */
|
|
if (adapter->flags &
|
|
RNPVF_FLAG_RX_CHKSUM_ENABLED)
|
|
adapter->netdev->features |=
|
|
NETIF_F_RXCSUM;
|
|
else
|
|
adapter->netdev->features &=
|
|
(~NETIF_F_RXCSUM);
|
|
}
|
|
} else if ((data) == RNPGBE_PF_SET_PAUSE) {
|
|
hw->fc.current_mode = mbx_rd32(hw, DATA_REG + 4);
|
|
} else if ((data) == RNPGBE_PF_SET_FT_PADDING) {
|
|
data = mbx_rd32(hw, DATA_REG + 4);
|
|
if (data) {
|
|
adapter->priv_flags |=
|
|
RNPVF_PRIV_FLAG_FT_PADDING;
|
|
} else {
|
|
adapter->priv_flags &=
|
|
(~RNPVF_PRIV_FLAG_FT_PADDING);
|
|
}
|
|
} else if ((data) == RNPGBE_PF_SET_VLAN_FILTER) {
|
|
data = mbx_rd32(hw, DATA_REG + 4);
|
|
if (data) {
|
|
if (hw->feature_flags &
|
|
RNPVF_NET_FEATURE_VLAN_OFFLOAD) {
|
|
adapter->netdev->features |=
|
|
NETIF_F_HW_VLAN_CTAG_FILTER;
|
|
}
|
|
if (hw->feature_flags &
|
|
RNPVF_NET_FEATURE_STAG_OFFLOAD) {
|
|
adapter->netdev->features |=
|
|
NETIF_F_HW_VLAN_STAG_FILTER;
|
|
}
|
|
|
|
} else {
|
|
if (hw->feature_flags &
|
|
RNPVF_NET_FEATURE_VLAN_OFFLOAD) {
|
|
adapter->netdev->features &=
|
|
~NETIF_F_HW_VLAN_CTAG_FILTER;
|
|
}
|
|
if (hw->feature_flags &
|
|
RNPVF_NET_FEATURE_STAG_OFFLOAD) {
|
|
adapter->netdev->features &=
|
|
~NETIF_F_HW_VLAN_STAG_FILTER;
|
|
}
|
|
}
|
|
} else if ((data) == RNPGBE_PF_SET_VLAN) {
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
|
|
data = mbx_rd32(hw, DATA_REG + 4);
|
|
adapter->flags |= RNPVF_FLAG_PF_UPDATE_VLAN;
|
|
if (data) {
|
|
adapter->flags |= RNPVF_FLAG_PF_SET_VLAN;
|
|
adapter->vf_vlan = data;
|
|
if (adapter->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
|
|
adapter->priv_flags |= RNPVF_FLAG_RX_CVLAN_OFFLOAD;
|
|
else
|
|
adapter->priv_flags &= ~RNPVF_FLAG_RX_CVLAN_OFFLOAD;
|
|
|
|
adapter->netdev->features |= NETIF_F_HW_VLAN_CTAG_RX;
|
|
if (adapter->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)
|
|
adapter->priv_flags |= RNPVF_FLAG_TX_CVLAN_OFFLOAD;
|
|
else
|
|
adapter->priv_flags &= ~RNPVF_FLAG_TX_CVLAN_OFFLOAD;
|
|
adapter->netdev->features &=
|
|
~NETIF_F_HW_VLAN_CTAG_TX;
|
|
if (adapter->netdev->features & NETIF_F_HW_VLAN_STAG_RX)
|
|
adapter->priv_flags |= RNPVF_FLAG_RX_SVLAN_OFFLOAD;
|
|
else
|
|
adapter->priv_flags &= ~RNPVF_FLAG_RX_SVLAN_OFFLOAD;
|
|
|
|
adapter->netdev->features |= NETIF_F_HW_VLAN_STAG_RX;
|
|
if (adapter->netdev->features & NETIF_F_HW_VLAN_STAG_TX)
|
|
adapter->priv_flags |= RNPVF_FLAG_TX_SVLAN_OFFLOAD;
|
|
else
|
|
adapter->priv_flags &= ~RNPVF_FLAG_TX_SVLAN_OFFLOAD;
|
|
|
|
adapter->netdev->features &= ~NETIF_F_HW_VLAN_STAG_TX;
|
|
} else {
|
|
adapter->flags &= (~RNPVF_FLAG_PF_SET_VLAN);
|
|
adapter->vf_vlan = 0;
|
|
if (adapter->priv_flags & RNPVF_FLAG_RX_CVLAN_OFFLOAD)
|
|
adapter->netdev->features |= NETIF_F_HW_VLAN_CTAG_RX;
|
|
else
|
|
adapter->netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
|
|
if (adapter->priv_flags & RNPVF_FLAG_TX_CVLAN_OFFLOAD)
|
|
adapter->netdev->features |= NETIF_F_HW_VLAN_CTAG_TX;
|
|
else
|
|
adapter->netdev->features &= ~NETIF_F_HW_VLAN_CTAG_TX;
|
|
if (adapter->priv_flags & RNPVF_FLAG_RX_SVLAN_OFFLOAD)
|
|
adapter->netdev->features |= NETIF_F_HW_VLAN_STAG_RX;
|
|
else
|
|
adapter->netdev->features &= ~NETIF_F_HW_VLAN_STAG_RX;
|
|
if (adapter->priv_flags & RNPVF_FLAG_TX_SVLAN_OFFLOAD)
|
|
adapter->netdev->features |= NETIF_F_HW_VLAN_STAG_TX;
|
|
else
|
|
adapter->netdev->features &= ~NETIF_F_HW_VLAN_STAG_TX;
|
|
}
|
|
hw->ops.set_veb_vlan(hw, data, VFNUM(mbx, hw->vfnum));
|
|
} else if ((data) == RNPGBE_PF_SET_LINK) {
|
|
data = mbx_rd32(hw, DATA_REG + 4);
|
|
if (data & RNPGBE_PF_LINK_UP) {
|
|
hw->link = true;
|
|
hw->speed = data & 0xffff;
|
|
} else {
|
|
hw->link = false;
|
|
hw->speed = 0;
|
|
}
|
|
} else if ((data) == RNPGBE_PF_SET_MTU) {
|
|
data = mbx_rd32(hw, DATA_REG + 4);
|
|
hw->mtu = data;
|
|
adapter->flags |= RNPVF_FLAG_PF_UPDATE_MTU;
|
|
} else if ((data) == RNPGBE_PF_SET_RESET) {
|
|
adapter->flags |= RNPVF_FLAG_PF_RESET;
|
|
} else {
|
|
return RNPGBE_ERR_MBX;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_check_for_ack_vf - checks to see if the PF has ACK'd
|
|
* @hw: pointer to the HW structure
|
|
* @to_cm3: to cm3 or not
|
|
*
|
|
* returns 0 if the PF has set the ACK bit or else ERR_MBX
|
|
**/
|
|
static s32 rnpgbevf_check_for_ack_vf(struct rnpgbevf_hw *hw, bool to_cm3)
|
|
{
|
|
s32 ret_val = RNPGBE_ERR_MBX;
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u8 vfnum = VFNUM(mbx, hw->vfnum);
|
|
|
|
if (to_cm3) {
|
|
if (rnpgbevf_mbx_get_ack(hw, CPU2VF_COUNTER(mbx, vfnum)) !=
|
|
hw->mbx.cpu_ack) {
|
|
ret_val = 0;
|
|
hw->mbx.stats.acks++;
|
|
}
|
|
} else {
|
|
if (rnpgbevf_mbx_get_ack(hw, PF2VF_COUNTER(mbx, vfnum)) !=
|
|
hw->mbx.pf_ack) {
|
|
ret_val = 0;
|
|
hw->mbx.stats.acks++;
|
|
}
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_obtain_mbx_lock_vf - obtain mailbox lock
|
|
* @hw: pointer to the HW structure
|
|
* @to_cm3: to cm3 or not
|
|
*
|
|
* return 0 if we obtained the mailbox lock
|
|
**/
|
|
static s32 rnpgbevf_obtain_mbx_lock_vf(struct rnpgbevf_hw *hw, bool to_cm3)
|
|
{
|
|
int try_cnt = 2 * 1000; // 1s
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u8 vfnum = VFNUM(mbx, hw->vfnum);
|
|
u32 CTRL_REG = (to_cm3) ? VF2CPU_MBOX_CTRL(mbx, vfnum) :
|
|
VF2PF_MBOX_CTRL(mbx, vfnum);
|
|
|
|
while (try_cnt-- > 0) {
|
|
/* Take ownership of the buffer */
|
|
mbx_wr32(hw, CTRL_REG, MBOX_CTRL_VF_HOLD_SHM);
|
|
/* memory barrier */
|
|
mb();
|
|
/* reserve mailbox for vf use */
|
|
if (mbx_rd32(hw, CTRL_REG) & MBOX_CTRL_VF_HOLD_SHM)
|
|
return 0;
|
|
udelay(500);
|
|
}
|
|
|
|
return RNPGBE_ERR_MBX;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_write_mbx_vf - Write a message to the mailbox
|
|
* @hw: pointer to the HW structure
|
|
* @msg: The message buffer
|
|
* @size: Length of buffer
|
|
* @to_cm3: to cm3 or not
|
|
*
|
|
* returns 0 if it successfully copied message into the buffer
|
|
**/
|
|
static s32 rnpgbevf_write_mbx_vf(struct rnpgbevf_hw *hw, u32 *msg, u16 size,
|
|
bool to_cm3)
|
|
{
|
|
s32 ret_val;
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 i;
|
|
u8 vfnum = VFNUM(mbx, hw->vfnum);
|
|
u32 DATA_REG = (to_cm3) ? CPU_VF_SHM_DATA(mbx, vfnum) :
|
|
PF_VF_SHM_DATA(mbx, vfnum);
|
|
u32 CTRL_REG = (to_cm3) ? VF2CPU_MBOX_CTRL(mbx, vfnum) :
|
|
VF2PF_MBOX_CTRL(mbx, vfnum);
|
|
|
|
/* lock the mailbox to prevent pf/vf race condition */
|
|
ret_val = rnpgbevf_obtain_mbx_lock_vf(hw, to_cm3);
|
|
if (ret_val)
|
|
goto out_no_write;
|
|
|
|
/* add mailbox_id [27:21] */
|
|
#define VF_NUM_OFFSET (21)
|
|
if (!to_cm3)
|
|
msg[0] |= ((hw->vfnum & 0x3f) << VF_NUM_OFFSET);
|
|
|
|
/* copy the caller specified message to the mailbox memory buffer */
|
|
for (i = 0; i < size; i++)
|
|
mbx_wr32(hw, DATA_REG + i * 4, msg[i]);
|
|
|
|
/* update acks. used by rnpgbevf_check_for_ack_vf */
|
|
if (to_cm3)
|
|
hw->mbx.cpu_ack =
|
|
rnpgbevf_mbx_get_ack(hw, CPU2VF_COUNTER(mbx, vfnum));
|
|
else
|
|
hw->mbx.pf_ack =
|
|
rnpgbevf_mbx_get_ack(hw, PF2VF_COUNTER(mbx, vfnum));
|
|
rnpgbevf_mbx_inc_vfreq(hw, to_cm3);
|
|
|
|
/* Drop VFU and interrupt the PF/CM3 to
|
|
* tell it a message has been sent
|
|
*/
|
|
mbx_wr32(hw, CTRL_REG, MBOX_CTRL_REQ);
|
|
|
|
out_no_write:
|
|
return ret_val;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_read_mbx_vf - Reads a message from the inbox intended for vf
|
|
* @hw: pointer to the HW structure
|
|
* @msg: The message buffer
|
|
* @size: Length of buffer
|
|
* @to_cm3: to cm3 or not
|
|
*
|
|
* returns 0 if it successfully read message from buffer
|
|
**/
|
|
static s32 rnpgbevf_read_mbx_vf(struct rnpgbevf_hw *hw, u32 *msg, u16 size,
|
|
bool to_cm3)
|
|
{
|
|
s32 ret_val = 0;
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u32 i;
|
|
u8 vfnum = VFNUM(mbx, hw->vfnum);
|
|
u32 BUF_REG = (to_cm3) ? CPU_VF_SHM_DATA(mbx, vfnum) :
|
|
PF_VF_SHM_DATA(mbx, vfnum);
|
|
u32 CTRL_REG = (to_cm3) ? VF2CPU_MBOX_CTRL(mbx, vfnum) :
|
|
VF2PF_MBOX_CTRL(mbx, vfnum);
|
|
|
|
/* lock the mailbox to prevent pf/vf race condition */
|
|
ret_val = rnpgbevf_obtain_mbx_lock_vf(hw, to_cm3);
|
|
if (ret_val)
|
|
goto out_no_read;
|
|
|
|
/* we need this */
|
|
mb();
|
|
/* copy the message from the mailbox memory buffer */
|
|
for (i = 0; i < size; i++)
|
|
msg[i] = mbx_rd32(hw, BUF_REG + 4 * i);
|
|
|
|
/* clear vf_num */
|
|
#define RNPGBE_VF_NUM_MASK (0x7f << 21)
|
|
msg[0] &= (~RNPGBE_VF_NUM_MASK);
|
|
|
|
/* update req. used by rnpgbevf_check_for_msg_vf */
|
|
if (to_cm3)
|
|
hw->mbx.cpu_req =
|
|
rnpgbevf_mbx_get_req(hw, CPU2VF_COUNTER(mbx, vfnum));
|
|
else
|
|
hw->mbx.pf_req =
|
|
rnpgbevf_mbx_get_req(hw, PF2VF_COUNTER(mbx, vfnum));
|
|
/* Acknowledge receipt and release mailbox, then we're done */
|
|
rnpgbevf_mbx_inc_vfack(hw, to_cm3);
|
|
|
|
/* free ownership of the buffer */
|
|
mbx_wr32(hw, CTRL_REG, 0);
|
|
|
|
out_no_read:
|
|
return ret_val;
|
|
}
|
|
|
|
static void rnpgbevf_reset_mbx(struct rnpgbevf_hw *hw)
|
|
{
|
|
u32 v;
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
u8 vfnum = VFNUM(mbx, hw->vfnum);
|
|
|
|
mbx_wr32(hw, VF2CPU_MBOX_CTRL(mbx, vfnum), 0);
|
|
mbx_wr32(hw, VF2PF_MBOX_CTRL(mbx, vfnum), 0);
|
|
|
|
v = mbx_rd32(hw, PF2VF_COUNTER(mbx, vfnum));
|
|
hw->mbx.pf_req = v & 0xffff;
|
|
hw->mbx.pf_ack = (v >> 16) & 0xffff;
|
|
|
|
v = mbx_rd32(hw, CPU2VF_COUNTER(mbx, vfnum));
|
|
hw->mbx.cpu_req = v & 0xffff;
|
|
hw->mbx.cpu_ack = (v >> 16) & 0xffff;
|
|
}
|
|
|
|
static s32 rnpgbevf_mbx_configure_vf(struct rnpgbevf_hw *hw, int nr_vec,
|
|
bool enable)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
int mbx_vec_reg, vfnum = VFNUM(mbx, hw->vfnum);
|
|
|
|
mbx_vec_reg = PF2VF_MBOX_VEC(mbx, vfnum);
|
|
mbx_wr32(hw, mbx_vec_reg, nr_vec);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rnpgbevf_init_mbx_params_vf - set initial values for vf mailbox
|
|
* @hw: pointer to the HW structure
|
|
*
|
|
* Initializes the hw->mbx struct to correct values for vf mailbox
|
|
*/
|
|
static s32 rnpgbevf_init_mbx_params_vf(struct rnpgbevf_hw *hw)
|
|
{
|
|
struct rnp_mbx_info *mbx = &hw->mbx;
|
|
|
|
/* start mailbox as timed out and let the reset_hw call set the timeout
|
|
* value to begin communications
|
|
*/
|
|
mbx->timeout = 0;
|
|
mbx->udelay = RNPGBE_VF_MBX_INIT_DELAY;
|
|
|
|
mbx->stats.msgs_tx = 0;
|
|
mbx->stats.msgs_rx = 0;
|
|
mbx->stats.reqs = 0;
|
|
mbx->stats.acks = 0;
|
|
mbx->stats.rsts = 0;
|
|
mbx->size = RNPGBE_VFMAILBOX_SIZE;
|
|
rnpgbevf_reset_mbx(hw);
|
|
|
|
return 0;
|
|
}
|
|
|
|
const struct rnp_mbx_operations rnpgbevf_mbx_ops = {
|
|
.init_params = rnpgbevf_init_mbx_params_vf,
|
|
.read = rnpgbevf_read_mbx_vf,
|
|
.write = rnpgbevf_write_mbx_vf,
|
|
.read_posted = rnpgbevf_read_posted_mbx,
|
|
.write_posted = rnpgbevf_write_posted_mbx,
|
|
.check_for_msg = rnpgbevf_check_for_msg_vf,
|
|
.check_for_ack = rnpgbevf_check_for_ack_vf,
|
|
.check_for_rst = rnpgbevf_check_for_rst_msg_vf,
|
|
.configure = rnpgbevf_mbx_configure_vf,
|
|
};
|