#include <linux/pci.h>
#include "wx_type.h"
#include "wx_mbx.h"
static int wx_obtain_mbx_lock_pf(struct wx *wx, u16 vf)
{
int count = 5;
u32 mailbox;
while (count--) {
wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_PFU);
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;
}
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);
}
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);
}
int wx_write_mbx_pf(struct wx *wx, u32 *msg, u16 size, u16 vf)
{
struct wx_mbx_info *mbx = &wx->mbx;
int ret, i;
if (size > mbx->size) {
wx_err(wx, "Invalid mailbox message size %d", size);
return -EINVAL;
}
ret = wx_obtain_mbx_lock_pf(wx, vf);
if (ret)
return ret;
wx_check_for_msg_pf(wx, vf);
wx_check_for_ack_pf(wx, vf);
for (i = 0; i < size; i++)
wr32a(wx, WX_PXMBMEM(vf), i, msg[i]);
wr32a(wx, WX_PXMBMEM(vf), WX_VXMAILBOX_SIZE, WX_PXMAILBOX_STS);
wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_STS);
return 0;
}
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;
if (size > mbx->size)
size = mbx->size;
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);
wr32a(wx, WX_PXMBMEM(vf), WX_VXMAILBOX_SIZE, WX_PXMAILBOX_ACK);
wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_ACK);
return 0;
}
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);
}
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);
}
static int wx_check_for_ack_vf(struct wx *wx)
{
return wx_check_for_bit_vf(wx, WX_VXMAILBOX_PFACK);
}
int wx_check_for_msg_vf(struct wx *wx)
{
return wx_check_for_bit_vf(wx, WX_VXMAILBOX_PFSTS);
}
int wx_check_for_rst_vf(struct wx *wx)
{
return wx_check_for_bit_vf(wx,
WX_VXMAILBOX_RSTD |
WX_VXMAILBOX_RSTI);
}
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);
}
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);
}
int wx_read_posted_mbx(struct wx *wx, u32 *msg, u16 size)
{
int ret;
ret = wx_poll_for_msg(wx);
if (ret)
return ret;
return wx_read_mbx_vf(wx, msg, size);
}
int wx_write_posted_mbx(struct wx *wx, u32 *msg, u16 size)
{
int ret;
ret = wx_write_mbx_vf(wx, msg, size);
if (ret)
return ret;
return wx_poll_for_ack(wx);
}
int wx_write_mbx_vf(struct wx *wx, u32 *msg, u16 size)
{
struct wx_mbx_info *mbx = &wx->mbx;
int ret, i;
if (size > mbx->size) {
wx_err(wx, "Invalid mailbox message size %d", size);
return -EINVAL;
}
ret = wx_obtain_mbx_lock_vf(wx);
if (ret)
return ret;
wx_check_for_msg_vf(wx);
wx_check_for_ack_vf(wx);
for (i = 0; i < size; i++)
wr32a(wx, WX_VXMBMEM, i, msg[i]);
wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_REQ);
return 0;
}
int wx_read_mbx_vf(struct wx *wx, u32 *msg, u16 size)
{
struct wx_mbx_info *mbx = &wx->mbx;
int ret, i;
if (size > mbx->size)
size = mbx->size;
ret = wx_obtain_mbx_lock_vf(wx);
if (ret)
return ret;
for (i = 0; i < size; i++)
msg[i] = rd32a(wx, WX_VXMBMEM, i);
wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_ACK);
return 0;
}
int wx_init_mbx_params_vf(struct wx *wx)
{
wx->vfinfo = kzalloc_obj(struct vf_data_storage);
if (!wx->vfinfo)
return -ENOMEM;
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);