mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Implements the mailbox interfaces for Wangxun vf drivers which will be used in txgbevf and ngbevf. Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com> Link: https://patch.msgid.link/20250704094923.652-2-mengyuanlou@net-swift.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
419 lines
9.9 KiB
C
419 lines
9.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
|
|
|
|
#include <linux/pci.h>
|
|
#include "wx_type.h"
|
|
#include "wx_mbx.h"
|
|
|
|
/**
|
|
* wx_obtain_mbx_lock_pf - obtain mailbox lock
|
|
* @wx: pointer to the HW structure
|
|
* @vf: the VF index
|
|
*
|
|
* Return: return 0 on success and -EBUSY on failure
|
|
**/
|
|
static int wx_obtain_mbx_lock_pf(struct wx *wx, u16 vf)
|
|
{
|
|
int count = 5;
|
|
u32 mailbox;
|
|
|
|
while (count--) {
|
|
/* Take ownership of the buffer */
|
|
wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_PFU);
|
|
|
|
/* reserve mailbox for vf use */
|
|
mailbox = rd32(wx, WX_PXMAILBOX(vf));
|
|
if (mailbox & WX_PXMAILBOX_PFU)
|
|
return 0;
|
|
else if (count)
|
|
udelay(10);
|
|
}
|
|
wx_err(wx, "Failed to obtain mailbox lock for PF%d", vf);
|
|
|
|
return -EBUSY;
|
|
}
|
|
|
|
static int wx_check_for_bit_pf(struct wx *wx, u32 mask, int index)
|
|
{
|
|
u32 mbvficr = rd32(wx, WX_MBVFICR(index));
|
|
|
|
if (!(mbvficr & mask))
|
|
return -EBUSY;
|
|
wr32(wx, WX_MBVFICR(index), mask);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* wx_check_for_ack_pf - checks to see if the VF has acked
|
|
* @wx: pointer to the HW structure
|
|
* @vf: the VF index
|
|
*
|
|
* Return: return 0 if the VF has set the status bit or else -EBUSY
|
|
**/
|
|
int wx_check_for_ack_pf(struct wx *wx, u16 vf)
|
|
{
|
|
u32 index = vf / 16, vf_bit = vf % 16;
|
|
|
|
return wx_check_for_bit_pf(wx,
|
|
FIELD_PREP(WX_MBVFICR_VFACK_MASK,
|
|
BIT(vf_bit)),
|
|
index);
|
|
}
|
|
|
|
/**
|
|
* wx_check_for_msg_pf - checks to see if the VF has sent mail
|
|
* @wx: pointer to the HW structure
|
|
* @vf: the VF index
|
|
*
|
|
* Return: return 0 if the VF has got req bit or else -EBUSY
|
|
**/
|
|
int wx_check_for_msg_pf(struct wx *wx, u16 vf)
|
|
{
|
|
u32 index = vf / 16, vf_bit = vf % 16;
|
|
|
|
return wx_check_for_bit_pf(wx,
|
|
FIELD_PREP(WX_MBVFICR_VFREQ_MASK,
|
|
BIT(vf_bit)),
|
|
index);
|
|
}
|
|
|
|
/**
|
|
* wx_write_mbx_pf - Places a message in the mailbox
|
|
* @wx: pointer to the HW structure
|
|
* @msg: The message buffer
|
|
* @size: Length of buffer
|
|
* @vf: the VF index
|
|
*
|
|
* Return: return 0 on success and -EINVAL/-EBUSY on failure
|
|
**/
|
|
int wx_write_mbx_pf(struct wx *wx, u32 *msg, u16 size, u16 vf)
|
|
{
|
|
struct wx_mbx_info *mbx = &wx->mbx;
|
|
int ret, i;
|
|
|
|
/* mbx->size is up to 15 */
|
|
if (size > mbx->size) {
|
|
wx_err(wx, "Invalid mailbox message size %d", size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* lock the mailbox to prevent pf/vf race condition */
|
|
ret = wx_obtain_mbx_lock_pf(wx, vf);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* flush msg and acks as we are overwriting the message buffer */
|
|
wx_check_for_msg_pf(wx, vf);
|
|
wx_check_for_ack_pf(wx, vf);
|
|
|
|
/* copy the caller specified message to the mailbox memory buffer */
|
|
for (i = 0; i < size; i++)
|
|
wr32a(wx, WX_PXMBMEM(vf), i, msg[i]);
|
|
|
|
/* Interrupt VF to tell it a message has been sent and release buffer */
|
|
/* set mirrored mailbox flags */
|
|
wr32a(wx, WX_PXMBMEM(vf), WX_VXMAILBOX_SIZE, WX_PXMAILBOX_STS);
|
|
wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_STS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* wx_read_mbx_pf - Read a message from the mailbox
|
|
* @wx: pointer to the HW structure
|
|
* @msg: The message buffer
|
|
* @size: Length of buffer
|
|
* @vf: the VF index
|
|
*
|
|
* Return: return 0 on success and -EBUSY on failure
|
|
**/
|
|
int wx_read_mbx_pf(struct wx *wx, u32 *msg, u16 size, u16 vf)
|
|
{
|
|
struct wx_mbx_info *mbx = &wx->mbx;
|
|
int ret;
|
|
u16 i;
|
|
|
|
/* limit read to size of mailbox and mbx->size is up to 15 */
|
|
if (size > mbx->size)
|
|
size = mbx->size;
|
|
|
|
/* lock the mailbox to prevent pf/vf race condition */
|
|
ret = wx_obtain_mbx_lock_pf(wx, vf);
|
|
if (ret)
|
|
return ret;
|
|
|
|
for (i = 0; i < size; i++)
|
|
msg[i] = rd32a(wx, WX_PXMBMEM(vf), i);
|
|
|
|
/* Acknowledge the message and release buffer */
|
|
/* set mirrored mailbox flags */
|
|
wr32a(wx, WX_PXMBMEM(vf), WX_VXMAILBOX_SIZE, WX_PXMAILBOX_ACK);
|
|
wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_ACK);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* wx_check_for_rst_pf - checks to see if the VF has reset
|
|
* @wx: pointer to the HW structure
|
|
* @vf: the VF index
|
|
*
|
|
* Return: return 0 on success and -EBUSY on failure
|
|
**/
|
|
int wx_check_for_rst_pf(struct wx *wx, u16 vf)
|
|
{
|
|
u32 reg_offset = WX_VF_REG_OFFSET(vf);
|
|
u32 vf_shift = WX_VF_IND_SHIFT(vf);
|
|
u32 vflre = 0;
|
|
|
|
vflre = rd32(wx, WX_VFLRE(reg_offset));
|
|
if (!(vflre & BIT(vf_shift)))
|
|
return -EBUSY;
|
|
wr32(wx, WX_VFLREC(reg_offset), BIT(vf_shift));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static u32 wx_read_v2p_mailbox(struct wx *wx)
|
|
{
|
|
u32 mailbox = rd32(wx, WX_VXMAILBOX);
|
|
|
|
mailbox |= wx->mbx.mailbox;
|
|
wx->mbx.mailbox |= mailbox & WX_VXMAILBOX_R2C_BITS;
|
|
|
|
return mailbox;
|
|
}
|
|
|
|
static u32 wx_mailbox_get_lock_vf(struct wx *wx)
|
|
{
|
|
wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_VFU);
|
|
return wx_read_v2p_mailbox(wx);
|
|
}
|
|
|
|
/**
|
|
* wx_obtain_mbx_lock_vf - obtain mailbox lock
|
|
* @wx: pointer to the HW structure
|
|
*
|
|
* Return: return 0 on success and -EBUSY on failure
|
|
**/
|
|
static int wx_obtain_mbx_lock_vf(struct wx *wx)
|
|
{
|
|
int count = 5, ret;
|
|
u32 mailbox;
|
|
|
|
ret = readx_poll_timeout_atomic(wx_mailbox_get_lock_vf, wx, mailbox,
|
|
(mailbox & WX_VXMAILBOX_VFU),
|
|
1, count);
|
|
if (ret)
|
|
wx_err(wx, "Failed to obtain mailbox lock for VF.\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int wx_check_for_bit_vf(struct wx *wx, u32 mask)
|
|
{
|
|
u32 mailbox = wx_read_v2p_mailbox(wx);
|
|
|
|
wx->mbx.mailbox &= ~mask;
|
|
|
|
return (mailbox & mask ? 0 : -EBUSY);
|
|
}
|
|
|
|
/**
|
|
* wx_check_for_ack_vf - checks to see if the PF has ACK'd
|
|
* @wx: pointer to the HW structure
|
|
*
|
|
* Return: return 0 if the PF has set the status bit or else -EBUSY
|
|
**/
|
|
static int wx_check_for_ack_vf(struct wx *wx)
|
|
{
|
|
/* read clear the pf ack bit */
|
|
return wx_check_for_bit_vf(wx, WX_VXMAILBOX_PFACK);
|
|
}
|
|
|
|
/**
|
|
* wx_check_for_msg_vf - checks to see if the PF has sent mail
|
|
* @wx: pointer to the HW structure
|
|
*
|
|
* Return: return 0 if the PF has got req bit or else -EBUSY
|
|
**/
|
|
int wx_check_for_msg_vf(struct wx *wx)
|
|
{
|
|
/* read clear the pf sts bit */
|
|
return wx_check_for_bit_vf(wx, WX_VXMAILBOX_PFSTS);
|
|
}
|
|
|
|
/**
|
|
* wx_check_for_rst_vf - checks to see if the PF has reset
|
|
* @wx: pointer to the HW structure
|
|
*
|
|
* Return: return 0 if the PF has set the reset done and -EBUSY on failure
|
|
**/
|
|
int wx_check_for_rst_vf(struct wx *wx)
|
|
{
|
|
/* read clear the pf reset done bit */
|
|
return wx_check_for_bit_vf(wx,
|
|
WX_VXMAILBOX_RSTD |
|
|
WX_VXMAILBOX_RSTI);
|
|
}
|
|
|
|
/**
|
|
* wx_poll_for_msg - Wait for message notification
|
|
* @wx: pointer to the HW structure
|
|
*
|
|
* Return: return 0 if the VF has successfully received a message notification
|
|
**/
|
|
static int wx_poll_for_msg(struct wx *wx)
|
|
{
|
|
struct wx_mbx_info *mbx = &wx->mbx;
|
|
u32 val;
|
|
|
|
return readx_poll_timeout_atomic(wx_check_for_msg_vf, wx, val,
|
|
(val == 0), mbx->udelay, mbx->timeout);
|
|
}
|
|
|
|
/**
|
|
* wx_poll_for_ack - Wait for message acknowledgment
|
|
* @wx: pointer to the HW structure
|
|
*
|
|
* Return: return 0 if the VF has successfully received a message ack
|
|
**/
|
|
static int wx_poll_for_ack(struct wx *wx)
|
|
{
|
|
struct wx_mbx_info *mbx = &wx->mbx;
|
|
u32 val;
|
|
|
|
return readx_poll_timeout_atomic(wx_check_for_ack_vf, wx, val,
|
|
(val == 0), mbx->udelay, mbx->timeout);
|
|
}
|
|
|
|
/**
|
|
* wx_read_posted_mbx - Wait for message notification and receive message
|
|
* @wx: pointer to the HW structure
|
|
* @msg: The message buffer
|
|
* @size: Length of buffer
|
|
*
|
|
* Return: returns 0 if it successfully received a message notification and
|
|
* copied it into the receive buffer.
|
|
**/
|
|
int wx_read_posted_mbx(struct wx *wx, u32 *msg, u16 size)
|
|
{
|
|
int ret;
|
|
|
|
ret = wx_poll_for_msg(wx);
|
|
/* if ack received read message, otherwise we timed out */
|
|
if (ret)
|
|
return ret;
|
|
|
|
return wx_read_mbx_vf(wx, msg, size);
|
|
}
|
|
|
|
/**
|
|
* wx_write_posted_mbx - Write a message to the mailbox, wait for ack
|
|
* @wx: pointer to the HW structure
|
|
* @msg: The message buffer
|
|
* @size: Length of buffer
|
|
*
|
|
* Return: returns 0 if it successfully copied message into the buffer and
|
|
* received an ack to that message within delay * timeout period
|
|
**/
|
|
int wx_write_posted_mbx(struct wx *wx, u32 *msg, u16 size)
|
|
{
|
|
int ret;
|
|
|
|
/* send msg */
|
|
ret = wx_write_mbx_vf(wx, msg, size);
|
|
/* if msg sent wait until we receive an ack */
|
|
if (ret)
|
|
return ret;
|
|
|
|
return wx_poll_for_ack(wx);
|
|
}
|
|
|
|
/**
|
|
* wx_write_mbx_vf - Write a message to the mailbox
|
|
* @wx: pointer to the HW structure
|
|
* @msg: The message buffer
|
|
* @size: Length of buffer
|
|
*
|
|
* Return: returns 0 if it successfully copied message into the buffer
|
|
**/
|
|
int wx_write_mbx_vf(struct wx *wx, u32 *msg, u16 size)
|
|
{
|
|
struct wx_mbx_info *mbx = &wx->mbx;
|
|
int ret, i;
|
|
|
|
/* mbx->size is up to 15 */
|
|
if (size > mbx->size) {
|
|
wx_err(wx, "Invalid mailbox message size %d", size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* lock the mailbox to prevent pf/vf race condition */
|
|
ret = wx_obtain_mbx_lock_vf(wx);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* flush msg and acks as we are overwriting the message buffer */
|
|
wx_check_for_msg_vf(wx);
|
|
wx_check_for_ack_vf(wx);
|
|
|
|
/* copy the caller specified message to the mailbox memory buffer */
|
|
for (i = 0; i < size; i++)
|
|
wr32a(wx, WX_VXMBMEM, i, msg[i]);
|
|
|
|
/* Drop VFU and interrupt the PF to tell it a message has been sent */
|
|
wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_REQ);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* wx_read_mbx_vf - Reads a message from the inbox intended for vf
|
|
* @wx: pointer to the HW structure
|
|
* @msg: The message buffer
|
|
* @size: Length of buffer
|
|
*
|
|
* Return: returns 0 if it successfully copied message into the buffer
|
|
**/
|
|
int wx_read_mbx_vf(struct wx *wx, u32 *msg, u16 size)
|
|
{
|
|
struct wx_mbx_info *mbx = &wx->mbx;
|
|
int ret, i;
|
|
|
|
/* limit read to size of mailbox and mbx->size is up to 15 */
|
|
if (size > mbx->size)
|
|
size = mbx->size;
|
|
|
|
/* lock the mailbox to prevent pf/vf race condition */
|
|
ret = wx_obtain_mbx_lock_vf(wx);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* copy the message from the mailbox memory buffer */
|
|
for (i = 0; i < size; i++)
|
|
msg[i] = rd32a(wx, WX_VXMBMEM, i);
|
|
|
|
/* Acknowledge receipt and release mailbox, then we're done */
|
|
wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_ACK);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int wx_init_mbx_params_vf(struct wx *wx)
|
|
{
|
|
wx->vfinfo = kzalloc(sizeof(struct vf_data_storage),
|
|
GFP_KERNEL);
|
|
if (!wx->vfinfo)
|
|
return -ENOMEM;
|
|
|
|
/* Initialize mailbox parameters */
|
|
wx->mbx.size = WX_VXMAILBOX_SIZE;
|
|
wx->mbx.mailbox = WX_VXMAILBOX;
|
|
wx->mbx.udelay = 10;
|
|
wx->mbx.timeout = 1000;
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(wx_init_mbx_params_vf);
|