* [PATCH net-next 01/12] net: libwx: add mailbox api for wangxun vf drivers
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-18 9:46 ` Michal Swiatkowski
2025-06-11 8:35 ` [PATCH net-next 02/12] net: libwx: add base vf api for " Mengyuan Lou
` (10 subsequent siblings)
11 siblings, 1 reply; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
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>
---
drivers/net/ethernet/wangxun/libwx/wx_mbx.c | 256 +++++++++++++++++++
drivers/net/ethernet/wangxun/libwx/wx_mbx.h | 22 ++
drivers/net/ethernet/wangxun/libwx/wx_type.h | 3 +
3 files changed, 281 insertions(+)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_mbx.c b/drivers/net/ethernet/wangxun/libwx/wx_mbx.c
index 73af5f11c3bd..ebfa07d50bd2 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_mbx.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_mbx.c
@@ -174,3 +174,259 @@ int wx_check_for_rst_pf(struct wx *wx, u16 vf)
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;
+}
+
+/**
+ * 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;
+ u32 mailbox;
+
+ while (count--) {
+ /* Take ownership of the buffer */
+ wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_VFU);
+
+ /* reserve mailbox for vf use */
+ mailbox = wx_read_v2p_mailbox(wx);
+ if (mailbox & WX_VXMAILBOX_VFU)
+ return 0;
+ }
+
+ wx_err(wx, "Failed to obtain mailbox lock for VF.\n");
+
+ return -EBUSY;
+}
+
+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;
+ int countdown = mbx->timeout;
+
+ while (countdown && wx_check_for_msg_vf(wx)) {
+ countdown--;
+ if (!countdown)
+ break;
+ udelay(mbx->udelay);
+ }
+
+ return countdown ? 0 : -EBUSY;
+}
+
+/**
+ * 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;
+ int countdown = mbx->timeout;
+
+ while (countdown && wx_check_for_ack_vf(wx)) {
+ countdown--;
+ if (!countdown)
+ break;
+ udelay(mbx->udelay);
+ }
+
+ return countdown ? 0 : -EBUSY;
+}
+
+/**
+ * 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)
+ ret = wx_read_mbx_vf(wx, msg, size);
+
+ return ret;
+}
+
+/**
+ * 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)
+ ret = wx_poll_for_ack(wx);
+
+ return ret;
+}
+
+/**
+ * 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;
+ 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_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 = kcalloc(1, 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);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_mbx.h b/drivers/net/ethernet/wangxun/libwx/wx_mbx.h
index 05aae138dbc3..82df9218490a 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_mbx.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_mbx.h
@@ -11,6 +11,20 @@
#define WX_PXMAILBOX_ACK BIT(1) /* Ack message recv'd from VF */
#define WX_PXMAILBOX_PFU BIT(3) /* PF owns the mailbox buffer */
+/* VF Registers */
+#define WX_VXMAILBOX 0x600
+#define WX_VXMAILBOX_REQ BIT(0) /* Request for PF Ready bit */
+#define WX_VXMAILBOX_ACK BIT(1) /* Ack PF message received */
+#define WX_VXMAILBOX_VFU BIT(2) /* VF owns the mailbox buffer */
+#define WX_VXMAILBOX_PFU BIT(3) /* PF owns the mailbox buffer */
+#define WX_VXMAILBOX_PFSTS BIT(4) /* PF wrote a message in the MB */
+#define WX_VXMAILBOX_PFACK BIT(5) /* PF ack the previous VF msg */
+#define WX_VXMAILBOX_RSTI BIT(6) /* PF has reset indication */
+#define WX_VXMAILBOX_RSTD BIT(7) /* PF has indicated reset done */
+#define WX_VXMAILBOX_R2C_BITS (WX_VXMAILBOX_RSTD | \
+ WX_VXMAILBOX_PFSTS | WX_VXMAILBOX_PFACK)
+
+#define WX_VXMBMEM 0x00C00 /* 16*4B */
#define WX_PXMBMEM(i) (0x5000 + (64 * (i))) /* i=[0,63] */
#define WX_VFLRE(i) (0x4A0 + (4 * (i))) /* i=[0,1] */
@@ -74,4 +88,12 @@ int wx_check_for_rst_pf(struct wx *wx, u16 mbx_id);
int wx_check_for_msg_pf(struct wx *wx, u16 mbx_id);
int wx_check_for_ack_pf(struct wx *wx, u16 mbx_id);
+int wx_read_posted_mbx(struct wx *wx, u32 *msg, u16 size);
+int wx_write_posted_mbx(struct wx *wx, u32 *msg, u16 size);
+int wx_check_for_rst_vf(struct wx *wx);
+int wx_check_for_msg_vf(struct wx *wx);
+int wx_read_mbx_vf(struct wx *wx, u32 *msg, u16 size);
+int wx_write_mbx_vf(struct wx *wx, u32 *msg, u16 size);
+int wx_init_mbx_params_vf(struct wx *wx);
+
#endif /* _WX_MBX_H_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 7730c9fc3e02..f2061c893358 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -825,6 +825,9 @@ struct wx_bus_info {
struct wx_mbx_info {
u16 size;
+ u32 mailbox;
+ u32 udelay;
+ u32 timeout;
};
struct wx_thermal_sensor_data {
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH net-next 01/12] net: libwx: add mailbox api for wangxun vf drivers
2025-06-11 8:35 ` [PATCH net-next 01/12] net: libwx: add mailbox api for wangxun vf drivers Mengyuan Lou
@ 2025-06-18 9:46 ` Michal Swiatkowski
2025-06-20 8:32 ` mengyuanlou
0 siblings, 1 reply; 20+ messages in thread
From: Michal Swiatkowski @ 2025-06-18 9:46 UTC (permalink / raw)
To: Mengyuan Lou
Cc: netdev, kuba, pabeni, horms, andrew+netdev, duanqiangwen,
linglingzhang, jiawenwu
On Wed, Jun 11, 2025 at 04:35:48PM +0800, Mengyuan Lou wrote:
> 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>
> ---
> drivers/net/ethernet/wangxun/libwx/wx_mbx.c | 256 +++++++++++++++++++
> drivers/net/ethernet/wangxun/libwx/wx_mbx.h | 22 ++
> drivers/net/ethernet/wangxun/libwx/wx_type.h | 3 +
> 3 files changed, 281 insertions(+)
>
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_mbx.c b/drivers/net/ethernet/wangxun/libwx/wx_mbx.c
> index 73af5f11c3bd..ebfa07d50bd2 100644
> --- a/drivers/net/ethernet/wangxun/libwx/wx_mbx.c
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_mbx.c
> @@ -174,3 +174,259 @@ int wx_check_for_rst_pf(struct wx *wx, u16 vf)
>
> 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;
> +}
> +
> +/**
> + * 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;
> + u32 mailbox;
> +
> + while (count--) {
> + /* Take ownership of the buffer */
> + wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_VFU);
> +
> + /* reserve mailbox for vf use */
> + mailbox = wx_read_v2p_mailbox(wx);
> + if (mailbox & WX_VXMAILBOX_VFU)
> + return 0;
> + }
You can try to use read_poll_timeout(). In other poll also.
> +
> + wx_err(wx, "Failed to obtain mailbox lock for VF.\n");
> +
> + return -EBUSY;
> +}
> +
> +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;
> + int countdown = mbx->timeout;
> +
> + while (countdown && wx_check_for_msg_vf(wx)) {
> + countdown--;
> + if (!countdown)
> + break;
> + udelay(mbx->udelay);
> + }
Here
> +
> + return countdown ? 0 : -EBUSY;
> +}
> +
> +/**
> + * 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;
> + int countdown = mbx->timeout;
> +
> + while (countdown && wx_check_for_ack_vf(wx)) {
> + countdown--;
> + if (!countdown)
> + break;
> + udelay(mbx->udelay);
> + }
And here
> +
> + return countdown ? 0 : -EBUSY;
> +}
> +
> +/**
> + * 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)
> + ret = wx_read_mbx_vf(wx, msg, size);
> +
> + return ret;
Nit, but usuall error path is in if statement. Sth like:
if (ret)
return ret;
return wx_read_mbx_vf();
can be more readable for someone.
> +}
> +
> +/**
> + * 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)
> + ret = wx_poll_for_ack(wx);
> +
> + return ret;
> +}
> +
> +/**
> + * 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);
Isn't checking returned value needed here?
> +
> + /* 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);
It isn't clear that it drops lock, maybe do it in a function like
wx_drop_mbx_lock_vf()? (just preference)
> +
> + 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;
> + u16 i;
int ret, i; like in previous function
> +
> + /* 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);
Oh, so any value written into WX_VXMAILVOX drop the lock. Ignore my
comment about function for that.
> +
> + return 0;
> +}
> +
> +int wx_init_mbx_params_vf(struct wx *wx)
> +{
> + wx->vfinfo = kcalloc(1, sizeof(struct vf_data_storage),
> + GFP_KERNEL);
Why kcalloc() for 1 element?
> + 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);
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_mbx.h b/drivers/net/ethernet/wangxun/libwx/wx_mbx.h
> index 05aae138dbc3..82df9218490a 100644
> --- a/drivers/net/ethernet/wangxun/libwx/wx_mbx.h
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_mbx.h
> @@ -11,6 +11,20 @@
> #define WX_PXMAILBOX_ACK BIT(1) /* Ack message recv'd from VF */
> #define WX_PXMAILBOX_PFU BIT(3) /* PF owns the mailbox buffer */
>
> +/* VF Registers */
> +#define WX_VXMAILBOX 0x600
> +#define WX_VXMAILBOX_REQ BIT(0) /* Request for PF Ready bit */
> +#define WX_VXMAILBOX_ACK BIT(1) /* Ack PF message received */
> +#define WX_VXMAILBOX_VFU BIT(2) /* VF owns the mailbox buffer */
> +#define WX_VXMAILBOX_PFU BIT(3) /* PF owns the mailbox buffer */
> +#define WX_VXMAILBOX_PFSTS BIT(4) /* PF wrote a message in the MB */
> +#define WX_VXMAILBOX_PFACK BIT(5) /* PF ack the previous VF msg */
> +#define WX_VXMAILBOX_RSTI BIT(6) /* PF has reset indication */
> +#define WX_VXMAILBOX_RSTD BIT(7) /* PF has indicated reset done */
> +#define WX_VXMAILBOX_R2C_BITS (WX_VXMAILBOX_RSTD | \
> + WX_VXMAILBOX_PFSTS | WX_VXMAILBOX_PFACK)
> +
> +#define WX_VXMBMEM 0x00C00 /* 16*4B */
> #define WX_PXMBMEM(i) (0x5000 + (64 * (i))) /* i=[0,63] */
>
> #define WX_VFLRE(i) (0x4A0 + (4 * (i))) /* i=[0,1] */
> @@ -74,4 +88,12 @@ int wx_check_for_rst_pf(struct wx *wx, u16 mbx_id);
> int wx_check_for_msg_pf(struct wx *wx, u16 mbx_id);
> int wx_check_for_ack_pf(struct wx *wx, u16 mbx_id);
>
> +int wx_read_posted_mbx(struct wx *wx, u32 *msg, u16 size);
> +int wx_write_posted_mbx(struct wx *wx, u32 *msg, u16 size);
> +int wx_check_for_rst_vf(struct wx *wx);
> +int wx_check_for_msg_vf(struct wx *wx);
> +int wx_read_mbx_vf(struct wx *wx, u32 *msg, u16 size);
> +int wx_write_mbx_vf(struct wx *wx, u32 *msg, u16 size);
> +int wx_init_mbx_params_vf(struct wx *wx);
> +
> #endif /* _WX_MBX_H_ */
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
> index 7730c9fc3e02..f2061c893358 100644
> --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
> @@ -825,6 +825,9 @@ struct wx_bus_info {
>
> struct wx_mbx_info {
> u16 size;
> + u32 mailbox;
> + u32 udelay;
> + u32 timeout;
> };
>
> struct wx_thermal_sensor_data {
> --
> 2.30.1
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH net-next 01/12] net: libwx: add mailbox api for wangxun vf drivers
2025-06-18 9:46 ` Michal Swiatkowski
@ 2025-06-20 8:32 ` mengyuanlou
0 siblings, 0 replies; 20+ messages in thread
From: mengyuanlou @ 2025-06-20 8:32 UTC (permalink / raw)
To: Michal Swiatkowski
Cc: netdev, kuba, pabeni, horms, andrew+netdev, duanqiangwen,
linglingzhang, jiawenwu
> 2025年6月18日 17:46,Michal Swiatkowski <michal.swiatkowski@linux.intel.com> 写道:
>
> On Wed, Jun 11, 2025 at 04:35:48PM +0800, Mengyuan Lou wrote:
>> 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>
>> ---
>> drivers/net/ethernet/wangxun/libwx/wx_mbx.c | 256 +++++++++++++++++++
>> drivers/net/ethernet/wangxun/libwx/wx_mbx.h | 22 ++
>> drivers/net/ethernet/wangxun/libwx/wx_type.h | 3 +
>> 3 files changed, 281 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_mbx.c b/drivers/net/ethernet/wangxun/libwx/wx_mbx.c
>> index 73af5f11c3bd..ebfa07d50bd2 100644
>> --- a/drivers/net/ethernet/wangxun/libwx/wx_mbx.c
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_mbx.c
>> @@ -174,3 +174,259 @@ int wx_check_for_rst_pf(struct wx *wx, u16 vf)
>>
>> 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;
>> +}
>> +
>> +/**
>> + * 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;
>> + u32 mailbox;
>> +
>> + while (count--) {
>> + /* Take ownership of the buffer */
>> + wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_VFU);
>> +
>> + /* reserve mailbox for vf use */
>> + mailbox = wx_read_v2p_mailbox(wx);
>> + if (mailbox & WX_VXMAILBOX_VFU)
>> + return 0;
>> + }
>
> You can try to use read_poll_timeout(). In other poll also.
>
>> +
>> + wx_err(wx, "Failed to obtain mailbox lock for VF.\n");
>> +
>> + return -EBUSY;
>> +}
>> +
>> +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;
>> + int countdown = mbx->timeout;
>> +
>> + while (countdown && wx_check_for_msg_vf(wx)) {
>> + countdown--;
>> + if (!countdown)
>> + break;
>> + udelay(mbx->udelay);
>> + }
>
> Here
>
>> +
>> + return countdown ? 0 : -EBUSY;
>> +}
>> +
>> +/**
>> + * 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;
>> + int countdown = mbx->timeout;
>> +
>> + while (countdown && wx_check_for_ack_vf(wx)) {
>> + countdown--;
>> + if (!countdown)
>> + break;
>> + udelay(mbx->udelay);
>> + }
>
> And here
>
>> +
>> + return countdown ? 0 : -EBUSY;
>> +}
>> +
>> +/**
>> + * 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)
>> + ret = wx_read_mbx_vf(wx, msg, size);
>> +
>> + return ret;
>
> Nit, but usuall error path is in if statement. Sth like:
>
> if (ret)
> return ret;
>
> return wx_read_mbx_vf();
>
> can be more readable for someone.
>
>> +}
>> +
>> +/**
>> + * 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)
>> + ret = wx_poll_for_ack(wx);
>> +
>> + return ret;
>> +}
>> +
>> +/**
>> + * 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);
>
> Isn't checking returned value needed here?
The status of the register is read clear, so do not care about it.
>
>> +
>> + /* 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);
>
> It isn't clear that it drops lock, maybe do it in a function like
> wx_drop_mbx_lock_vf()? (just preference)
>
>> +
>> + 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;
>> + u16 i;
>
> int ret, i; like in previous function
>
>> +
>> + /* 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);
>
> Oh, so any value written into WX_VXMAILVOX drop the lock. Ignore my
> comment about function for that.
>
>> +
>> + return 0;
>> +}
>> +
>> +int wx_init_mbx_params_vf(struct wx *wx)
>> +{
>> + wx->vfinfo = kcalloc(1, sizeof(struct vf_data_storage),
>> + GFP_KERNEL);
>
> Why kcalloc() for 1 element?
This code was synchronized from pf. Since pf needs to allocate several of them.
And I forgot to change it.
>
>> + 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);
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_mbx.h b/drivers/net/ethernet/wangxun/libwx/wx_mbx.h
>> index 05aae138dbc3..82df9218490a 100644
>> --- a/drivers/net/ethernet/wangxun/libwx/wx_mbx.h
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_mbx.h
>> @@ -11,6 +11,20 @@
>> #define WX_PXMAILBOX_ACK BIT(1) /* Ack message recv'd from VF */
>> #define WX_PXMAILBOX_PFU BIT(3) /* PF owns the mailbox buffer */
>>
>> +/* VF Registers */
>> +#define WX_VXMAILBOX 0x600
>> +#define WX_VXMAILBOX_REQ BIT(0) /* Request for PF Ready bit */
>> +#define WX_VXMAILBOX_ACK BIT(1) /* Ack PF message received */
>> +#define WX_VXMAILBOX_VFU BIT(2) /* VF owns the mailbox buffer */
>> +#define WX_VXMAILBOX_PFU BIT(3) /* PF owns the mailbox buffer */
>> +#define WX_VXMAILBOX_PFSTS BIT(4) /* PF wrote a message in the MB */
>> +#define WX_VXMAILBOX_PFACK BIT(5) /* PF ack the previous VF msg */
>> +#define WX_VXMAILBOX_RSTI BIT(6) /* PF has reset indication */
>> +#define WX_VXMAILBOX_RSTD BIT(7) /* PF has indicated reset done */
>> +#define WX_VXMAILBOX_R2C_BITS (WX_VXMAILBOX_RSTD | \
>> + WX_VXMAILBOX_PFSTS | WX_VXMAILBOX_PFACK)
>> +
>> +#define WX_VXMBMEM 0x00C00 /* 16*4B */
>> #define WX_PXMBMEM(i) (0x5000 + (64 * (i))) /* i=[0,63] */
>>
>> #define WX_VFLRE(i) (0x4A0 + (4 * (i))) /* i=[0,1] */
>> @@ -74,4 +88,12 @@ int wx_check_for_rst_pf(struct wx *wx, u16 mbx_id);
>> int wx_check_for_msg_pf(struct wx *wx, u16 mbx_id);
>> int wx_check_for_ack_pf(struct wx *wx, u16 mbx_id);
>>
>> +int wx_read_posted_mbx(struct wx *wx, u32 *msg, u16 size);
>> +int wx_write_posted_mbx(struct wx *wx, u32 *msg, u16 size);
>> +int wx_check_for_rst_vf(struct wx *wx);
>> +int wx_check_for_msg_vf(struct wx *wx);
>> +int wx_read_mbx_vf(struct wx *wx, u32 *msg, u16 size);
>> +int wx_write_mbx_vf(struct wx *wx, u32 *msg, u16 size);
>> +int wx_init_mbx_params_vf(struct wx *wx);
>> +
>> #endif /* _WX_MBX_H_ */
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
>> index 7730c9fc3e02..f2061c893358 100644
>> --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
>> @@ -825,6 +825,9 @@ struct wx_bus_info {
>>
>> struct wx_mbx_info {
>> u16 size;
>> + u32 mailbox;
>> + u32 udelay;
>> + u32 timeout;
>> };
>>
>> struct wx_thermal_sensor_data {
>> --
>> 2.30.1
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH net-next 02/12] net: libwx: add base vf api for vf drivers
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 01/12] net: libwx: add mailbox api for wangxun vf drivers Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-18 11:28 ` Michal Swiatkowski
2025-06-11 8:35 ` [PATCH net-next 03/12] net: libwx: add wangxun vf common api Mengyuan Lou
` (9 subsequent siblings)
11 siblings, 1 reply; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Implement mbox_write_and_read_ack functions which are
used to set basic functions like set_mac, get_link.etc
for vf.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
drivers/net/ethernet/wangxun/libwx/Makefile | 1 +
drivers/net/ethernet/wangxun/libwx/wx_hw.c | 2 +-
drivers/net/ethernet/wangxun/libwx/wx_hw.h | 1 +
drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 +
drivers/net/ethernet/wangxun/libwx/wx_vf.c | 521 +++++++++++++++++++
drivers/net/ethernet/wangxun/libwx/wx_vf.h | 61 +++
6 files changed, 586 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_vf.c
create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_vf.h
diff --git a/drivers/net/ethernet/wangxun/libwx/Makefile b/drivers/net/ethernet/wangxun/libwx/Makefile
index 9b78b604a94e..ddf0bb921676 100644
--- a/drivers/net/ethernet/wangxun/libwx/Makefile
+++ b/drivers/net/ethernet/wangxun/libwx/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_LIBWX) += libwx.o
libwx-objs := wx_hw.o wx_lib.o wx_ethtool.o wx_ptp.o wx_mbx.o wx_sriov.o
+libwx-objs += wx_vf.o
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 0f4be72116b8..82dd76f0326e 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -1107,7 +1107,7 @@ static int wx_write_uc_addr_list(struct net_device *netdev, int pool)
* by the MO field of the MCSTCTRL. The MO field is set during initialization
* to mc_filter_type.
**/
-static u32 wx_mta_vector(struct wx *wx, u8 *mc_addr)
+u32 wx_mta_vector(struct wx *wx, u8 *mc_addr)
{
u32 vector = 0;
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
index 26a56cba60b9..718015611da6 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
@@ -29,6 +29,7 @@ void wx_mac_set_default_filter(struct wx *wx, u8 *addr);
int wx_add_mac_filter(struct wx *wx, u8 *addr, u16 pool);
int wx_del_mac_filter(struct wx *wx, u8 *addr, u16 pool);
void wx_flush_sw_mac_table(struct wx *wx);
+u32 wx_mta_vector(struct wx *wx, u8 *mc_addr);
int wx_set_mac(struct net_device *netdev, void *p);
void wx_disable_rx(struct wx *wx);
int wx_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index f2061c893358..d2d0764792d4 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -1213,6 +1213,7 @@ struct wx {
void *priv;
u8 __iomem *hw_addr;
+ u8 __iomem *b4_addr; /* vf only */
struct pci_dev *pdev;
struct net_device *netdev;
struct wx_bus_info bus;
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.c b/drivers/net/ethernet/wangxun/libwx/wx_vf.c
new file mode 100644
index 000000000000..a211329fd71a
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+
+#include "wx_type.h"
+#include "wx_hw.h"
+#include "wx_mbx.h"
+#include "wx_vf.h"
+
+static void wx_virt_clr_reg(struct wx *wx)
+{
+ u32 vfsrrctl;
+ int i;
+
+ /* VRSRRCTL default values (BSIZEPACKET = 2048, BSIZEHEADER = 256) */
+ vfsrrctl = WX_VXRXDCTL_HDRSZ(wx_hdr_sz(WX_RX_HDR_SIZE));
+ vfsrrctl |= WX_VXRXDCTL_BUFSZ(wx_buf_sz(WX_RX_BUF_SIZE));
+
+ /* clear all rxd ctl */
+ for (i = 0; i < 7; i++) {
+ wr32m(wx, WX_VXRXDCTL(i),
+ WX_VXRXDCTL_HDRSZ_MASK | WX_VXRXDCTL_BUFSZ_MASK,
+ vfsrrctl);
+ }
+
+ rd32(wx, WX_VXSTATUS);
+}
+
+/**
+ * wx_start_hw_vf - Prepare hardware for Tx/Rx
+ * @wx: 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
+ **/
+void wx_start_hw_vf(struct wx *wx)
+{
+ /* Clear wx stopped flag */
+ wx->adapter_stopped = false;
+}
+EXPORT_SYMBOL(wx_start_hw_vf);
+
+/**
+ * wx_init_hw_vf - virtual function hardware initialization
+ * @wx: pointer to hardware structure
+ *
+ * Initialize the hardware by resetting the hardware and then starting
+ * the hardware
+ **/
+void wx_init_hw_vf(struct wx *wx)
+{
+ wx_start_hw_vf(wx);
+ wx_get_mac_addr_vf(wx, wx->mac.addr);
+}
+EXPORT_SYMBOL(wx_init_hw_vf);
+
+static int wx_mbx_write_and_read_reply(struct wx *wx, u32 *req_buf,
+ u32 *resp_buf, u16 size)
+{
+ int ret;
+
+ ret = wx_write_posted_mbx(wx, req_buf, size);
+ if (unlikely(ret))
+ return ret;
+
+ return wx_read_posted_mbx(wx, resp_buf, size);
+}
+
+/**
+ * wx_reset_hw_vf - Performs hardware reset
+ * @wx: pointer to hardware structure
+ *
+ * Resets the hardware by resetting the transmit and receive units, masks and
+ * clears all interrupts.
+ *
+ * Return: returns 0 on success, negative error code on failure
+ **/
+int wx_reset_hw_vf(struct wx *wx)
+{
+ struct wx_mbx_info *mbx = &wx->mbx;
+ u32 msgbuf[4] = {WX_VF_RESET};
+ u8 *addr = (u8 *)(&msgbuf[1]);
+ u32 b4_buf[16] = {0};
+ u32 timeout = 200;
+ int ret;
+ u32 i;
+
+ /* Call wx stop to disable tx/rx and clear interrupts */
+ wx_stop_adapter_vf(wx);
+
+ /* reset the api version */
+ wx->vfinfo->vf_api = wx_mbox_api_null;
+
+ /* backup msix vectors */
+ if (wx->b4_addr) {
+ for (i = 0; i < 16; i++)
+ b4_buf[i] = readl(wx->b4_addr + i * 4);
+ }
+
+ wr32m(wx, WX_VXCTRL, WX_VXCTRL_RST, WX_VXCTRL_RST);
+ rd32(wx, WX_VXSTATUS);
+
+ /* we cannot reset while the RSTI / RSTD bits are asserted */
+ while (!wx_check_for_rst_vf(wx) && timeout) {
+ timeout--;
+ udelay(5);
+ }
+
+ /* restore msix vectors */
+ if (wx->b4_addr) {
+ for (i = 0; i < 16; i++)
+ writel(b4_buf[i], wx->b4_addr + i * 4);
+ }
+
+ /* amlite: bme */
+#define WX_VX_PF_BME 0x4B8
+ if (wx->mac.type == wx_mac_aml || wx->mac.type == wx_mac_aml40)
+ wr32(wx, WX_VX_PF_BME, BIT(0));
+
+ if (!timeout)
+ return -EBUSY;
+
+ /* Reset VF registers to initial values */
+ wx_virt_clr_reg(wx);
+
+ /* mailbox timeout can now become active */
+ mbx->timeout = 2000;
+
+ ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
+ ARRAY_SIZE(msgbuf));
+ if (ret)
+ return ret;
+
+ if (msgbuf[0] != (WX_VF_RESET | WX_VT_MSGTYPE_ACK) &&
+ msgbuf[0] != (WX_VF_RESET | WX_VT_MSGTYPE_NACK))
+ return -EINVAL;
+
+ if (msgbuf[0] == (WX_VF_RESET | WX_VT_MSGTYPE_ACK))
+ ether_addr_copy(wx->mac.perm_addr, addr);
+
+ wx->mac.mc_filter_type = msgbuf[3];
+
+ return 0;
+}
+EXPORT_SYMBOL(wx_reset_hw_vf);
+
+/**
+ * wx_stop_adapter_vf - Generic stop Tx/Rx units
+ * @wx: pointer to hardware structure
+ *
+ * Sets the adapter_stopped flag within wx struct. Clears interrupts,
+ * disables transmit and receive units. The adapter_stopped flag is used by
+ * the shared code and drivers to determine if the wx is in a stopped
+ * state and should not touch the hardware.
+ *
+ * Return: returns 0 on success, negative error code on failure
+ **/
+int wx_stop_adapter_vf(struct wx *wx)
+{
+ u32 reg_val;
+ u16 i;
+
+ wx->adapter_stopped = true;
+
+ /* Clear interrupt mask to stop from interrupts being generated */
+ wr32(wx, WX_VXIMS, WX_VF_IRQ_CLEAR_MASK);
+
+ /* Clear any pending interrupts, flush previous writes */
+ wr32(wx, WX_VXICR, U32_MAX);
+
+ /* Disable the transmit unit. Each queue must be disabled. */
+ for (i = 0; i < wx->mac.max_tx_queues; i++)
+ wr32(wx, WX_VXTXDCTL(i), WX_VXTXDCTL_FLUSH);
+
+ /* Disable the receive unit by stopping each queue */
+ for (i = 0; i < wx->mac.max_rx_queues; i++) {
+ reg_val = rd32(wx, WX_VXRXDCTL(i));
+ reg_val &= ~WX_VXRXDCTL_ENABLE;
+ wr32(wx, WX_VXRXDCTL(i), reg_val);
+ }
+ /* Clear packet split and pool config */
+ wr32(wx, WX_VXMRQC, 0);
+
+ /* flush all queues disables */
+ rd32(wx, WX_VXSTATUS);
+
+ return 0;
+}
+EXPORT_SYMBOL(wx_stop_adapter_vf);
+
+/**
+ * wx_set_rar_vf - set device MAC address
+ * @wx: pointer to hardware structure
+ * @index: Receive address register to write
+ * @addr: Address to put into receive address register
+ * @enable_addr: set flag that address is active
+ *
+ * Return: returns 0 on success, negative error code on failure
+ **/
+int wx_set_rar_vf(struct wx *wx, u32 index, u8 *addr, u32 enable_addr)
+{
+ u32 msgbuf[3] = {WX_VF_SET_MAC_ADDR};
+ u8 *msg_addr = (u8 *)(&msgbuf[1]);
+ int ret;
+
+ memcpy(msg_addr, addr, ETH_ALEN);
+
+ ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
+ ARRAY_SIZE(msgbuf));
+ if (ret)
+ return ret;
+ msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
+
+ /* if nacked the address was rejected, use "perm_addr" */
+ if (msgbuf[0] == (WX_VF_SET_MAC_ADDR | WX_VT_MSGTYPE_NACK)) {
+ wx_get_mac_addr_vf(wx, wx->mac.addr);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(wx_set_rar_vf);
+
+/**
+ * wx_update_mc_addr_list_vf - Update Multicast addresses
+ * @wx: pointer to the HW structure
+ * @netdev: pointer to the net device structure
+ *
+ * Updates the Multicast Table Array.
+ *
+ * Return: returns 0 on success, negative error code on failure
+ **/
+int wx_update_mc_addr_list_vf(struct wx *wx, struct net_device *netdev)
+{
+ u32 msgbuf[WX_VXMAILBOX_SIZE] = {0};
+ u16 *vector_l = (u16 *)&msgbuf[1];
+ struct netdev_hw_addr *ha;
+ u32 cnt, i;
+
+ /* Each entry in the list uses 1 16 bit word. We have 30
+ * 16 bit words available in our HW msgbuf buffer (minus 1 for the
+ * msgbuf type). That's 30 hash values if we pack 'em right. If
+ * there are more than 30 MC addresses to add then punt the
+ * extras for now and then add code to handle more than 30 later.
+ * It would be unusual for a server to request that many multi-cast
+ * addresses except for in large enterprise network environments.
+ */
+
+ cnt = netdev_mc_count(netdev);
+ if (cnt > 30)
+ cnt = 30;
+ msgbuf[0] = WX_VF_SET_MULTICAST;
+ msgbuf[0] |= cnt << WX_VT_MSGINFO_SHIFT;
+
+ i = 0;
+ netdev_for_each_mc_addr(ha, netdev) {
+ if (i == cnt)
+ break;
+ if (is_link_local_ether_addr(ha->addr))
+ continue;
+
+ vector_l[i++] = wx_mta_vector(wx, ha->addr);
+ }
+
+ return wx_write_posted_mbx(wx, msgbuf, WX_VXMAILBOX_SIZE);
+}
+EXPORT_SYMBOL(wx_update_mc_addr_list_vf);
+
+/**
+ * wx_update_xcast_mode_vf - Update Multicast mode
+ * @wx: pointer to the HW structure
+ * @xcast_mode: new multicast mode
+ *
+ * Updates the Multicast Mode of VF.
+ *
+ * Return: returns 0 on success, negative error code on failure
+ **/
+int wx_update_xcast_mode_vf(struct wx *wx, int xcast_mode)
+{
+ u32 msgbuf[2] = {WX_VF_UPDATE_XCAST_MODE, xcast_mode};
+ int ret = 0;
+
+ switch (wx->vfinfo->vf_api) {
+ case wx_mbox_api_13:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
+ ARRAY_SIZE(msgbuf));
+ if (ret)
+ return ret;
+
+ msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
+ if (msgbuf[0] == (WX_VF_UPDATE_XCAST_MODE | WX_VT_MSGTYPE_NACK))
+ return -EINVAL;
+
+ return ret;
+}
+EXPORT_SYMBOL(wx_update_xcast_mode_vf);
+
+/**
+ * wx_get_link_state_vf - Get VF link state from PF
+ * @wx: pointer to the HW structure
+ * @link_state: link state storage
+ *
+ * Return: return state of the operation error or success.
+ **/
+int wx_get_link_state_vf(struct wx *wx, u16 *link_state)
+{
+ u32 msgbuf[2] = {WX_VF_GET_LINK_STATE};
+ int ret = 0;
+
+ ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
+ ARRAY_SIZE(msgbuf));
+ if (ret)
+ return ret;
+
+ if (msgbuf[0] & WX_VT_MSGTYPE_NACK)
+ return -EINVAL;
+
+ *link_state = msgbuf[1];
+
+ return ret;
+}
+EXPORT_SYMBOL(wx_get_link_state_vf);
+
+/**
+ * wx_set_vfta_vf - Set/Unset vlan filter table address
+ * @wx: pointer to the HW structure
+ * @vlan: 12 bit VLAN ID
+ * @vind: unused by VF drivers
+ * @vlan_on: if true then set bit, else clear bit
+ * @vlvf_bypass: boolean flag indicating updating default pool is okay
+ *
+ * Turn on/off specified VLAN in the VLAN filter table.
+ *
+ * Return: returns 0 on success, negative error code on failure
+ **/
+int wx_set_vfta_vf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on,
+ bool vlvf_bypass)
+{
+ u32 msgbuf[2] = {WX_VF_SET_VLAN, vlan};
+ bool vlan_offload = false;
+ int ret = 0;
+
+ /* Setting the 8 bit field MSG INFO to TRUE indicates "add" */
+ msgbuf[0] |= vlan_on << WX_VT_MSGINFO_SHIFT;
+ /* if vf vlan offload is disabled, allow to create vlan under pf port vlan */
+ msgbuf[0] |= BIT(vlan_offload);
+
+ ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
+ ARRAY_SIZE(msgbuf));
+ if (ret)
+ return ret;
+
+ if (msgbuf[0] & WX_VT_MSGTYPE_ACK)
+ return 0;
+
+ return msgbuf[0] & WX_VT_MSGTYPE_NACK;
+}
+EXPORT_SYMBOL(wx_set_vfta_vf);
+
+void wx_get_mac_addr_vf(struct wx *wx, u8 *mac_addr)
+{
+ ether_addr_copy(mac_addr, wx->mac.perm_addr);
+}
+EXPORT_SYMBOL(wx_get_mac_addr_vf);
+
+int wx_get_fw_version_vf(struct wx *wx)
+{
+ u32 msgbuf[2] = {WX_VF_GET_FW_VERSION};
+ int ret;
+
+ ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
+ ARRAY_SIZE(msgbuf));
+ if (ret)
+ return ret;
+
+ if (msgbuf[0] & WX_VT_MSGTYPE_NACK)
+ return -EINVAL;
+ snprintf(wx->eeprom_id, 32, "0x%08x", msgbuf[1]);
+
+ return ret;
+}
+EXPORT_SYMBOL(wx_get_fw_version_vf);
+
+int wx_set_uc_addr_vf(struct wx *wx, u32 index, u8 *addr)
+{
+ u32 msgbuf[3] = {WX_VF_SET_MACVLAN};
+ u8 *msg_addr = (u8 *)(&msgbuf[1]);
+ int ret;
+
+ /* If index is one then this is the start of a new list and needs
+ * indication to the PF so it can do it's own list management.
+ * If it is zero then that tells the PF to just clear all of
+ * this VF's macvlans and there is no new list.
+ */
+ msgbuf[0] |= index << WX_VT_MSGINFO_SHIFT;
+ if (addr)
+ memcpy(msg_addr, addr, 6);
+ ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
+ ARRAY_SIZE(msgbuf));
+ if (ret)
+ return ret;
+
+ msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
+
+ if (msgbuf[0] == (WX_VF_SET_MACVLAN | WX_VT_MSGTYPE_NACK))
+ return -EINVAL;
+
+ return ret;
+}
+EXPORT_SYMBOL(wx_set_uc_addr_vf);
+
+/**
+ * wx_rlpml_set_vf - Set the maximum receive packet length
+ * @wx: pointer to the HW structure
+ * @max_size: value to assign to max frame size
+ *
+ * Return: returns 0 on success, negative error code on failure
+ **/
+int wx_rlpml_set_vf(struct wx *wx, u16 max_size)
+{
+ u32 msgbuf[2] = {WX_VF_SET_LPE, max_size};
+ int ret;
+
+ ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
+ ARRAY_SIZE(msgbuf));
+ if (ret)
+ return ret;
+ if ((msgbuf[0] & WX_VF_SET_LPE) &&
+ (msgbuf[0] & WX_VT_MSGTYPE_NACK))
+ return -EINVAL;
+
+ return ret;
+}
+EXPORT_SYMBOL(wx_rlpml_set_vf);
+
+/**
+ * wx_negotiate_api_version - Negotiate supported API version
+ * @wx: pointer to the HW structure
+ * @api: integer containing requested API version
+ *
+ * Return: returns 0 on success, negative error code on failure
+ **/
+int wx_negotiate_api_version(struct wx *wx, int api)
+{
+ u32 msgbuf[2] = {WX_VF_API_NEGOTIATE, api};
+ int ret;
+
+ ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
+ ARRAY_SIZE(msgbuf));
+ if (ret)
+ return ret;
+
+ msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
+
+ /* Store value and return 0 on success */
+ if (msgbuf[0] == (WX_VF_API_NEGOTIATE | WX_VT_MSGTYPE_NACK))
+ return -EINVAL;
+ wx->vfinfo->vf_api = api;
+
+ return ret;
+}
+EXPORT_SYMBOL(wx_negotiate_api_version);
+
+int wx_get_queues_vf(struct wx *wx, u32 *num_tcs, u32 *default_tc)
+{
+ u32 msgbuf[5] = {WX_VF_GET_QUEUES};
+ int ret = 0;
+
+ /* do nothing if API doesn't support wx_get_queues */
+ switch (wx->vfinfo->vf_api) {
+ case wx_mbox_api_13:
+ break;
+ default:
+ return 0;
+ }
+
+ /* Fetch queue configuration from the PF */
+ ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
+ ARRAY_SIZE(msgbuf));
+ if (ret)
+ return ret;
+ msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
+
+ /* if we didn't get an ACK there must have been
+ * some sort of mailbox error so we should treat it
+ * as such
+ */
+ if (msgbuf[0] != (WX_VF_GET_QUEUES | WX_VT_MSGTYPE_ACK))
+ return -EINVAL;
+ /* record and validate values from message */
+ wx->mac.max_tx_queues = msgbuf[WX_VF_TX_QUEUES];
+ if (wx->mac.max_tx_queues == 0 ||
+ wx->mac.max_tx_queues > WX_VF_MAX_TX_QUEUES)
+ wx->mac.max_tx_queues = WX_VF_MAX_TX_QUEUES;
+
+ wx->mac.max_rx_queues = msgbuf[WX_VF_RX_QUEUES];
+ if (wx->mac.max_rx_queues == 0 ||
+ wx->mac.max_rx_queues > WX_VF_MAX_RX_QUEUES)
+ wx->mac.max_rx_queues = WX_VF_MAX_RX_QUEUES;
+
+ *num_tcs = msgbuf[WX_VF_TRANS_VLAN];
+ /* in case of unknown state assume we cannot tag frames */
+ if (*num_tcs > wx->mac.max_rx_queues)
+ *num_tcs = 1;
+ *default_tc = msgbuf[WX_VF_DEF_QUEUE];
+ /* default to queue 0 on out-of-bounds queue number */
+ if (*default_tc >= wx->mac.max_tx_queues)
+ *default_tc = 0;
+
+ return ret;
+}
+EXPORT_SYMBOL(wx_get_queues_vf);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.h b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
new file mode 100644
index 000000000000..eb40048f46eb
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _WX_VF_H_
+#define _WX_VF_H_
+
+#define WX_VXSTATUS 0x4
+#define WX_VXCTRL 0x8
+#define WX_VXCTRL_RST BIT(0)
+
+#define WX_VXMRQC 0x78
+#define WX_VXICR 0x100
+#define WX_VXIMS 0x108
+#define WX_VF_IRQ_CLEAR_MASK 7
+#define WX_VF_MAX_TX_QUEUES 4
+#define WX_VF_MAX_RX_QUEUES 4
+#define WX_VXTXDCTL(r) (0x3010 + (0x40 * (r)))
+#define WX_VXRXDCTL(r) (0x1010 + (0x40 * (r)))
+#define WX_VXRXDCTL_ENABLE BIT(0)
+#define WX_VXTXDCTL_FLUSH BIT(26)
+
+#define WX_VXRXDCTL_RSCMAX(f) FIELD_PREP(GENMASK(24, 23), f)
+#define WX_VXRXDCTL_BUFLEN(f) FIELD_PREP(GENMASK(6, 1), f)
+#define WX_VXRXDCTL_BUFSZ(f) FIELD_PREP(GENMASK(11, 8), f)
+#define WX_VXRXDCTL_HDRSZ(f) FIELD_PREP(GENMASK(15, 12), f)
+
+#define WX_VXRXDCTL_RSCMAX_MASK GENMASK(24, 23)
+#define WX_VXRXDCTL_BUFLEN_MASK GENMASK(6, 1)
+#define WX_VXRXDCTL_BUFSZ_MASK GENMASK(11, 8)
+#define WX_VXRXDCTL_HDRSZ_MASK GENMASK(15, 12)
+
+#define wx_conf_size(v, mwidth, uwidth) ({ \
+ typeof(v) _v = (v); \
+ (_v == 2 << (mwidth) ? 0 : _v >> (uwidth)); \
+})
+#define wx_buf_len(v) wx_conf_size(v, 13, 7)
+#define wx_hdr_sz(v) wx_conf_size(v, 10, 6)
+#define wx_buf_sz(v) wx_conf_size(v, 14, 10)
+#define wx_pkt_thresh(v) wx_conf_size(v, 4, 0)
+
+#define WX_RX_HDR_SIZE 256
+#define WX_RX_BUF_SIZE 2048
+
+void wx_start_hw_vf(struct wx *wx);
+void wx_init_hw_vf(struct wx *wx);
+int wx_reset_hw_vf(struct wx *wx);
+void wx_get_mac_addr_vf(struct wx *wx, u8 *mac_addr);
+int wx_stop_adapter_vf(struct wx *wx);
+int wx_get_fw_version_vf(struct wx *wx);
+int wx_set_rar_vf(struct wx *wx, u32 index, u8 *addr, u32 enable_addr);
+int wx_update_mc_addr_list_vf(struct wx *wx, struct net_device *netdev);
+int wx_set_uc_addr_vf(struct wx *wx, u32 index, u8 *addr);
+int wx_rlpml_set_vf(struct wx *wx, u16 max_size);
+int wx_negotiate_api_version(struct wx *wx, int api);
+int wx_get_queues_vf(struct wx *wx, u32 *num_tcs, u32 *default_tc);
+int wx_update_xcast_mode_vf(struct wx *wx, int xcast_mode);
+int wx_get_link_state_vf(struct wx *wx, u16 *link_state);
+int wx_set_vfta_vf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on,
+ bool vlvf_bypass);
+
+#endif /* _WX_VF_H_ */
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH net-next 02/12] net: libwx: add base vf api for vf drivers
2025-06-11 8:35 ` [PATCH net-next 02/12] net: libwx: add base vf api for " Mengyuan Lou
@ 2025-06-18 11:28 ` Michal Swiatkowski
2025-06-20 10:27 ` mengyuanlou
0 siblings, 1 reply; 20+ messages in thread
From: Michal Swiatkowski @ 2025-06-18 11:28 UTC (permalink / raw)
To: Mengyuan Lou
Cc: netdev, kuba, pabeni, horms, andrew+netdev, duanqiangwen,
linglingzhang, jiawenwu
On Wed, Jun 11, 2025 at 04:35:49PM +0800, Mengyuan Lou wrote:
> Implement mbox_write_and_read_ack functions which are
> used to set basic functions like set_mac, get_link.etc
> for vf.
>
> Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
> ---
> drivers/net/ethernet/wangxun/libwx/Makefile | 1 +
> drivers/net/ethernet/wangxun/libwx/wx_hw.c | 2 +-
> drivers/net/ethernet/wangxun/libwx/wx_hw.h | 1 +
> drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 +
> drivers/net/ethernet/wangxun/libwx/wx_vf.c | 521 +++++++++++++++++++
> drivers/net/ethernet/wangxun/libwx/wx_vf.h | 61 +++
> 6 files changed, 586 insertions(+), 1 deletion(-)
> create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_vf.c
> create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_vf.h
>
> diff --git a/drivers/net/ethernet/wangxun/libwx/Makefile b/drivers/net/ethernet/wangxun/libwx/Makefile
> index 9b78b604a94e..ddf0bb921676 100644
> --- a/drivers/net/ethernet/wangxun/libwx/Makefile
> +++ b/drivers/net/ethernet/wangxun/libwx/Makefile
> @@ -5,3 +5,4 @@
> obj-$(CONFIG_LIBWX) += libwx.o
>
> libwx-objs := wx_hw.o wx_lib.o wx_ethtool.o wx_ptp.o wx_mbx.o wx_sriov.o
> +libwx-objs += wx_vf.o
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
> index 0f4be72116b8..82dd76f0326e 100644
> --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
> @@ -1107,7 +1107,7 @@ static int wx_write_uc_addr_list(struct net_device *netdev, int pool)
> * by the MO field of the MCSTCTRL. The MO field is set during initialization
> * to mc_filter_type.
> **/
> -static u32 wx_mta_vector(struct wx *wx, u8 *mc_addr)
> +u32 wx_mta_vector(struct wx *wx, u8 *mc_addr)
> {
> u32 vector = 0;
>
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
> index 26a56cba60b9..718015611da6 100644
> --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.h
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
> @@ -29,6 +29,7 @@ void wx_mac_set_default_filter(struct wx *wx, u8 *addr);
> int wx_add_mac_filter(struct wx *wx, u8 *addr, u16 pool);
> int wx_del_mac_filter(struct wx *wx, u8 *addr, u16 pool);
> void wx_flush_sw_mac_table(struct wx *wx);
> +u32 wx_mta_vector(struct wx *wx, u8 *mc_addr);
> int wx_set_mac(struct net_device *netdev, void *p);
> void wx_disable_rx(struct wx *wx);
> int wx_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
> index f2061c893358..d2d0764792d4 100644
> --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
> @@ -1213,6 +1213,7 @@ struct wx {
>
> void *priv;
> u8 __iomem *hw_addr;
> + u8 __iomem *b4_addr; /* vf only */
> struct pci_dev *pdev;
> struct net_device *netdev;
> struct wx_bus_info bus;
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.c b/drivers/net/ethernet/wangxun/libwx/wx_vf.c
> new file mode 100644
> index 000000000000..a211329fd71a
> --- /dev/null
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.c
> @@ -0,0 +1,521 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
> +
> +#include <linux/etherdevice.h>
> +#include <linux/pci.h>
> +
> +#include "wx_type.h"
> +#include "wx_hw.h"
> +#include "wx_mbx.h"
> +#include "wx_vf.h"
> +
> +static void wx_virt_clr_reg(struct wx *wx)
> +{
> + u32 vfsrrctl;
> + int i;
> +
> + /* VRSRRCTL default values (BSIZEPACKET = 2048, BSIZEHEADER = 256) */
> + vfsrrctl = WX_VXRXDCTL_HDRSZ(wx_hdr_sz(WX_RX_HDR_SIZE));
> + vfsrrctl |= WX_VXRXDCTL_BUFSZ(wx_buf_sz(WX_RX_BUF_SIZE));
> +
> + /* clear all rxd ctl */
> + for (i = 0; i < 7; i++) {
Define for 7 will be usefull.
> + wr32m(wx, WX_VXRXDCTL(i),
> + WX_VXRXDCTL_HDRSZ_MASK | WX_VXRXDCTL_BUFSZ_MASK,
> + vfsrrctl);
> + }
Drop {, } as it is one line.
> +
> + rd32(wx, WX_VXSTATUS);
> +}
> +
> +/**
> + * wx_start_hw_vf - Prepare hardware for Tx/Rx
> + * @wx: 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
> + **/
> +void wx_start_hw_vf(struct wx *wx)
> +{
> + /* Clear wx stopped flag */
> + wx->adapter_stopped = false;
From the description it should do a lot more. Maybe move the description
to the patch where the function is filled.
> +}
> +EXPORT_SYMBOL(wx_start_hw_vf);
> +
> +/**
> + * wx_init_hw_vf - virtual function hardware initialization
> + * @wx: pointer to hardware structure
> + *
> + * Initialize the hardware by resetting the hardware and then starting
> + * the hardware
Now it is just setting the flag and reading MAC address.
> + **/
> +void wx_init_hw_vf(struct wx *wx)
> +{
> + wx_start_hw_vf(wx);
> + wx_get_mac_addr_vf(wx, wx->mac.addr);
> +}
> +EXPORT_SYMBOL(wx_init_hw_vf);
> +
> +static int wx_mbx_write_and_read_reply(struct wx *wx, u32 *req_buf,
> + u32 *resp_buf, u16 size)
> +{
> + int ret;
> +
> + ret = wx_write_posted_mbx(wx, req_buf, size);
> + if (unlikely(ret))
Why unlikely? It isn't usuall to add in error handling outside hot path.
> + return ret;
> +
> + return wx_read_posted_mbx(wx, resp_buf, size);
> +}
> +
> +/**
> + * wx_reset_hw_vf - Performs hardware reset
> + * @wx: pointer to hardware structure
> + *
> + * Resets the hardware by resetting the transmit and receive units, masks and
> + * clears all interrupts.
> + *
> + * Return: returns 0 on success, negative error code on failure
> + **/
> +int wx_reset_hw_vf(struct wx *wx)
> +{
> + struct wx_mbx_info *mbx = &wx->mbx;
> + u32 msgbuf[4] = {WX_VF_RESET};
> + u8 *addr = (u8 *)(&msgbuf[1]);
> + u32 b4_buf[16] = {0};
> + u32 timeout = 200;
> + int ret;
> + u32 i;
> +
> + /* Call wx stop to disable tx/rx and clear interrupts */
> + wx_stop_adapter_vf(wx);
> +
> + /* reset the api version */
> + wx->vfinfo->vf_api = wx_mbox_api_null;
> +
> + /* backup msix vectors */
> + if (wx->b4_addr) {
Where this address is being set? I wonder if 0 is always invalid (as 0
sounds like valid address) and also if it shouldn't return error in case
wx->b4_addr is invalid.
> + for (i = 0; i < 16; i++)
> + b4_buf[i] = readl(wx->b4_addr + i * 4);
> + }
> +
> + wr32m(wx, WX_VXCTRL, WX_VXCTRL_RST, WX_VXCTRL_RST);
> + rd32(wx, WX_VXSTATUS);
> +
> + /* we cannot reset while the RSTI / RSTD bits are asserted */
> + while (!wx_check_for_rst_vf(wx) && timeout) {
> + timeout--;
> + udelay(5);
> + }
> +
> + /* restore msix vectors */
> + if (wx->b4_addr) {
> + for (i = 0; i < 16; i++)
> + writel(b4_buf[i], wx->b4_addr + i * 4);
> + }
> +
> + /* amlite: bme */
> +#define WX_VX_PF_BME 0x4B8
In my opinion it should go to the header where there are other
register definitions.
> + if (wx->mac.type == wx_mac_aml || wx->mac.type == wx_mac_aml40)
> + wr32(wx, WX_VX_PF_BME, BIT(0));
BIT(0) can be also described there.
> +
> + if (!timeout)
> + return -EBUSY;
> +
> + /* Reset VF registers to initial values */
> + wx_virt_clr_reg(wx);
> +
> + /* mailbox timeout can now become active */
> + mbx->timeout = 2000;
> +
> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
> + ARRAY_SIZE(msgbuf));
> + if (ret)
> + return ret;
> +
> + if (msgbuf[0] != (WX_VF_RESET | WX_VT_MSGTYPE_ACK) &&
> + msgbuf[0] != (WX_VF_RESET | WX_VT_MSGTYPE_NACK))
> + return -EINVAL;
> +
> + if (msgbuf[0] == (WX_VF_RESET | WX_VT_MSGTYPE_ACK))
> + ether_addr_copy(wx->mac.perm_addr, addr);
> +
> + wx->mac.mc_filter_type = msgbuf[3];
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(wx_reset_hw_vf);
> +
> +/**
> + * wx_stop_adapter_vf - Generic stop Tx/Rx units
> + * @wx: pointer to hardware structure
> + *
> + * Sets the adapter_stopped flag within wx struct. Clears interrupts,
> + * disables transmit and receive units. The adapter_stopped flag is used by
> + * the shared code and drivers to determine if the wx is in a stopped
> + * state and should not touch the hardware.
> + *
> + * Return: returns 0 on success, negative error code on failure
> + **/
> +int wx_stop_adapter_vf(struct wx *wx)
> +{
> + u32 reg_val;
> + u16 i;
> +
> + wx->adapter_stopped = true;
> +
> + /* Clear interrupt mask to stop from interrupts being generated */
> + wr32(wx, WX_VXIMS, WX_VF_IRQ_CLEAR_MASK);
> +
> + /* Clear any pending interrupts, flush previous writes */
> + wr32(wx, WX_VXICR, U32_MAX);
> +
> + /* Disable the transmit unit. Each queue must be disabled. */
> + for (i = 0; i < wx->mac.max_tx_queues; i++)
> + wr32(wx, WX_VXTXDCTL(i), WX_VXTXDCTL_FLUSH);
> +
> + /* Disable the receive unit by stopping each queue */
> + for (i = 0; i < wx->mac.max_rx_queues; i++) {
> + reg_val = rd32(wx, WX_VXRXDCTL(i));
> + reg_val &= ~WX_VXRXDCTL_ENABLE;
> + wr32(wx, WX_VXRXDCTL(i), reg_val);
> + }
> + /* Clear packet split and pool config */
> + wr32(wx, WX_VXMRQC, 0);
> +
> + /* flush all queues disables */
> + rd32(wx, WX_VXSTATUS);
> +
> + return 0;
Always returns 0, should be void.
> +}
> +EXPORT_SYMBOL(wx_stop_adapter_vf);
> +
> +/**
> + * wx_set_rar_vf - set device MAC address
> + * @wx: pointer to hardware structure
> + * @index: Receive address register to write
> + * @addr: Address to put into receive address register
> + * @enable_addr: set flag that address is active
> + *
> + * Return: returns 0 on success, negative error code on failure
> + **/
> +int wx_set_rar_vf(struct wx *wx, u32 index, u8 *addr, u32 enable_addr)
> +{
> + u32 msgbuf[3] = {WX_VF_SET_MAC_ADDR};
> + u8 *msg_addr = (u8 *)(&msgbuf[1]);
> + int ret;
> +
> + memcpy(msg_addr, addr, ETH_ALEN);
> +
> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
> + ARRAY_SIZE(msgbuf));
> + if (ret)
> + return ret;
> + msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
> +
> + /* if nacked the address was rejected, use "perm_addr" */
> + if (msgbuf[0] == (WX_VF_SET_MAC_ADDR | WX_VT_MSGTYPE_NACK)) {
> + wx_get_mac_addr_vf(wx, wx->mac.addr);
> + return -EINVAL;
> + }
> +
> + return ret;
nit, ret is always 0 here, so return 0; should be more readable.
> +}
> +EXPORT_SYMBOL(wx_set_rar_vf);
> +
> +/**
> + * wx_update_mc_addr_list_vf - Update Multicast addresses
> + * @wx: pointer to the HW structure
> + * @netdev: pointer to the net device structure
> + *
> + * Updates the Multicast Table Array.
> + *
> + * Return: returns 0 on success, negative error code on failure
> + **/
> +int wx_update_mc_addr_list_vf(struct wx *wx, struct net_device *netdev)
> +{
> + u32 msgbuf[WX_VXMAILBOX_SIZE] = {0};
WX_VXMAILBOX_SIZE is 15, but 4B is opcode. There is 14 * 4B for payload
= 56B, so it is 28 16 bit words, not 30, am I correct? Please add it as
define instead of just the number.
> + u16 *vector_l = (u16 *)&msgbuf[1];
> + struct netdev_hw_addr *ha;
> + u32 cnt, i;
> +
> + /* Each entry in the list uses 1 16 bit word. We have 30
> + * 16 bit words available in our HW msgbuf buffer (minus 1 for the
> + * msgbuf type). That's 30 hash values if we pack 'em right. If
> + * there are more than 30 MC addresses to add then punt the
> + * extras for now and then add code to handle more than 30 later.
> + * It would be unusual for a server to request that many multi-cast
> + * addresses except for in large enterprise network environments.
> + */
I think you should handle more than 30 here, instead of writting a
comment about adding it later. It is just about sending anoither
command, yes?
}
> +
> + cnt = netdev_mc_count(netdev);
> + if (cnt > 30)
> + cnt = 30;
> + msgbuf[0] = WX_VF_SET_MULTICAST;
> + msgbuf[0] |= cnt << WX_VT_MSGINFO_SHIFT;
> +
> + i = 0;
> + netdev_for_each_mc_addr(ha, netdev) {
> + if (i == cnt)
> + break;
> + if (is_link_local_ether_addr(ha->addr))
> + continue;
> +
> + vector_l[i++] = wx_mta_vector(wx, ha->addr);
What about endianess, don't you need a __cpu_to_le16/be16 conversion?
> + }
> +
> + return wx_write_posted_mbx(wx, msgbuf, WX_VXMAILBOX_SIZE);
Shouldn't the size be cut to the real number of address?
> +}
> +EXPORT_SYMBOL(wx_update_mc_addr_list_vf);
> +
> +/**
> + * wx_update_xcast_mode_vf - Update Multicast mode
> + * @wx: pointer to the HW structure
> + * @xcast_mode: new multicast mode
> + *
> + * Updates the Multicast Mode of VF.
> + *
> + * Return: returns 0 on success, negative error code on failure
> + **/
> +int wx_update_xcast_mode_vf(struct wx *wx, int xcast_mode)
> +{
> + u32 msgbuf[2] = {WX_VF_UPDATE_XCAST_MODE, xcast_mode};
> + int ret = 0;
> +
> + switch (wx->vfinfo->vf_api) {
> + case wx_mbox_api_13:
> + break;
> + default:
> + return -EINVAL;
> + }
if (api != vx_mbox_api_13)
return -EINVAL;
> +
> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
> + ARRAY_SIZE(msgbuf));
> + if (ret)
> + return ret;
> +
> + msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
> + if (msgbuf[0] == (WX_VF_UPDATE_XCAST_MODE | WX_VT_MSGTYPE_NACK))
> + return -EINVAL;
> +
> + return ret;
return 0;
> +}
> +EXPORT_SYMBOL(wx_update_xcast_mode_vf);
> +
> +/**
> + * wx_get_link_state_vf - Get VF link state from PF
> + * @wx: pointer to the HW structure
> + * @link_state: link state storage
> + *
> + * Return: return state of the operation error or success.
> + **/
> +int wx_get_link_state_vf(struct wx *wx, u16 *link_state)
> +{
> + u32 msgbuf[2] = {WX_VF_GET_LINK_STATE};
> + int ret = 0;
> +
> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
> + ARRAY_SIZE(msgbuf));
> + if (ret)
> + return ret;
> +
> + if (msgbuf[0] & WX_VT_MSGTYPE_NACK)
> + return -EINVAL;
> +
> + *link_state = msgbuf[1];
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(wx_get_link_state_vf);
> +
> +/**
> + * wx_set_vfta_vf - Set/Unset vlan filter table address
> + * @wx: pointer to the HW structure
> + * @vlan: 12 bit VLAN ID
> + * @vind: unused by VF drivers
> + * @vlan_on: if true then set bit, else clear bit
> + * @vlvf_bypass: boolean flag indicating updating default pool is okay
> + *
> + * Turn on/off specified VLAN in the VLAN filter table.
> + *
> + * Return: returns 0 on success, negative error code on failure
> + **/
> +int wx_set_vfta_vf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on,
> + bool vlvf_bypass)
> +{
> + u32 msgbuf[2] = {WX_VF_SET_VLAN, vlan};
> + bool vlan_offload = false;
> + int ret = 0;
> +
> + /* Setting the 8 bit field MSG INFO to TRUE indicates "add" */
> + msgbuf[0] |= vlan_on << WX_VT_MSGINFO_SHIFT;
> + /* if vf vlan offload is disabled, allow to create vlan under pf port vlan */
> + msgbuf[0] |= BIT(vlan_offload);
> +
> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
> + ARRAY_SIZE(msgbuf));
> + if (ret)
> + return ret;
> +
> + if (msgbuf[0] & WX_VT_MSGTYPE_ACK)
> + return 0;
> +
> + return msgbuf[0] & WX_VT_MSGTYPE_NACK;
This will be positive on fail. Reword the kdoc.
Is it even possible to not have ACK and not have NACK?
Maybe return -EIO; here is enough? Or even better return error if no ACK
and return 0; at the end.
> +}
> +EXPORT_SYMBOL(wx_set_vfta_vf);
> +
> +void wx_get_mac_addr_vf(struct wx *wx, u8 *mac_addr)
> +{
> + ether_addr_copy(mac_addr, wx->mac.perm_addr);
> +}
> +EXPORT_SYMBOL(wx_get_mac_addr_vf);
> +
> +int wx_get_fw_version_vf(struct wx *wx)
> +{
> + u32 msgbuf[2] = {WX_VF_GET_FW_VERSION};
> + int ret;
> +
> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
> + ARRAY_SIZE(msgbuf));
> + if (ret)
> + return ret;
> +
> + if (msgbuf[0] & WX_VT_MSGTYPE_NACK)
> + return -EINVAL;
> + snprintf(wx->eeprom_id, 32, "0x%08x", msgbuf[1]);
> +
> + return ret;
It will be great to stick to one style of checking if it is possible.
Here is the best, if nack returns error, just return 0 at the end, as
ret is always 0 here.
> +}
> +EXPORT_SYMBOL(wx_get_fw_version_vf);
> +
> +int wx_set_uc_addr_vf(struct wx *wx, u32 index, u8 *addr)
> +{
> + u32 msgbuf[3] = {WX_VF_SET_MACVLAN};
> + u8 *msg_addr = (u8 *)(&msgbuf[1]);
> + int ret;
> +
> + /* If index is one then this is the start of a new list and needs
> + * indication to the PF so it can do it's own list management.
> + * If it is zero then that tells the PF to just clear all of
> + * this VF's macvlans and there is no new list.
> + */
> + msgbuf[0] |= index << WX_VT_MSGINFO_SHIFT;
> + if (addr)
> + memcpy(msg_addr, addr, 6);
> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
> + ARRAY_SIZE(msgbuf));
> + if (ret)
> + return ret;
> +
> + msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
> +
> + if (msgbuf[0] == (WX_VF_SET_MACVLAN | WX_VT_MSGTYPE_NACK))
> + return -EINVAL;
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(wx_set_uc_addr_vf);
> +
> +/**
> + * wx_rlpml_set_vf - Set the maximum receive packet length
> + * @wx: pointer to the HW structure
> + * @max_size: value to assign to max frame size
> + *
> + * Return: returns 0 on success, negative error code on failure
> + **/
> +int wx_rlpml_set_vf(struct wx *wx, u16 max_size)
> +{
> + u32 msgbuf[2] = {WX_VF_SET_LPE, max_size};
> + int ret;
> +
> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
> + ARRAY_SIZE(msgbuf));
> + if (ret)
> + return ret;
> + if ((msgbuf[0] & WX_VF_SET_LPE) &&
> + (msgbuf[0] & WX_VT_MSGTYPE_NACK))
> + return -EINVAL;
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(wx_rlpml_set_vf);
> +
> +/**
> + * wx_negotiate_api_version - Negotiate supported API version
> + * @wx: pointer to the HW structure
> + * @api: integer containing requested API version
> + *
> + * Return: returns 0 on success, negative error code on failure
> + **/
> +int wx_negotiate_api_version(struct wx *wx, int api)
> +{
> + u32 msgbuf[2] = {WX_VF_API_NEGOTIATE, api};
> + int ret;
> +
> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
> + ARRAY_SIZE(msgbuf));
> + if (ret)
> + return ret;
> +
> + msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
> +
> + /* Store value and return 0 on success */
> + if (msgbuf[0] == (WX_VF_API_NEGOTIATE | WX_VT_MSGTYPE_NACK))
> + return -EINVAL;
> + wx->vfinfo->vf_api = api;
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(wx_negotiate_api_version);
> +
> +int wx_get_queues_vf(struct wx *wx, u32 *num_tcs, u32 *default_tc)
> +{
> + u32 msgbuf[5] = {WX_VF_GET_QUEUES};
> + int ret = 0;
int ret; is enough.
> +
> + /* do nothing if API doesn't support wx_get_queues */
> + switch (wx->vfinfo->vf_api) {
> + case wx_mbox_api_13:
> + break;
> + default:
> + return 0;
if() instead
> + }
> +
> + /* Fetch queue configuration from the PF */
> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
> + ARRAY_SIZE(msgbuf));
> + if (ret)
> + return ret;
> + msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
> +
> + /* if we didn't get an ACK there must have been
> + * some sort of mailbox error so we should treat it
> + * as such
> + */
> + if (msgbuf[0] != (WX_VF_GET_QUEUES | WX_VT_MSGTYPE_ACK))
> + return -EINVAL;
> + /* record and validate values from message */
> + wx->mac.max_tx_queues = msgbuf[WX_VF_TX_QUEUES];
> + if (wx->mac.max_tx_queues == 0 ||
> + wx->mac.max_tx_queues > WX_VF_MAX_TX_QUEUES)
> + wx->mac.max_tx_queues = WX_VF_MAX_TX_QUEUES;
> +
> + wx->mac.max_rx_queues = msgbuf[WX_VF_RX_QUEUES];
> + if (wx->mac.max_rx_queues == 0 ||
> + wx->mac.max_rx_queues > WX_VF_MAX_RX_QUEUES)
> + wx->mac.max_rx_queues = WX_VF_MAX_RX_QUEUES;
> +
> + *num_tcs = msgbuf[WX_VF_TRANS_VLAN];
> + /* in case of unknown state assume we cannot tag frames */
> + if (*num_tcs > wx->mac.max_rx_queues)
> + *num_tcs = 1;
> + *default_tc = msgbuf[WX_VF_DEF_QUEUE];
> + /* default to queue 0 on out-of-bounds queue number */
> + if (*default_tc >= wx->mac.max_tx_queues)
> + *default_tc = 0;
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(wx_get_queues_vf);
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.h b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
> new file mode 100644
> index 000000000000..eb40048f46eb
> --- /dev/null
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
> @@ -0,0 +1,61 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
> +
> +#ifndef _WX_VF_H_
> +#define _WX_VF_H_
> +
> +#define WX_VXSTATUS 0x4
> +#define WX_VXCTRL 0x8
> +#define WX_VXCTRL_RST BIT(0)
> +
> +#define WX_VXMRQC 0x78
> +#define WX_VXICR 0x100
> +#define WX_VXIMS 0x108
> +#define WX_VF_IRQ_CLEAR_MASK 7
> +#define WX_VF_MAX_TX_QUEUES 4
> +#define WX_VF_MAX_RX_QUEUES 4
> +#define WX_VXTXDCTL(r) (0x3010 + (0x40 * (r)))
> +#define WX_VXRXDCTL(r) (0x1010 + (0x40 * (r)))
> +#define WX_VXRXDCTL_ENABLE BIT(0)
> +#define WX_VXTXDCTL_FLUSH BIT(26)
> +
> +#define WX_VXRXDCTL_RSCMAX(f) FIELD_PREP(GENMASK(24, 23), f)
> +#define WX_VXRXDCTL_BUFLEN(f) FIELD_PREP(GENMASK(6, 1), f)
> +#define WX_VXRXDCTL_BUFSZ(f) FIELD_PREP(GENMASK(11, 8), f)
> +#define WX_VXRXDCTL_HDRSZ(f) FIELD_PREP(GENMASK(15, 12), f)
> +
> +#define WX_VXRXDCTL_RSCMAX_MASK GENMASK(24, 23)
> +#define WX_VXRXDCTL_BUFLEN_MASK GENMASK(6, 1)
> +#define WX_VXRXDCTL_BUFSZ_MASK GENMASK(11, 8)
> +#define WX_VXRXDCTL_HDRSZ_MASK GENMASK(15, 12)
> +
> +#define wx_conf_size(v, mwidth, uwidth) ({ \
> + typeof(v) _v = (v); \
> + (_v == 2 << (mwidth) ? 0 : _v >> (uwidth)); \
> +})
> +#define wx_buf_len(v) wx_conf_size(v, 13, 7)
> +#define wx_hdr_sz(v) wx_conf_size(v, 10, 6)
> +#define wx_buf_sz(v) wx_conf_size(v, 14, 10)
> +#define wx_pkt_thresh(v) wx_conf_size(v, 4, 0)
> +
> +#define WX_RX_HDR_SIZE 256
> +#define WX_RX_BUF_SIZE 2048
> +
> +void wx_start_hw_vf(struct wx *wx);
> +void wx_init_hw_vf(struct wx *wx);
> +int wx_reset_hw_vf(struct wx *wx);
> +void wx_get_mac_addr_vf(struct wx *wx, u8 *mac_addr);
> +int wx_stop_adapter_vf(struct wx *wx);
> +int wx_get_fw_version_vf(struct wx *wx);
> +int wx_set_rar_vf(struct wx *wx, u32 index, u8 *addr, u32 enable_addr);
> +int wx_update_mc_addr_list_vf(struct wx *wx, struct net_device *netdev);
> +int wx_set_uc_addr_vf(struct wx *wx, u32 index, u8 *addr);
> +int wx_rlpml_set_vf(struct wx *wx, u16 max_size);
> +int wx_negotiate_api_version(struct wx *wx, int api);
> +int wx_get_queues_vf(struct wx *wx, u32 *num_tcs, u32 *default_tc);
> +int wx_update_xcast_mode_vf(struct wx *wx, int xcast_mode);
> +int wx_get_link_state_vf(struct wx *wx, u16 *link_state);
> +int wx_set_vfta_vf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on,
> + bool vlvf_bypass);
> +
> +#endif /* _WX_VF_H_ */
In general it will be great to define structures for each command that
is used in VF communication. Filling it should be also easier.
Thanks
> --
> 2.30.1
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH net-next 02/12] net: libwx: add base vf api for vf drivers
2025-06-18 11:28 ` Michal Swiatkowski
@ 2025-06-20 10:27 ` mengyuanlou
0 siblings, 0 replies; 20+ messages in thread
From: mengyuanlou @ 2025-06-20 10:27 UTC (permalink / raw)
To: Michal Swiatkowski
Cc: netdev, kuba, pabeni, horms, andrew+netdev, duanqiangwen,
linglingzhang, jiawenwu
> 2025年6月18日 19:28,Michal Swiatkowski <michal.swiatkowski@linux.intel.com> 写道:
>
> On Wed, Jun 11, 2025 at 04:35:49PM +0800, Mengyuan Lou wrote:
>> Implement mbox_write_and_read_ack functions which are
>> used to set basic functions like set_mac, get_link.etc
>> for vf.
>>
>> Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
>> ---
>> drivers/net/ethernet/wangxun/libwx/Makefile | 1 +
>> drivers/net/ethernet/wangxun/libwx/wx_hw.c | 2 +-
>> drivers/net/ethernet/wangxun/libwx/wx_hw.h | 1 +
>> drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 +
>> drivers/net/ethernet/wangxun/libwx/wx_vf.c | 521 +++++++++++++++++++
>> drivers/net/ethernet/wangxun/libwx/wx_vf.h | 61 +++
>> 6 files changed, 586 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_vf.c
>> create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_vf.h
>>
>> diff --git a/drivers/net/ethernet/wangxun/libwx/Makefile b/drivers/net/ethernet/wangxun/libwx/Makefile
>> index 9b78b604a94e..ddf0bb921676 100644
>> --- a/drivers/net/ethernet/wangxun/libwx/Makefile
>> +++ b/drivers/net/ethernet/wangxun/libwx/Makefile
>> @@ -5,3 +5,4 @@
>> obj-$(CONFIG_LIBWX) += libwx.o
>>
>> libwx-objs := wx_hw.o wx_lib.o wx_ethtool.o wx_ptp.o wx_mbx.o wx_sriov.o
>> +libwx-objs += wx_vf.o
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
>> index 0f4be72116b8..82dd76f0326e 100644
>> --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
>> @@ -1107,7 +1107,7 @@ static int wx_write_uc_addr_list(struct net_device *netdev, int pool)
>> * by the MO field of the MCSTCTRL. The MO field is set during initialization
>> * to mc_filter_type.
>> **/
>> -static u32 wx_mta_vector(struct wx *wx, u8 *mc_addr)
>> +u32 wx_mta_vector(struct wx *wx, u8 *mc_addr)
>> {
>> u32 vector = 0;
>>
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
>> index 26a56cba60b9..718015611da6 100644
>> --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.h
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
>> @@ -29,6 +29,7 @@ void wx_mac_set_default_filter(struct wx *wx, u8 *addr);
>> int wx_add_mac_filter(struct wx *wx, u8 *addr, u16 pool);
>> int wx_del_mac_filter(struct wx *wx, u8 *addr, u16 pool);
>> void wx_flush_sw_mac_table(struct wx *wx);
>> +u32 wx_mta_vector(struct wx *wx, u8 *mc_addr);
>> int wx_set_mac(struct net_device *netdev, void *p);
>> void wx_disable_rx(struct wx *wx);
>> int wx_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
>> index f2061c893358..d2d0764792d4 100644
>> --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
>> @@ -1213,6 +1213,7 @@ struct wx {
>>
>> void *priv;
>> u8 __iomem *hw_addr;
>> + u8 __iomem *b4_addr; /* vf only */
>> struct pci_dev *pdev;
>> struct net_device *netdev;
>> struct wx_bus_info bus;
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.c b/drivers/net/ethernet/wangxun/libwx/wx_vf.c
>> new file mode 100644
>> index 000000000000..a211329fd71a
>> --- /dev/null
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.c
>> @@ -0,0 +1,521 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
>> +
>> +#include <linux/etherdevice.h>
>> +#include <linux/pci.h>
>> +
>> +#include "wx_type.h"
>> +#include "wx_hw.h"
>> +#include "wx_mbx.h"
>> +#include "wx_vf.h"
>> +
>> +static void wx_virt_clr_reg(struct wx *wx)
>> +{
>> + u32 vfsrrctl;
>> + int i;
>> +
>> + /* VRSRRCTL default values (BSIZEPACKET = 2048, BSIZEHEADER = 256) */
>> + vfsrrctl = WX_VXRXDCTL_HDRSZ(wx_hdr_sz(WX_RX_HDR_SIZE));
>> + vfsrrctl |= WX_VXRXDCTL_BUFSZ(wx_buf_sz(WX_RX_BUF_SIZE));
>> +
>> + /* clear all rxd ctl */
>> + for (i = 0; i < 7; i++) {
>
> Define for 7 will be usefull.
>
>> + wr32m(wx, WX_VXRXDCTL(i),
>> + WX_VXRXDCTL_HDRSZ_MASK | WX_VXRXDCTL_BUFSZ_MASK,
>> + vfsrrctl);
>> + }
>
> Drop {, } as it is one line.
>
>> +
>> + rd32(wx, WX_VXSTATUS);
>> +}
>> +
>> +/**
>> + * wx_start_hw_vf - Prepare hardware for Tx/Rx
>> + * @wx: 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
>> + **/
>> +void wx_start_hw_vf(struct wx *wx)
>> +{
>> + /* Clear wx stopped flag */
>> + wx->adapter_stopped = false;
>
> From the description it should do a lot more. Maybe move the description
> to the patch where the function is filled.
>
>> +}
>> +EXPORT_SYMBOL(wx_start_hw_vf);
>> +
>> +/**
>> + * wx_init_hw_vf - virtual function hardware initialization
>> + * @wx: pointer to hardware structure
>> + *
>> + * Initialize the hardware by resetting the hardware and then starting
>> + * the hardware
>
> Now it is just setting the flag and reading MAC address.
>
>> + **/
>> +void wx_init_hw_vf(struct wx *wx)
>> +{
>> + wx_start_hw_vf(wx);
>> + wx_get_mac_addr_vf(wx, wx->mac.addr);
>> +}
>> +EXPORT_SYMBOL(wx_init_hw_vf);
>> +
>> +static int wx_mbx_write_and_read_reply(struct wx *wx, u32 *req_buf,
>> + u32 *resp_buf, u16 size)
>> +{
>> + int ret;
>> +
>> + ret = wx_write_posted_mbx(wx, req_buf, size);
>> + if (unlikely(ret))
>
> Why unlikely? It isn't usuall to add in error handling outside hot path.
>
>> + return ret;
>> +
>> + return wx_read_posted_mbx(wx, resp_buf, size);
>> +}
>> +
>> +/**
>> + * wx_reset_hw_vf - Performs hardware reset
>> + * @wx: pointer to hardware structure
>> + *
>> + * Resets the hardware by resetting the transmit and receive units, masks and
>> + * clears all interrupts.
>> + *
>> + * Return: returns 0 on success, negative error code on failure
>> + **/
>> +int wx_reset_hw_vf(struct wx *wx)
>> +{
>> + struct wx_mbx_info *mbx = &wx->mbx;
>> + u32 msgbuf[4] = {WX_VF_RESET};
>> + u8 *addr = (u8 *)(&msgbuf[1]);
>> + u32 b4_buf[16] = {0};
>> + u32 timeout = 200;
>> + int ret;
>> + u32 i;
>> +
>> + /* Call wx stop to disable tx/rx and clear interrupts */
>> + wx_stop_adapter_vf(wx);
>> +
>> + /* reset the api version */
>> + wx->vfinfo->vf_api = wx_mbox_api_null;
>> +
>> + /* backup msix vectors */
>> + if (wx->b4_addr) {
>
> Where this address is being set? I wonder if 0 is always invalid (as 0
> sounds like valid address) and also if it shouldn't return error in case
> wx->b4_addr is invalid.
It is inited in probe.
Because there are two different macs, one of them requires manual saving of the value of bar4.
Another one is unnecessary.
>
>> + for (i = 0; i < 16; i++)
>> + b4_buf[i] = readl(wx->b4_addr + i * 4);
>> + }
>> +
>> + wr32m(wx, WX_VXCTRL, WX_VXCTRL_RST, WX_VXCTRL_RST);
>> + rd32(wx, WX_VXSTATUS);
>> +
>> + /* we cannot reset while the RSTI / RSTD bits are asserted */
>> + while (!wx_check_for_rst_vf(wx) && timeout) {
>> + timeout--;
>> + udelay(5);
>> + }
>> +
>> + /* restore msix vectors */
>> + if (wx->b4_addr) {
>> + for (i = 0; i < 16; i++)
>> + writel(b4_buf[i], wx->b4_addr + i * 4);
>> + }
>> +
>> + /* amlite: bme */
>> +#define WX_VX_PF_BME 0x4B8
>
> In my opinion it should go to the header where there are other
> register definitions.
>
>> + if (wx->mac.type == wx_mac_aml || wx->mac.type == wx_mac_aml40)
>> + wr32(wx, WX_VX_PF_BME, BIT(0));
>
> BIT(0) can be also described there.
>
>> +
>> + if (!timeout)
>> + return -EBUSY;
>> +
>> + /* Reset VF registers to initial values */
>> + wx_virt_clr_reg(wx);
>> +
>> + /* mailbox timeout can now become active */
>> + mbx->timeout = 2000;
>> +
>> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
>> + ARRAY_SIZE(msgbuf));
>> + if (ret)
>> + return ret;
>> +
>> + if (msgbuf[0] != (WX_VF_RESET | WX_VT_MSGTYPE_ACK) &&
>> + msgbuf[0] != (WX_VF_RESET | WX_VT_MSGTYPE_NACK))
>> + return -EINVAL;
>> +
>> + if (msgbuf[0] == (WX_VF_RESET | WX_VT_MSGTYPE_ACK))
>> + ether_addr_copy(wx->mac.perm_addr, addr);
>> +
>> + wx->mac.mc_filter_type = msgbuf[3];
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(wx_reset_hw_vf);
>> +
>> +/**
>> + * wx_stop_adapter_vf - Generic stop Tx/Rx units
>> + * @wx: pointer to hardware structure
>> + *
>> + * Sets the adapter_stopped flag within wx struct. Clears interrupts,
>> + * disables transmit and receive units. The adapter_stopped flag is used by
>> + * the shared code and drivers to determine if the wx is in a stopped
>> + * state and should not touch the hardware.
>> + *
>> + * Return: returns 0 on success, negative error code on failure
>> + **/
>> +int wx_stop_adapter_vf(struct wx *wx)
>> +{
>> + u32 reg_val;
>> + u16 i;
>> +
>> + wx->adapter_stopped = true;
>> +
>> + /* Clear interrupt mask to stop from interrupts being generated */
>> + wr32(wx, WX_VXIMS, WX_VF_IRQ_CLEAR_MASK);
>> +
>> + /* Clear any pending interrupts, flush previous writes */
>> + wr32(wx, WX_VXICR, U32_MAX);
>> +
>> + /* Disable the transmit unit. Each queue must be disabled. */
>> + for (i = 0; i < wx->mac.max_tx_queues; i++)
>> + wr32(wx, WX_VXTXDCTL(i), WX_VXTXDCTL_FLUSH);
>> +
>> + /* Disable the receive unit by stopping each queue */
>> + for (i = 0; i < wx->mac.max_rx_queues; i++) {
>> + reg_val = rd32(wx, WX_VXRXDCTL(i));
>> + reg_val &= ~WX_VXRXDCTL_ENABLE;
>> + wr32(wx, WX_VXRXDCTL(i), reg_val);
>> + }
>> + /* Clear packet split and pool config */
>> + wr32(wx, WX_VXMRQC, 0);
>> +
>> + /* flush all queues disables */
>> + rd32(wx, WX_VXSTATUS);
>> +
>> + return 0;
>
> Always returns 0, should be void.
>
>> +}
>> +EXPORT_SYMBOL(wx_stop_adapter_vf);
>> +
>> +/**
>> + * wx_set_rar_vf - set device MAC address
>> + * @wx: pointer to hardware structure
>> + * @index: Receive address register to write
>> + * @addr: Address to put into receive address register
>> + * @enable_addr: set flag that address is active
>> + *
>> + * Return: returns 0 on success, negative error code on failure
>> + **/
>> +int wx_set_rar_vf(struct wx *wx, u32 index, u8 *addr, u32 enable_addr)
>> +{
>> + u32 msgbuf[3] = {WX_VF_SET_MAC_ADDR};
>> + u8 *msg_addr = (u8 *)(&msgbuf[1]);
>> + int ret;
>> +
>> + memcpy(msg_addr, addr, ETH_ALEN);
>> +
>> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
>> + ARRAY_SIZE(msgbuf));
>> + if (ret)
>> + return ret;
>> + msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
>> +
>> + /* if nacked the address was rejected, use "perm_addr" */
>> + if (msgbuf[0] == (WX_VF_SET_MAC_ADDR | WX_VT_MSGTYPE_NACK)) {
>> + wx_get_mac_addr_vf(wx, wx->mac.addr);
>> + return -EINVAL;
>> + }
>> +
>> + return ret;
>
> nit, ret is always 0 here, so return 0; should be more readable.
>
>> +}
>> +EXPORT_SYMBOL(wx_set_rar_vf);
>> +
>> +/**
>> + * wx_update_mc_addr_list_vf - Update Multicast addresses
>> + * @wx: pointer to the HW structure
>> + * @netdev: pointer to the net device structure
>> + *
>> + * Updates the Multicast Table Array.
>> + *
>> + * Return: returns 0 on success, negative error code on failure
>> + **/
>> +int wx_update_mc_addr_list_vf(struct wx *wx, struct net_device *netdev)
>> +{
>> + u32 msgbuf[WX_VXMAILBOX_SIZE] = {0};
>
> WX_VXMAILBOX_SIZE is 15, but 4B is opcode. There is 14 * 4B for payload
> = 56B, so it is 28 16 bit words, not 30, am I correct? Please add it as
> define instead of just the number.
I check the spec, find the hw size is 16. And last 4B is reserve.
>
>> + u16 *vector_l = (u16 *)&msgbuf[1];
>> + struct netdev_hw_addr *ha;
>> + u32 cnt, i;
>> +
>> + /* Each entry in the list uses 1 16 bit word. We have 30
>> + * 16 bit words available in our HW msgbuf buffer (minus 1 for the
>> + * msgbuf type). That's 30 hash values if we pack 'em right. If
>> + * there are more than 30 MC addresses to add then punt the
>> + * extras for now and then add code to handle more than 30 later.
>> + * It would be unusual for a server to request that many multi-cast
>> + * addresses except for in large enterprise network environments.
>> + */
>
> I think you should handle more than 30 here, instead of writting a
> comment about adding it later. It is just about sending anoither
> command, yes?
> }
This comment is confused.
This mailbox cmd is tell pf should open multicast when netdev_mc_count > 30.
Set MAC address is another cmd.
>> +
>> + cnt = netdev_mc_count(netdev);
>> + if (cnt > 30)
>> + cnt = 30;
>> + msgbuf[0] = WX_VF_SET_MULTICAST;
>> + msgbuf[0] |= cnt << WX_VT_MSGINFO_SHIFT;
>> +
>> + i = 0;
>> + netdev_for_each_mc_addr(ha, netdev) {
>> + if (i == cnt)
>> + break;
>> + if (is_link_local_ether_addr(ha->addr))
>> + continue;
>> +
>> + vector_l[i++] = wx_mta_vector(wx, ha->addr);
>
> What about endianess, don't you need a __cpu_to_le16/be16 conversion?
>
>> + }
>> +
>> + return wx_write_posted_mbx(wx, msgbuf, WX_VXMAILBOX_SIZE);
>
> Shouldn't the size be cut to the real number of address?
Your are right.
>
>> +}
>> +EXPORT_SYMBOL(wx_update_mc_addr_list_vf);
>> +
>> +/**
>> + * wx_update_xcast_mode_vf - Update Multicast mode
>> + * @wx: pointer to the HW structure
>> + * @xcast_mode: new multicast mode
>> + *
>> + * Updates the Multicast Mode of VF.
>> + *
>> + * Return: returns 0 on success, negative error code on failure
>> + **/
>> +int wx_update_xcast_mode_vf(struct wx *wx, int xcast_mode)
>> +{
>> + u32 msgbuf[2] = {WX_VF_UPDATE_XCAST_MODE, xcast_mode};
>> + int ret = 0;
>> +
>> + switch (wx->vfinfo->vf_api) {
>> + case wx_mbox_api_13:
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>
> if (api != vx_mbox_api_13)
> return -EINVAL;
>
>> +
>> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
>> + ARRAY_SIZE(msgbuf));
>> + if (ret)
>> + return ret;
>> +
>> + msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
>> + if (msgbuf[0] == (WX_VF_UPDATE_XCAST_MODE | WX_VT_MSGTYPE_NACK))
>> + return -EINVAL;
>> +
>> + return ret;
>
> return 0;
>
>> +}
>> +EXPORT_SYMBOL(wx_update_xcast_mode_vf);
>> +
>> +/**
>> + * wx_get_link_state_vf - Get VF link state from PF
>> + * @wx: pointer to the HW structure
>> + * @link_state: link state storage
>> + *
>> + * Return: return state of the operation error or success.
>> + **/
>> +int wx_get_link_state_vf(struct wx *wx, u16 *link_state)
>> +{
>> + u32 msgbuf[2] = {WX_VF_GET_LINK_STATE};
>> + int ret = 0;
>> +
>> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
>> + ARRAY_SIZE(msgbuf));
>> + if (ret)
>> + return ret;
>> +
>> + if (msgbuf[0] & WX_VT_MSGTYPE_NACK)
>> + return -EINVAL;
>> +
>> + *link_state = msgbuf[1];
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(wx_get_link_state_vf);
>> +
>> +/**
>> + * wx_set_vfta_vf - Set/Unset vlan filter table address
>> + * @wx: pointer to the HW structure
>> + * @vlan: 12 bit VLAN ID
>> + * @vind: unused by VF drivers
>> + * @vlan_on: if true then set bit, else clear bit
>> + * @vlvf_bypass: boolean flag indicating updating default pool is okay
>> + *
>> + * Turn on/off specified VLAN in the VLAN filter table.
>> + *
>> + * Return: returns 0 on success, negative error code on failure
>> + **/
>> +int wx_set_vfta_vf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on,
>> + bool vlvf_bypass)
>> +{
>> + u32 msgbuf[2] = {WX_VF_SET_VLAN, vlan};
>> + bool vlan_offload = false;
>> + int ret = 0;
>> +
>> + /* Setting the 8 bit field MSG INFO to TRUE indicates "add" */
>> + msgbuf[0] |= vlan_on << WX_VT_MSGINFO_SHIFT;
>> + /* if vf vlan offload is disabled, allow to create vlan under pf port vlan */
>> + msgbuf[0] |= BIT(vlan_offload);
>> +
>> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
>> + ARRAY_SIZE(msgbuf));
>> + if (ret)
>> + return ret;
>> +
>> + if (msgbuf[0] & WX_VT_MSGTYPE_ACK)
>> + return 0;
>> +
>> + return msgbuf[0] & WX_VT_MSGTYPE_NACK;
>
> This will be positive on fail. Reword the kdoc.
> Is it even possible to not have ACK and not have NACK?
> Maybe return -EIO; here is enough? Or even better return error if no ACK
> and return 0; at the end.
If wx_mbx_write_and_read_reply is passed, the msgbuf definitely received successfully.
So I think if it not have ACK and not have NACK, it will return before.
>
>> +}
>> +EXPORT_SYMBOL(wx_set_vfta_vf);
>> +
>> +void wx_get_mac_addr_vf(struct wx *wx, u8 *mac_addr)
>> +{
>> + ether_addr_copy(mac_addr, wx->mac.perm_addr);
>> +}
>> +EXPORT_SYMBOL(wx_get_mac_addr_vf);
>> +
>> +int wx_get_fw_version_vf(struct wx *wx)
>> +{
>> + u32 msgbuf[2] = {WX_VF_GET_FW_VERSION};
>> + int ret;
>> +
>> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
>> + ARRAY_SIZE(msgbuf));
>> + if (ret)
>> + return ret;
>> +
>> + if (msgbuf[0] & WX_VT_MSGTYPE_NACK)
>> + return -EINVAL;
>> + snprintf(wx->eeprom_id, 32, "0x%08x", msgbuf[1]);
>> +
>> + return ret;
>
> It will be great to stick to one style of checking if it is possible.
> Here is the best, if nack returns error, just return 0 at the end, as
> ret is always 0 here.
>
>> +}
>> +EXPORT_SYMBOL(wx_get_fw_version_vf);
>> +
>> +int wx_set_uc_addr_vf(struct wx *wx, u32 index, u8 *addr)
>> +{
>> + u32 msgbuf[3] = {WX_VF_SET_MACVLAN};
>> + u8 *msg_addr = (u8 *)(&msgbuf[1]);
>> + int ret;
>> +
>> + /* If index is one then this is the start of a new list and needs
>> + * indication to the PF so it can do it's own list management.
>> + * If it is zero then that tells the PF to just clear all of
>> + * this VF's macvlans and there is no new list.
>> + */
>> + msgbuf[0] |= index << WX_VT_MSGINFO_SHIFT;
>> + if (addr)
>> + memcpy(msg_addr, addr, 6);
>> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
>> + ARRAY_SIZE(msgbuf));
>> + if (ret)
>> + return ret;
>> +
>> + msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
>> +
>> + if (msgbuf[0] == (WX_VF_SET_MACVLAN | WX_VT_MSGTYPE_NACK))
>> + return -EINVAL;
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(wx_set_uc_addr_vf);
>> +
>> +/**
>> + * wx_rlpml_set_vf - Set the maximum receive packet length
>> + * @wx: pointer to the HW structure
>> + * @max_size: value to assign to max frame size
>> + *
>> + * Return: returns 0 on success, negative error code on failure
>> + **/
>> +int wx_rlpml_set_vf(struct wx *wx, u16 max_size)
>> +{
>> + u32 msgbuf[2] = {WX_VF_SET_LPE, max_size};
>> + int ret;
>> +
>> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
>> + ARRAY_SIZE(msgbuf));
>> + if (ret)
>> + return ret;
>> + if ((msgbuf[0] & WX_VF_SET_LPE) &&
>> + (msgbuf[0] & WX_VT_MSGTYPE_NACK))
>> + return -EINVAL;
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(wx_rlpml_set_vf);
>> +
>> +/**
>> + * wx_negotiate_api_version - Negotiate supported API version
>> + * @wx: pointer to the HW structure
>> + * @api: integer containing requested API version
>> + *
>> + * Return: returns 0 on success, negative error code on failure
>> + **/
>> +int wx_negotiate_api_version(struct wx *wx, int api)
>> +{
>> + u32 msgbuf[2] = {WX_VF_API_NEGOTIATE, api};
>> + int ret;
>> +
>> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
>> + ARRAY_SIZE(msgbuf));
>> + if (ret)
>> + return ret;
>> +
>> + msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
>> +
>> + /* Store value and return 0 on success */
>> + if (msgbuf[0] == (WX_VF_API_NEGOTIATE | WX_VT_MSGTYPE_NACK))
>> + return -EINVAL;
>> + wx->vfinfo->vf_api = api;
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(wx_negotiate_api_version);
>> +
>> +int wx_get_queues_vf(struct wx *wx, u32 *num_tcs, u32 *default_tc)
>> +{
>> + u32 msgbuf[5] = {WX_VF_GET_QUEUES};
>> + int ret = 0;
>
> int ret; is enough.
>
>> +
>> + /* do nothing if API doesn't support wx_get_queues */
>> + switch (wx->vfinfo->vf_api) {
>> + case wx_mbox_api_13:
>> + break;
>> + default:
>> + return 0;
>
> if() instead
>
>> + }
>> +
>> + /* Fetch queue configuration from the PF */
>> + ret = wx_mbx_write_and_read_reply(wx, msgbuf, msgbuf,
>> + ARRAY_SIZE(msgbuf));
>> + if (ret)
>> + return ret;
>> + msgbuf[0] &= ~WX_VT_MSGTYPE_CTS;
>> +
>> + /* if we didn't get an ACK there must have been
>> + * some sort of mailbox error so we should treat it
>> + * as such
>> + */
>> + if (msgbuf[0] != (WX_VF_GET_QUEUES | WX_VT_MSGTYPE_ACK))
>> + return -EINVAL;
>> + /* record and validate values from message */
>> + wx->mac.max_tx_queues = msgbuf[WX_VF_TX_QUEUES];
>> + if (wx->mac.max_tx_queues == 0 ||
>> + wx->mac.max_tx_queues > WX_VF_MAX_TX_QUEUES)
>> + wx->mac.max_tx_queues = WX_VF_MAX_TX_QUEUES;
>> +
>> + wx->mac.max_rx_queues = msgbuf[WX_VF_RX_QUEUES];
>> + if (wx->mac.max_rx_queues == 0 ||
>> + wx->mac.max_rx_queues > WX_VF_MAX_RX_QUEUES)
>> + wx->mac.max_rx_queues = WX_VF_MAX_RX_QUEUES;
>> +
>> + *num_tcs = msgbuf[WX_VF_TRANS_VLAN];
>> + /* in case of unknown state assume we cannot tag frames */
>> + if (*num_tcs > wx->mac.max_rx_queues)
>> + *num_tcs = 1;
>> + *default_tc = msgbuf[WX_VF_DEF_QUEUE];
>> + /* default to queue 0 on out-of-bounds queue number */
>> + if (*default_tc >= wx->mac.max_tx_queues)
>> + *default_tc = 0;
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(wx_get_queues_vf);
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.h b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
>> new file mode 100644
>> index 000000000000..eb40048f46eb
>> --- /dev/null
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
>> @@ -0,0 +1,61 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
>> +
>> +#ifndef _WX_VF_H_
>> +#define _WX_VF_H_
>> +
>> +#define WX_VXSTATUS 0x4
>> +#define WX_VXCTRL 0x8
>> +#define WX_VXCTRL_RST BIT(0)
>> +
>> +#define WX_VXMRQC 0x78
>> +#define WX_VXICR 0x100
>> +#define WX_VXIMS 0x108
>> +#define WX_VF_IRQ_CLEAR_MASK 7
>> +#define WX_VF_MAX_TX_QUEUES 4
>> +#define WX_VF_MAX_RX_QUEUES 4
>> +#define WX_VXTXDCTL(r) (0x3010 + (0x40 * (r)))
>> +#define WX_VXRXDCTL(r) (0x1010 + (0x40 * (r)))
>> +#define WX_VXRXDCTL_ENABLE BIT(0)
>> +#define WX_VXTXDCTL_FLUSH BIT(26)
>> +
>> +#define WX_VXRXDCTL_RSCMAX(f) FIELD_PREP(GENMASK(24, 23), f)
>> +#define WX_VXRXDCTL_BUFLEN(f) FIELD_PREP(GENMASK(6, 1), f)
>> +#define WX_VXRXDCTL_BUFSZ(f) FIELD_PREP(GENMASK(11, 8), f)
>> +#define WX_VXRXDCTL_HDRSZ(f) FIELD_PREP(GENMASK(15, 12), f)
>> +
>> +#define WX_VXRXDCTL_RSCMAX_MASK GENMASK(24, 23)
>> +#define WX_VXRXDCTL_BUFLEN_MASK GENMASK(6, 1)
>> +#define WX_VXRXDCTL_BUFSZ_MASK GENMASK(11, 8)
>> +#define WX_VXRXDCTL_HDRSZ_MASK GENMASK(15, 12)
>> +
>> +#define wx_conf_size(v, mwidth, uwidth) ({ \
>> + typeof(v) _v = (v); \
>> + (_v == 2 << (mwidth) ? 0 : _v >> (uwidth)); \
>> +})
>> +#define wx_buf_len(v) wx_conf_size(v, 13, 7)
>> +#define wx_hdr_sz(v) wx_conf_size(v, 10, 6)
>> +#define wx_buf_sz(v) wx_conf_size(v, 14, 10)
>> +#define wx_pkt_thresh(v) wx_conf_size(v, 4, 0)
>> +
>> +#define WX_RX_HDR_SIZE 256
>> +#define WX_RX_BUF_SIZE 2048
>> +
>> +void wx_start_hw_vf(struct wx *wx);
>> +void wx_init_hw_vf(struct wx *wx);
>> +int wx_reset_hw_vf(struct wx *wx);
>> +void wx_get_mac_addr_vf(struct wx *wx, u8 *mac_addr);
>> +int wx_stop_adapter_vf(struct wx *wx);
>> +int wx_get_fw_version_vf(struct wx *wx);
>> +int wx_set_rar_vf(struct wx *wx, u32 index, u8 *addr, u32 enable_addr);
>> +int wx_update_mc_addr_list_vf(struct wx *wx, struct net_device *netdev);
>> +int wx_set_uc_addr_vf(struct wx *wx, u32 index, u8 *addr);
>> +int wx_rlpml_set_vf(struct wx *wx, u16 max_size);
>> +int wx_negotiate_api_version(struct wx *wx, int api);
>> +int wx_get_queues_vf(struct wx *wx, u32 *num_tcs, u32 *default_tc);
>> +int wx_update_xcast_mode_vf(struct wx *wx, int xcast_mode);
>> +int wx_get_link_state_vf(struct wx *wx, u16 *link_state);
>> +int wx_set_vfta_vf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on,
>> + bool vlvf_bypass);
>> +
>> +#endif /* _WX_VF_H_ */
>
> In general it will be great to define structures for each command that
> is used in VF communication. Filling it should be also easier.
>
> Thanks
>
>> --
>> 2.30.1
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH net-next 03/12] net: libwx: add wangxun vf common api
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 01/12] net: libwx: add mailbox api for wangxun vf drivers Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 02/12] net: libwx: add base vf api for " Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-17 15:11 ` Simon Horman
2025-06-11 8:35 ` [PATCH net-next 04/12] net: wangxun: add txgbevf build Mengyuan Lou
` (8 subsequent siblings)
11 siblings, 1 reply; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Add common wx_configure_vf and wx_set_mac_vf for
ngbevf and txgbevf.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
drivers/net/ethernet/wangxun/libwx/Makefile | 2 +-
drivers/net/ethernet/wangxun/libwx/wx_hw.c | 3 +-
drivers/net/ethernet/wangxun/libwx/wx_hw.h | 1 +
drivers/net/ethernet/wangxun/libwx/wx_type.h | 4 +
drivers/net/ethernet/wangxun/libwx/wx_vf.h | 49 +++
.../net/ethernet/wangxun/libwx/wx_vf_common.c | 194 ++++++++++++
.../net/ethernet/wangxun/libwx/wx_vf_common.h | 14 +
.../net/ethernet/wangxun/libwx/wx_vf_lib.c | 290 ++++++++++++++++++
.../net/ethernet/wangxun/libwx/wx_vf_lib.h | 14 +
9 files changed, 569 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h
diff --git a/drivers/net/ethernet/wangxun/libwx/Makefile b/drivers/net/ethernet/wangxun/libwx/Makefile
index ddf0bb921676..a71b0ad77de3 100644
--- a/drivers/net/ethernet/wangxun/libwx/Makefile
+++ b/drivers/net/ethernet/wangxun/libwx/Makefile
@@ -5,4 +5,4 @@
obj-$(CONFIG_LIBWX) += libwx.o
libwx-objs := wx_hw.o wx_lib.o wx_ethtool.o wx_ptp.o wx_mbx.o wx_sriov.o
-libwx-objs += wx_vf.o
+libwx-objs += wx_vf.o wx_vf_lib.o wx_vf_common.o
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 82dd76f0326e..27bb33788701 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -1827,7 +1827,7 @@ void wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring)
}
EXPORT_SYMBOL(wx_disable_rx_queue);
-static void wx_enable_rx_queue(struct wx *wx, struct wx_ring *ring)
+void wx_enable_rx_queue(struct wx *wx, struct wx_ring *ring)
{
u8 reg_idx = ring->reg_idx;
u32 rxdctl;
@@ -1843,6 +1843,7 @@ static void wx_enable_rx_queue(struct wx *wx, struct wx_ring *ring)
reg_idx);
}
}
+EXPORT_SYMBOL(wx_enable_rx_queue);
static void wx_configure_srrctl(struct wx *wx,
struct wx_ring *rx_ring)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
index 718015611da6..2393a743b564 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
@@ -38,6 +38,7 @@ void wx_enable_sec_rx_path(struct wx *wx);
void wx_set_rx_mode(struct net_device *netdev);
int wx_change_mtu(struct net_device *netdev, int new_mtu);
void wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring);
+void wx_enable_rx_queue(struct wx *wx, struct wx_ring *ring);
void wx_configure_rx(struct wx *wx);
void wx_configure(struct wx *wx);
void wx_start_hw(struct wx *wx);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index d2d0764792d4..63bb7785fd19 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -828,6 +828,8 @@ struct wx_mbx_info {
u32 mailbox;
u32 udelay;
u32 timeout;
+ /* lock mbx access */
+ spinlock_t mbx_lock;
};
struct wx_thermal_sensor_data {
@@ -1288,6 +1290,8 @@ struct wx {
u32 *isb_mem;
u32 isb_tag[WX_ISB_MAX];
bool misc_irq_domain;
+ u32 eims_other;
+ u32 eims_enable_mask;
#define WX_MAX_RETA_ENTRIES 128
#define WX_RSS_INDIR_TBL_MAX 64
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.h b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
index eb40048f46eb..3bb70421622a 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
@@ -11,6 +11,7 @@
#define WX_VXMRQC 0x78
#define WX_VXICR 0x100
#define WX_VXIMS 0x108
+#define WX_VXIMC 0x10C
#define WX_VF_IRQ_CLEAR_MASK 7
#define WX_VF_MAX_TX_QUEUES 4
#define WX_VF_MAX_RX_QUEUES 4
@@ -19,6 +20,11 @@
#define WX_VXRXDCTL_ENABLE BIT(0)
#define WX_VXTXDCTL_FLUSH BIT(26)
+#define WX_VXITR(i) (0x200 + (4 * (i))) /* i=[0,1] */
+#define WX_VXITR_CNT_WDIS BIT(31)
+#define WX_VXIVAR_MISC 0x260
+#define WX_VXIVAR(i) (0x240 + (4 * (i))) /* i=[0,3] */
+
#define WX_VXRXDCTL_RSCMAX(f) FIELD_PREP(GENMASK(24, 23), f)
#define WX_VXRXDCTL_BUFLEN(f) FIELD_PREP(GENMASK(6, 1), f)
#define WX_VXRXDCTL_BUFSZ(f) FIELD_PREP(GENMASK(11, 8), f)
@@ -41,6 +47,49 @@
#define WX_RX_HDR_SIZE 256
#define WX_RX_BUF_SIZE 2048
+#define WX_RXBUFFER_2048 (2048)
+#define WX_RXBUFFER_3072 3072
+
+/* Receive Path */
+#define WX_VXRDBAL(r) (0x1000 + (0x40 * (r)))
+#define WX_VXRDBAH(r) (0x1004 + (0x40 * (r)))
+#define WX_VXRDT(r) (0x1008 + (0x40 * (r)))
+#define WX_VXRDH(r) (0x100C + (0x40 * (r)))
+
+#define WX_VXRXDCTL_RSCEN BIT(29)
+#define WX_VXRXDCTL_DROP BIT(30)
+#define WX_VXRXDCTL_VLAN BIT(31)
+
+#define WX_VXTDBAL(r) (0x3000 + (0x40 * (r)))
+#define WX_VXTDBAH(r) (0x3004 + (0x40 * (r)))
+#define WX_VXTDT(r) (0x3008 + (0x40 * (r)))
+#define WX_VXTDH(r) (0x300C + (0x40 * (r)))
+
+#define WX_VXTXDCTL_ENABLE BIT(0)
+#define WX_VXTXDCTL_BUFLEN(f) FIELD_PREP(GENMASK(6, 1), f)
+#define WX_VXTXDCTL_PTHRESH(f) FIELD_PREP(GENMASK(11, 8), f)
+#define WX_VXTXDCTL_WTHRESH(f) FIELD_PREP(GENMASK(22, 16), f)
+
+#define WX_VXMRQC_PSR(f) FIELD_PREP(GENMASK(5, 1), f)
+#define WX_VXMRQC_PSR_MASK GENMASK(5, 1)
+#define WX_VXMRQC_PSR_L4HDR BIT(0)
+#define WX_VXMRQC_PSR_L3HDR BIT(1)
+#define WX_VXMRQC_PSR_L2HDR BIT(2)
+#define WX_VXMRQC_PSR_TUNHDR BIT(3)
+#define WX_VXMRQC_PSR_TUNMAC BIT(4)
+
+#define WX_VXRSSRK(i) (0x80 + ((i) * 4)) /* i=[0,9] */
+#define WX_VXRETA(i) (0xC0 + ((i) * 4)) /* i=[0,15] */
+
+#define WX_VXMRQC_RSS(f) FIELD_PREP(GENMASK(31, 16), f)
+#define WX_VXMRQC_RSS_MASK GENMASK(31, 16)
+#define WX_VXMRQC_RSS_ALG_IPV4_TCP BIT(0)
+#define WX_VXMRQC_RSS_ALG_IPV4 BIT(1)
+#define WX_VXMRQC_RSS_ALG_IPV6 BIT(4)
+#define WX_VXMRQC_RSS_ALG_IPV6_TCP BIT(5)
+#define WX_VXMRQC_RSS_EN BIT(8)
+#define WX_VXMRQC_RSS_HASH(f) FIELD_PREP(GENMASK(15, 13), f)
+
void wx_start_hw_vf(struct wx *wx);
void wx_init_hw_vf(struct wx *wx);
int wx_reset_hw_vf(struct wx *wx);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
new file mode 100644
index 000000000000..861adf97e801
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+
+#include "wx_type.h"
+#include "wx_mbx.h"
+#include "wx_lib.h"
+#include "wx_vf.h"
+#include "wx_vf_lib.h"
+#include "wx_vf_common.h"
+
+static irqreturn_t wx_msix_misc_vf(int __always_unused irq, void *data)
+{
+ struct wx *wx = data;
+
+ /* Clear the interrupt */
+ if (netif_running(wx->netdev))
+ wr32(wx, WX_VXIMC, wx->eims_other);
+
+ return IRQ_HANDLED;
+}
+
+int wx_request_msix_irqs_vf(struct wx *wx)
+{
+ struct net_device *netdev = wx->netdev;
+ int vector, err;
+
+ for (vector = 0; vector < wx->num_q_vectors; vector++) {
+ struct wx_q_vector *q_vector = wx->q_vector[vector];
+ struct msix_entry *entry = &wx->msix_q_entries[vector];
+
+ if (q_vector->tx.ring && q_vector->rx.ring)
+ snprintf(q_vector->name, sizeof(q_vector->name) - 1,
+ "%s-TxRx-%d", netdev->name, entry->entry);
+ else
+ /* skip this unused q_vector */
+ continue;
+
+ err = request_irq(entry->vector, wx_msix_clean_rings, 0,
+ q_vector->name, q_vector);
+ if (err) {
+ wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n",
+ q_vector->name, err);
+ goto free_queue_irqs;
+ }
+ }
+
+ err = request_irq(wx->msix_entry->vector,
+ wx_msix_misc_vf, 0, netdev->name, wx);
+ if (err) {
+ wx_err(wx, "request_irq for msix_other failed: %d\n", err);
+ goto free_queue_irqs;
+ }
+
+ return 0;
+
+free_queue_irqs:
+ while (vector) {
+ vector--;
+ free_irq(wx->msix_q_entries[vector].vector,
+ wx->q_vector[vector]);
+ }
+ wx_reset_interrupt_capability(wx);
+ return err;
+}
+EXPORT_SYMBOL(wx_request_msix_irqs_vf);
+
+void wx_negotiate_api_vf(struct wx *wx)
+{
+ int api[] = {
+ wx_mbox_api_13,
+ wx_mbox_api_null};
+ int err = 0, idx = 0;
+
+ spin_lock_bh(&wx->mbx.mbx_lock);
+ while (api[idx] != wx_mbox_api_null) {
+ err = wx_negotiate_api_version(wx, api[idx]);
+ if (!err)
+ break;
+ idx++;
+ }
+ spin_unlock_bh(&wx->mbx.mbx_lock);
+}
+EXPORT_SYMBOL(wx_negotiate_api_vf);
+
+void wx_reset_vf(struct wx *wx)
+{
+ struct net_device *netdev = wx->netdev;
+ int ret = 0;
+
+ ret = wx_reset_hw_vf(wx);
+ if (!ret)
+ wx_init_hw_vf(wx);
+ wx_negotiate_api_vf(wx);
+ if (is_valid_ether_addr(wx->mac.addr)) {
+ eth_hw_addr_set(netdev, wx->mac.addr);
+ ether_addr_copy(netdev->perm_addr, wx->mac.addr);
+ }
+}
+EXPORT_SYMBOL(wx_reset_vf);
+
+void wx_set_rx_mode_vf(struct net_device *netdev)
+{
+ struct wx *wx = netdev_priv(netdev);
+ unsigned int flags = netdev->flags;
+ int xcast_mode;
+
+ xcast_mode = (flags & IFF_ALLMULTI) ? WXVF_XCAST_MODE_ALLMULTI :
+ (flags & (IFF_BROADCAST | IFF_MULTICAST)) ?
+ WXVF_XCAST_MODE_MULTI : WXVF_XCAST_MODE_NONE;
+ /* request the most inclusive mode we need */
+ if (flags & IFF_PROMISC)
+ xcast_mode = WXVF_XCAST_MODE_PROMISC;
+ else if (flags & IFF_ALLMULTI)
+ xcast_mode = WXVF_XCAST_MODE_ALLMULTI;
+ else if (flags & (IFF_BROADCAST | IFF_MULTICAST))
+ xcast_mode = WXVF_XCAST_MODE_MULTI;
+ else
+ xcast_mode = WXVF_XCAST_MODE_NONE;
+
+ spin_lock_bh(&wx->mbx.mbx_lock);
+ wx_update_xcast_mode_vf(wx, xcast_mode);
+ wx_update_mc_addr_list_vf(wx, netdev);
+ wx_write_uc_addr_list_vf(netdev);
+ spin_unlock_bh(&wx->mbx.mbx_lock);
+}
+EXPORT_SYMBOL(wx_set_rx_mode_vf);
+
+/**
+ * wx_configure_rx_vf - Configure Receive Unit after Reset
+ * @wx: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void wx_configure_rx_vf(struct wx *wx)
+{
+ struct net_device *netdev = wx->netdev;
+ int i, ret;
+
+ wx_setup_psrtype_vf(wx);
+ wx_setup_vfmrqc_vf(wx);
+
+ spin_lock_bh(&wx->mbx.mbx_lock);
+ ret = wx_rlpml_set_vf(wx, netdev->mtu + ETH_HLEN + ETH_FCS_LEN);
+ spin_unlock_bh(&wx->mbx.mbx_lock);
+ if (ret)
+ wx_dbg(wx, "Failed to set MTU at %d\n", netdev->mtu);
+
+ /* Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring
+ */
+ for (i = 0; i < wx->num_rx_queues; i++) {
+ struct wx_ring *rx_ring = wx->rx_ring[i];
+#ifdef HAVE_SWIOTLB_SKIP_CPU_SYNC
+ wx_set_rx_buffer_len_vf(wx, rx_ring);
+#endif
+ wx_configure_rx_ring_vf(wx, rx_ring);
+ }
+}
+
+void wx_configure_vf(struct wx *wx)
+{
+ wx_set_rx_mode_vf(wx->netdev);
+ wx_configure_tx_vf(wx);
+ wx_configure_rx_vf(wx);
+}
+EXPORT_SYMBOL(wx_configure_vf);
+
+int wx_set_mac_vf(struct net_device *netdev, void *p)
+{
+ struct wx *wx = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+ int ret;
+
+ ret = eth_prepare_mac_addr_change(netdev, addr);
+ if (ret)
+ return ret;
+
+ spin_lock_bh(&wx->mbx.mbx_lock);
+ ret = wx_set_rar_vf(wx, 1, (u8 *)addr->sa_data, 1);
+ spin_unlock_bh(&wx->mbx.mbx_lock);
+
+ if (ret)
+ return -EPERM;
+
+ memcpy(wx->mac.addr, addr->sa_data, netdev->addr_len);
+ memcpy(wx->mac.perm_addr, addr->sa_data, netdev->addr_len);
+ eth_hw_addr_set(netdev, addr->sa_data);
+
+ return 0;
+}
+EXPORT_SYMBOL(wx_set_mac_vf);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
new file mode 100644
index 000000000000..9bee9de86cb2
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _WX_VF_COMMON_H_
+#define _WX_VF_COMMON_H_
+
+int wx_request_msix_irqs_vf(struct wx *wx);
+void wx_negotiate_api_vf(struct wx *wx);
+void wx_reset_vf(struct wx *wx);
+void wx_set_rx_mode_vf(struct net_device *netdev);
+void wx_configure_vf(struct wx *wx);
+int wx_set_mac_vf(struct net_device *netdev, void *p);
+
+#endif /* _WX_VF_COMMON_H_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
new file mode 100644
index 000000000000..b234d18153b5
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+
+#include "wx_type.h"
+#include "wx_hw.h"
+#include "wx_lib.h"
+#include "wx_vf.h"
+#include "wx_vf_lib.h"
+
+static void wx_write_eitr_vf(struct wx_q_vector *q_vector)
+{
+ struct wx *wx = q_vector->wx;
+ int v_idx = q_vector->v_idx;
+ u32 itr_reg;
+
+ itr_reg = q_vector->itr & GENMASK(8, 0);
+
+ /* set the WDIS bit to not clear the timer bits and cause an
+ * immediate assertion of the interrupt
+ */
+ itr_reg |= WX_VXITR_CNT_WDIS;
+
+ wr32(wx, WX_VXITR(v_idx), itr_reg);
+}
+
+static void wx_set_ivar_vf(struct wx *wx, s8 direction, u8 queue,
+ u8 msix_vector)
+{
+ u32 ivar, index;
+
+ if (direction == -1) {
+ /* other causes */
+ msix_vector |= WX_PX_IVAR_ALLOC_VAL;
+ ivar = rd32(wx, WX_VXIVAR_MISC);
+ ivar &= ~0xFF;
+ ivar |= msix_vector;
+ wr32(wx, WX_VXIVAR_MISC, ivar);
+ } else {
+ /* tx or rx causes */
+ msix_vector |= WX_PX_IVAR_ALLOC_VAL;
+ index = ((16 * (queue & 1)) + (8 * direction));
+ ivar = rd32(wx, WX_VXIVAR(queue >> 1));
+ ivar &= ~(0xFF << index);
+ ivar |= (msix_vector << index);
+ wr32(wx, WX_VXIVAR(queue >> 1), ivar);
+ }
+}
+
+void wx_configure_msix_vf(struct wx *wx)
+{
+ int v_idx;
+
+ wx->eims_enable_mask = 0;
+ for (v_idx = 0; v_idx < wx->num_q_vectors; v_idx++) {
+ struct wx_q_vector *q_vector = wx->q_vector[v_idx];
+ struct wx_ring *ring;
+
+ wx_for_each_ring(ring, q_vector->rx)
+ wx_set_ivar_vf(wx, 0, ring->reg_idx, v_idx);
+
+ wx_for_each_ring(ring, q_vector->tx)
+ wx_set_ivar_vf(wx, 1, ring->reg_idx, v_idx);
+
+ /* add q_vector eims value to global eims_enable_mask */
+ wx->eims_enable_mask |= BIT(v_idx);
+ wx_write_eitr_vf(q_vector);
+ }
+
+ wx_set_ivar_vf(wx, -1, 1, v_idx);
+
+ /* setup eims_other and add value to global eims_enable_mask */
+ wx->eims_other = BIT(v_idx);
+ wx->eims_enable_mask |= wx->eims_other;
+}
+
+int wx_write_uc_addr_list_vf(struct net_device *netdev)
+{
+ struct wx *wx = netdev_priv(netdev);
+ int count = 0;
+
+ if (!netdev_uc_empty(netdev)) {
+ struct netdev_hw_addr *ha;
+
+ netdev_for_each_uc_addr(ha, netdev)
+ wx_set_uc_addr_vf(wx, ++count, ha->addr);
+ } else {
+ /*
+ * If the list is empty then send message to PF driver to
+ * clear all macvlans on this VF.
+ */
+ wx_set_uc_addr_vf(wx, 0, NULL);
+ }
+
+ return count;
+}
+
+/**
+ * wx_configure_tx_ring_vf - Configure Tx ring after Reset
+ * @wx: board private structure
+ * @ring: structure containing ring specific data
+ *
+ * Configure the Tx descriptor ring after a reset.
+ **/
+static void wx_configure_tx_ring_vf(struct wx *wx, struct wx_ring *ring)
+{
+ u8 reg_idx = ring->reg_idx;
+ u64 tdba = ring->dma;
+ u32 txdctl = 0;
+ int ret;
+
+ /* disable queue to avoid issues while updating state */
+ wr32(wx, WX_VXTXDCTL(reg_idx), WX_VXTXDCTL_FLUSH);
+ wr32(wx, WX_VXTDBAL(reg_idx), tdba & DMA_BIT_MASK(32));
+ wr32(wx, WX_VXTDBAH(reg_idx), tdba >> 32);
+
+ /* enable relaxed ordering */
+ pcie_capability_clear_and_set_word(wx->pdev, PCI_EXP_DEVCTL,
+ 0, PCI_EXP_DEVCTL_RELAX_EN);
+
+ /* reset head and tail pointers */
+ wr32(wx, WX_VXTDH(reg_idx), 0);
+ wr32(wx, WX_VXTDT(reg_idx), 0);
+ ring->tail = wx->hw_addr + WX_VXTDT(reg_idx);
+
+ /* reset ntu and ntc to place SW in sync with hardwdare */
+ ring->next_to_clean = 0;
+ ring->next_to_use = 0;
+
+ txdctl |= WX_VXTXDCTL_BUFLEN(wx_buf_len(ring->count));
+ txdctl |= WX_VXTXDCTL_ENABLE;
+
+ /* set WTHRESH to encourage burst writeback, it should not be set
+ * higher than 1 when ITR is 0 as it could cause false TX hangs
+ *
+ * In order to avoid issues WTHRESH + PTHRESH should always be equal
+ * to or less than the number of on chip descriptors, which is
+ * currently 40.
+ */
+ /* reinitialize tx_buffer_info */
+ memset(ring->tx_buffer_info, 0,
+ sizeof(struct wx_tx_buffer) * ring->count);
+
+ wr32(wx, WX_VXTXDCTL(reg_idx), txdctl);
+ /* poll to verify queue is enabled */
+ ret = read_poll_timeout(rd32, txdctl, txdctl & WX_VXTXDCTL_ENABLE,
+ 1000, 10000, true, wx, WX_VXTXDCTL(reg_idx));
+ if (ret == -ETIMEDOUT)
+ wx_err(wx, "Could not enable Tx Queue %d\n", reg_idx);
+}
+
+/**
+ * wx_configure_tx_vf - Configure Transmit Unit after Reset
+ * @wx: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+void wx_configure_tx_vf(struct wx *wx)
+{
+ u32 i;
+
+ /* Setup the HW Tx Head and Tail descriptor pointers */
+ for (i = 0; i < wx->num_tx_queues; i++)
+ wx_configure_tx_ring_vf(wx, wx->tx_ring[i]);
+}
+
+static void wx_configure_srrctl_vf(struct wx *wx, struct wx_ring *ring,
+ int index)
+{
+ u32 srrctl;
+
+ srrctl = rd32m(wx, WX_VXRXDCTL(index),
+ (u32)~(WX_VXRXDCTL_HDRSZ_MASK | WX_VXRXDCTL_BUFSZ_MASK));
+ srrctl |= WX_VXRXDCTL_DROP;
+ srrctl |= WX_VXRXDCTL_HDRSZ(wx_hdr_sz(WX_RX_HDR_SIZE));
+ srrctl |= WX_VXRXDCTL_BUFSZ(wx_buf_sz(WX_RX_BUF_SIZE));
+
+ wr32(wx, WX_VXRXDCTL(index), srrctl);
+}
+
+void wx_setup_psrtype_vf(struct wx *wx)
+{
+ /* PSRTYPE must be initialized */
+ u32 psrtype = WX_VXMRQC_PSR_L2HDR |
+ WX_VXMRQC_PSR_L3HDR |
+ WX_VXMRQC_PSR_L4HDR |
+ WX_VXMRQC_PSR_TUNHDR |
+ WX_VXMRQC_PSR_TUNMAC;
+
+ if (wx->num_rx_queues > 1)
+ psrtype |= BIT(14);
+
+ wr32m(wx, WX_VXMRQC, WX_VXMRQC_PSR_MASK, WX_VXMRQC_PSR(psrtype));
+}
+
+void wx_setup_vfmrqc_vf(struct wx *wx)
+{
+ u16 rss_i = wx->num_rx_queues;
+ u32 vfmrqc = 0, vfreta = 0;
+ u8 i, j;
+
+ /* Fill out hash function seeds */
+ netdev_rss_key_fill(wx->rss_key, sizeof(wx->rss_key));
+ for (i = 0; i < 10; i++)
+ wr32(wx, WX_VXRSSRK(i), wx->rss_key[i]);
+
+ for (i = 0, j = 0; i < 128; i++, j++) {
+ if (j == rss_i)
+ j = 0;
+
+ wx->rss_indir_tbl[i] = j;
+
+ vfreta |= j << (i & 0x3) * 8;
+ if ((i & 3) == 3) {
+ wr32(wx, WX_VXRETA(i >> 2), vfreta);
+ vfreta = 0;
+ }
+ }
+
+ /* Perform hash on these packet types */
+ vfmrqc |= WX_VXMRQC_RSS_ALG_IPV4 |
+ WX_VXMRQC_RSS_ALG_IPV4_TCP |
+ WX_VXMRQC_RSS_ALG_IPV6 |
+ WX_VXMRQC_RSS_ALG_IPV6_TCP;
+
+ vfmrqc |= WX_VXMRQC_RSS_EN;
+
+ if (wx->num_rx_queues > 3)
+ vfmrqc |= WX_VXMRQC_RSS_HASH(2);
+ else if (wx->num_rx_queues > 1)
+ vfmrqc |= WX_VXMRQC_RSS_HASH(1);
+ wr32m(wx, WX_VXMRQC, WX_VXMRQC_RSS_MASK, WX_VXMRQC_RSS(vfmrqc));
+}
+
+void wx_configure_rx_ring_vf(struct wx *wx, struct wx_ring *ring)
+{
+ u8 reg_idx = ring->reg_idx;
+ union wx_rx_desc *rx_desc;
+ u64 rdba = ring->dma;
+ u32 rxdctl;
+
+ /* disable queue to avoid issues while updating state */
+ rxdctl = rd32(wx, WX_VXRXDCTL(reg_idx));
+ wx_disable_rx_queue(wx, ring);
+
+ wr32(wx, WX_VXRDBAL(reg_idx), rdba & DMA_BIT_MASK(32));
+ wr32(wx, WX_VXRDBAH(reg_idx), rdba >> 32);
+
+ /* enable relaxed ordering */
+ pcie_capability_clear_and_set_word(wx->pdev, PCI_EXP_DEVCTL,
+ 0, PCI_EXP_DEVCTL_RELAX_EN);
+
+ /* reset head and tail pointers */
+ wr32(wx, WX_VXRDH(reg_idx), 0);
+ wr32(wx, WX_VXRDT(reg_idx), 0);
+ ring->tail = wx->hw_addr + WX_VXRDT(reg_idx);
+
+ /* initialize rx_buffer_info */
+ memset(ring->rx_buffer_info, 0,
+ sizeof(struct wx_rx_buffer) * ring->count);
+
+ /* initialize Rx descriptor 0 */
+ rx_desc = WX_RX_DESC(ring, 0);
+ rx_desc->wb.upper.length = 0;
+
+ /* reset ntu and ntc to place SW in sync with hardwdare */
+ ring->next_to_clean = 0;
+ ring->next_to_use = 0;
+ ring->next_to_alloc = 0;
+
+ wx_configure_srrctl_vf(wx, ring, reg_idx);
+
+ /* allow any size packet since we can handle overflow */
+ rxdctl &= ~WX_VXRXDCTL_BUFLEN_MASK;
+ rxdctl |= WX_VXRXDCTL_BUFLEN(wx_buf_len(ring->count));
+ rxdctl |= WX_VXRXDCTL_ENABLE | WX_VXRXDCTL_VLAN;
+
+ /* enable RSC */
+ rxdctl &= ~WX_VXRXDCTL_RSCMAX_MASK;
+ rxdctl |= WX_VXRXDCTL_RSCMAX(0);
+ rxdctl |= WX_VXRXDCTL_RSCEN;
+
+ wr32(wx, WX_VXRXDCTL(reg_idx), rxdctl);
+
+ /* pf/vf reuse */
+ wx_enable_rx_queue(wx, ring);
+ wx_alloc_rx_buffers(ring, wx_desc_unused(ring));
+}
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h
new file mode 100644
index 000000000000..43ea126b79eb
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _WX_VF_LIB_H_
+#define _WX_VF_LIB_H_
+
+void wx_configure_msix_vf(struct wx *wx);
+int wx_write_uc_addr_list_vf(struct net_device *netdev);
+void wx_setup_psrtype_vf(struct wx *wx);
+void wx_setup_vfmrqc_vf(struct wx *wx);
+void wx_configure_tx_vf(struct wx *wx);
+void wx_configure_rx_ring_vf(struct wx *wx, struct wx_ring *ring);
+
+#endif /* _WX_VF_LIB_H_ */
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH net-next 03/12] net: libwx: add wangxun vf common api
2025-06-11 8:35 ` [PATCH net-next 03/12] net: libwx: add wangxun vf common api Mengyuan Lou
@ 2025-06-17 15:11 ` Simon Horman
2025-06-20 8:02 ` mengyuanlou
0 siblings, 1 reply; 20+ messages in thread
From: Simon Horman @ 2025-06-17 15:11 UTC (permalink / raw)
To: Mengyuan Lou
Cc: netdev, kuba, pabeni, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu
On Wed, Jun 11, 2025 at 04:35:50PM +0800, Mengyuan Lou wrote:
> Add common wx_configure_vf and wx_set_mac_vf for
> ngbevf and txgbevf.
>
> Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
...
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.h b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
...
> +#define WX_VXMRQC_PSR(f) FIELD_PREP(GENMASK(5, 1), f)
> +#define WX_VXMRQC_PSR_MASK GENMASK(5, 1)
> +#define WX_VXMRQC_PSR_L4HDR BIT(0)
> +#define WX_VXMRQC_PSR_L3HDR BIT(1)
> +#define WX_VXMRQC_PSR_L2HDR BIT(2)
> +#define WX_VXMRQC_PSR_TUNHDR BIT(3)
> +#define WX_VXMRQC_PSR_TUNMAC BIT(4)
...
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
...
> +/**
> + * wx_configure_tx_ring_vf - Configure Tx ring after Reset
> + * @wx: board private structure
> + * @ring: structure containing ring specific data
> + *
> + * Configure the Tx descriptor ring after a reset.
> + **/
> +static void wx_configure_tx_ring_vf(struct wx *wx, struct wx_ring *ring)
> +{
> + u8 reg_idx = ring->reg_idx;
> + u64 tdba = ring->dma;
> + u32 txdctl = 0;
> + int ret;
> +
> + /* disable queue to avoid issues while updating state */
> + wr32(wx, WX_VXTXDCTL(reg_idx), WX_VXTXDCTL_FLUSH);
> + wr32(wx, WX_VXTDBAL(reg_idx), tdba & DMA_BIT_MASK(32));
> + wr32(wx, WX_VXTDBAH(reg_idx), tdba >> 32);
> +
> + /* enable relaxed ordering */
> + pcie_capability_clear_and_set_word(wx->pdev, PCI_EXP_DEVCTL,
> + 0, PCI_EXP_DEVCTL_RELAX_EN);
> +
> + /* reset head and tail pointers */
> + wr32(wx, WX_VXTDH(reg_idx), 0);
> + wr32(wx, WX_VXTDT(reg_idx), 0);
> + ring->tail = wx->hw_addr + WX_VXTDT(reg_idx);
> +
> + /* reset ntu and ntc to place SW in sync with hardwdare */
nit: hardware
> + ring->next_to_clean = 0;
> + ring->next_to_use = 0;
> +
> + txdctl |= WX_VXTXDCTL_BUFLEN(wx_buf_len(ring->count));
> + txdctl |= WX_VXTXDCTL_ENABLE;
> +
> + /* set WTHRESH to encourage burst writeback, it should not be set
> + * higher than 1 when ITR is 0 as it could cause false TX hangs
> + *
> + * In order to avoid issues WTHRESH + PTHRESH should always be equal
> + * to or less than the number of on chip descriptors, which is
> + * currently 40.
> + */
> + /* reinitialize tx_buffer_info */
> + memset(ring->tx_buffer_info, 0,
> + sizeof(struct wx_tx_buffer) * ring->count);
> +
> + wr32(wx, WX_VXTXDCTL(reg_idx), txdctl);
> + /* poll to verify queue is enabled */
> + ret = read_poll_timeout(rd32, txdctl, txdctl & WX_VXTXDCTL_ENABLE,
> + 1000, 10000, true, wx, WX_VXTXDCTL(reg_idx));
> + if (ret == -ETIMEDOUT)
> + wx_err(wx, "Could not enable Tx Queue %d\n", reg_idx);
> +}
...
> +void wx_setup_psrtype_vf(struct wx *wx)
> +{
> + /* PSRTYPE must be initialized */
> + u32 psrtype = WX_VXMRQC_PSR_L2HDR |
> + WX_VXMRQC_PSR_L3HDR |
> + WX_VXMRQC_PSR_L4HDR |
> + WX_VXMRQC_PSR_TUNHDR |
> + WX_VXMRQC_PSR_TUNMAC;
> +
> + if (wx->num_rx_queues > 1)
> + psrtype |= BIT(14);
Here bit 14 of psrtype may be set (what is bit 14?).
> +
> + wr32m(wx, WX_VXMRQC, WX_VXMRQC_PSR_MASK, WX_VXMRQC_PSR(psrtype));
But WX_VXMRQC_PSR() uses a mask that limits psrtype to 5 bits.
This is flagged by W=1 builds with gcc-8.5.0 on x86_64
(but curiously not gcc-15.1.0 builds). It is flagged like this:
CC [M] drivers/net/ethernet/wangxun/libwx/wx_vf_lib.o
In file included from <command-line>:
drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c: In function 'wx_setup_psrtype_vf':
././include/linux/compiler_types.h:568:38: error: call to '__compiletime_assert_1833' declared with attribute error: FIELD_PREP: value too large for the field
_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
^
././include/linux/compiler_types.h:549:4: note: in definition of macro '__compiletime_assert'
prefix ## suffix(); \
^~~~~~
././include/linux/compiler_types.h:568:2: note: in expansion of macro '_compiletime_assert'
_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
^~~~~~~~~~~~~~~~~~~
./include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert'
#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
^~~~~~~~~~~~~~~~~~
./include/linux/bitfield.h:68:3: note: in expansion of macro 'BUILD_BUG_ON_MSG'
BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \
^~~~~~~~~~~~~~~~
./include/linux/bitfield.h:115:3: note: in expansion of macro '__BF_FIELD_CHECK'
__BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \
^~~~~~~~~~~~~~~~
drivers/net/ethernet/wangxun/libwx/wx_vf.h:73:34: note: in expansion of macro 'FIELD_PREP'
#define WX_VXMRQC_PSR(f) FIELD_PREP(GENMASK(5, 1), f)
^~~~~~~~~~
drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c:195:43: note: in expansion of macro 'WX_VXMRQC_PSR'
wr32m(wx, WX_VXMRQC, WX_VXMRQC_PSR_MASK, WX_VXMRQC_PSR(psrtype));
^~~~~~~~~~~~~
make[7]: *** [scripts/Makefile.build:203:
drivers/net/ethernet/wangxun/libwx/wx_vf_lib.o] Error 1:
> +}
...
> +void wx_configure_rx_ring_vf(struct wx *wx, struct wx_ring *ring)
> +{
> + u8 reg_idx = ring->reg_idx;
> + union wx_rx_desc *rx_desc;
> + u64 rdba = ring->dma;
> + u32 rxdctl;
> +
> + /* disable queue to avoid issues while updating state */
> + rxdctl = rd32(wx, WX_VXRXDCTL(reg_idx));
> + wx_disable_rx_queue(wx, ring);
> +
> + wr32(wx, WX_VXRDBAL(reg_idx), rdba & DMA_BIT_MASK(32));
> + wr32(wx, WX_VXRDBAH(reg_idx), rdba >> 32);
> +
> + /* enable relaxed ordering */
> + pcie_capability_clear_and_set_word(wx->pdev, PCI_EXP_DEVCTL,
> + 0, PCI_EXP_DEVCTL_RELAX_EN);
> +
> + /* reset head and tail pointers */
> + wr32(wx, WX_VXRDH(reg_idx), 0);
> + wr32(wx, WX_VXRDT(reg_idx), 0);
> + ring->tail = wx->hw_addr + WX_VXRDT(reg_idx);
> +
> + /* initialize rx_buffer_info */
> + memset(ring->rx_buffer_info, 0,
> + sizeof(struct wx_rx_buffer) * ring->count);
> +
> + /* initialize Rx descriptor 0 */
> + rx_desc = WX_RX_DESC(ring, 0);
> + rx_desc->wb.upper.length = 0;
> +
> + /* reset ntu and ntc to place SW in sync with hardwdare */
nit: hardware
> + ring->next_to_clean = 0;
> + ring->next_to_use = 0;
> + ring->next_to_alloc = 0;
> +
> + wx_configure_srrctl_vf(wx, ring, reg_idx);
> +
> + /* allow any size packet since we can handle overflow */
> + rxdctl &= ~WX_VXRXDCTL_BUFLEN_MASK;
> + rxdctl |= WX_VXRXDCTL_BUFLEN(wx_buf_len(ring->count));
> + rxdctl |= WX_VXRXDCTL_ENABLE | WX_VXRXDCTL_VLAN;
> +
> + /* enable RSC */
> + rxdctl &= ~WX_VXRXDCTL_RSCMAX_MASK;
> + rxdctl |= WX_VXRXDCTL_RSCMAX(0);
> + rxdctl |= WX_VXRXDCTL_RSCEN;
> +
> + wr32(wx, WX_VXRXDCTL(reg_idx), rxdctl);
> +
> + /* pf/vf reuse */
> + wx_enable_rx_queue(wx, ring);
> + wx_alloc_rx_buffers(ring, wx_desc_unused(ring));
> +}
> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h
> new file mode 100644
> index 000000000000..43ea126b79eb
> --- /dev/null
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
> +
> +#ifndef _WX_VF_LIB_H_
> +#define _WX_VF_LIB_H_
> +
> +void wx_configure_msix_vf(struct wx *wx);
> +int wx_write_uc_addr_list_vf(struct net_device *netdev);
> +void wx_setup_psrtype_vf(struct wx *wx);
> +void wx_setup_vfmrqc_vf(struct wx *wx);
> +void wx_configure_tx_vf(struct wx *wx);
> +void wx_configure_rx_ring_vf(struct wx *wx, struct wx_ring *ring);
> +
> +#endif /* _WX_VF_LIB_H_ */
> --
> 2.30.1
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH net-next 03/12] net: libwx: add wangxun vf common api
2025-06-17 15:11 ` Simon Horman
@ 2025-06-20 8:02 ` mengyuanlou
0 siblings, 0 replies; 20+ messages in thread
From: mengyuanlou @ 2025-06-20 8:02 UTC (permalink / raw)
To: Simon Horman
Cc: netdev, kuba, pabeni, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu
> 2025年6月17日 23:11,Simon Horman <horms@kernel.org> 写道:
>
> On Wed, Jun 11, 2025 at 04:35:50PM +0800, Mengyuan Lou wrote:
>> Add common wx_configure_vf and wx_set_mac_vf for
>> ngbevf and txgbevf.
>>
>> Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
>
> ...
>
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.h b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
>
> ...
>
>> +#define WX_VXMRQC_PSR(f) FIELD_PREP(GENMASK(5, 1), f)
>> +#define WX_VXMRQC_PSR_MASK GENMASK(5, 1)
>> +#define WX_VXMRQC_PSR_L4HDR BIT(0)
>> +#define WX_VXMRQC_PSR_L3HDR BIT(1)
>> +#define WX_VXMRQC_PSR_L2HDR BIT(2)
>> +#define WX_VXMRQC_PSR_TUNHDR BIT(3)
>> +#define WX_VXMRQC_PSR_TUNMAC BIT(4)
>
> ...
>
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
>
> ...
>
>> +/**
>> + * wx_configure_tx_ring_vf - Configure Tx ring after Reset
>> + * @wx: board private structure
>> + * @ring: structure containing ring specific data
>> + *
>> + * Configure the Tx descriptor ring after a reset.
>> + **/
>> +static void wx_configure_tx_ring_vf(struct wx *wx, struct wx_ring *ring)
>> +{
>> + u8 reg_idx = ring->reg_idx;
>> + u64 tdba = ring->dma;
>> + u32 txdctl = 0;
>> + int ret;
>> +
>> + /* disable queue to avoid issues while updating state */
>> + wr32(wx, WX_VXTXDCTL(reg_idx), WX_VXTXDCTL_FLUSH);
>> + wr32(wx, WX_VXTDBAL(reg_idx), tdba & DMA_BIT_MASK(32));
>> + wr32(wx, WX_VXTDBAH(reg_idx), tdba >> 32);
>> +
>> + /* enable relaxed ordering */
>> + pcie_capability_clear_and_set_word(wx->pdev, PCI_EXP_DEVCTL,
>> + 0, PCI_EXP_DEVCTL_RELAX_EN);
>> +
>> + /* reset head and tail pointers */
>> + wr32(wx, WX_VXTDH(reg_idx), 0);
>> + wr32(wx, WX_VXTDT(reg_idx), 0);
>> + ring->tail = wx->hw_addr + WX_VXTDT(reg_idx);
>> +
>> + /* reset ntu and ntc to place SW in sync with hardwdare */
>
> nit: hardware
>
>> + ring->next_to_clean = 0;
>> + ring->next_to_use = 0;
>> +
>> + txdctl |= WX_VXTXDCTL_BUFLEN(wx_buf_len(ring->count));
>> + txdctl |= WX_VXTXDCTL_ENABLE;
>> +
>> + /* set WTHRESH to encourage burst writeback, it should not be set
>> + * higher than 1 when ITR is 0 as it could cause false TX hangs
>> + *
>> + * In order to avoid issues WTHRESH + PTHRESH should always be equal
>> + * to or less than the number of on chip descriptors, which is
>> + * currently 40.
>> + */
>> + /* reinitialize tx_buffer_info */
>> + memset(ring->tx_buffer_info, 0,
>> + sizeof(struct wx_tx_buffer) * ring->count);
>> +
>> + wr32(wx, WX_VXTXDCTL(reg_idx), txdctl);
>> + /* poll to verify queue is enabled */
>> + ret = read_poll_timeout(rd32, txdctl, txdctl & WX_VXTXDCTL_ENABLE,
>> + 1000, 10000, true, wx, WX_VXTXDCTL(reg_idx));
>> + if (ret == -ETIMEDOUT)
>> + wx_err(wx, "Could not enable Tx Queue %d\n", reg_idx);
>> +}
>
> ...
>
>> +void wx_setup_psrtype_vf(struct wx *wx)
>> +{
>> + /* PSRTYPE must be initialized */
>> + u32 psrtype = WX_VXMRQC_PSR_L2HDR |
>> + WX_VXMRQC_PSR_L3HDR |
>> + WX_VXMRQC_PSR_L4HDR |
>> + WX_VXMRQC_PSR_TUNHDR |
>> + WX_VXMRQC_PSR_TUNMAC;
>> +
>> + if (wx->num_rx_queues > 1)
>> + psrtype |= BIT(14);
>
> Here bit 14 of psrtype may be set (what is bit 14?).
There is indeed no need to set this bit here.
>
>> +
>> + wr32m(wx, WX_VXMRQC, WX_VXMRQC_PSR_MASK, WX_VXMRQC_PSR(psrtype));
>
> But WX_VXMRQC_PSR() uses a mask that limits psrtype to 5 bits.
>
> This is flagged by W=1 builds with gcc-8.5.0 on x86_64
> (but curiously not gcc-15.1.0 builds). It is flagged like this:
Thanks!
When I compiled locally, I set C=1 and W=1. I'm curious as to why this error hasn't been reported locally.
>
> CC [M] drivers/net/ethernet/wangxun/libwx/wx_vf_lib.o
> In file included from <command-line>:
> drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c: In function 'wx_setup_psrtype_vf':
> ././include/linux/compiler_types.h:568:38: error: call to '__compiletime_assert_1833' declared with attribute error: FIELD_PREP: value too large for the field
> _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
> ^
> ././include/linux/compiler_types.h:549:4: note: in definition of macro '__compiletime_assert'
> prefix ## suffix(); \
> ^~~~~~
> ././include/linux/compiler_types.h:568:2: note: in expansion of macro '_compiletime_assert'
> _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
> ^~~~~~~~~~~~~~~~~~~
> ./include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert'
> #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
> ^~~~~~~~~~~~~~~~~~
> ./include/linux/bitfield.h:68:3: note: in expansion of macro 'BUILD_BUG_ON_MSG'
> BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \
> ^~~~~~~~~~~~~~~~
> ./include/linux/bitfield.h:115:3: note: in expansion of macro '__BF_FIELD_CHECK'
> __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \
> ^~~~~~~~~~~~~~~~
> drivers/net/ethernet/wangxun/libwx/wx_vf.h:73:34: note: in expansion of macro 'FIELD_PREP'
> #define WX_VXMRQC_PSR(f) FIELD_PREP(GENMASK(5, 1), f)
> ^~~~~~~~~~
> drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c:195:43: note: in expansion of macro 'WX_VXMRQC_PSR'
> wr32m(wx, WX_VXMRQC, WX_VXMRQC_PSR_MASK, WX_VXMRQC_PSR(psrtype));
> ^~~~~~~~~~~~~
> make[7]: *** [scripts/Makefile.build:203:
> drivers/net/ethernet/wangxun/libwx/wx_vf_lib.o] Error 1:
>
>> +}
>
> ...
>
>> +void wx_configure_rx_ring_vf(struct wx *wx, struct wx_ring *ring)
>> +{
>> + u8 reg_idx = ring->reg_idx;
>> + union wx_rx_desc *rx_desc;
>> + u64 rdba = ring->dma;
>> + u32 rxdctl;
>> +
>> + /* disable queue to avoid issues while updating state */
>> + rxdctl = rd32(wx, WX_VXRXDCTL(reg_idx));
>> + wx_disable_rx_queue(wx, ring);
>> +
>> + wr32(wx, WX_VXRDBAL(reg_idx), rdba & DMA_BIT_MASK(32));
>> + wr32(wx, WX_VXRDBAH(reg_idx), rdba >> 32);
>> +
>> + /* enable relaxed ordering */
>> + pcie_capability_clear_and_set_word(wx->pdev, PCI_EXP_DEVCTL,
>> + 0, PCI_EXP_DEVCTL_RELAX_EN);
>> +
>> + /* reset head and tail pointers */
>> + wr32(wx, WX_VXRDH(reg_idx), 0);
>> + wr32(wx, WX_VXRDT(reg_idx), 0);
>> + ring->tail = wx->hw_addr + WX_VXRDT(reg_idx);
>> +
>> + /* initialize rx_buffer_info */
>> + memset(ring->rx_buffer_info, 0,
>> + sizeof(struct wx_rx_buffer) * ring->count);
>> +
>> + /* initialize Rx descriptor 0 */
>> + rx_desc = WX_RX_DESC(ring, 0);
>> + rx_desc->wb.upper.length = 0;
>> +
>> + /* reset ntu and ntc to place SW in sync with hardwdare */
>
> nit: hardware
>
>> + ring->next_to_clean = 0;
>> + ring->next_to_use = 0;
>> + ring->next_to_alloc = 0;
>> +
>> + wx_configure_srrctl_vf(wx, ring, reg_idx);
>> +
>> + /* allow any size packet since we can handle overflow */
>> + rxdctl &= ~WX_VXRXDCTL_BUFLEN_MASK;
>> + rxdctl |= WX_VXRXDCTL_BUFLEN(wx_buf_len(ring->count));
>> + rxdctl |= WX_VXRXDCTL_ENABLE | WX_VXRXDCTL_VLAN;
>> +
>> + /* enable RSC */
>> + rxdctl &= ~WX_VXRXDCTL_RSCMAX_MASK;
>> + rxdctl |= WX_VXRXDCTL_RSCMAX(0);
>> + rxdctl |= WX_VXRXDCTL_RSCEN;
>> +
>> + wr32(wx, WX_VXRXDCTL(reg_idx), rxdctl);
>> +
>> + /* pf/vf reuse */
>> + wx_enable_rx_queue(wx, ring);
>> + wx_alloc_rx_buffers(ring, wx_desc_unused(ring));
>> +}
>> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h
>> new file mode 100644
>> index 000000000000..43ea126b79eb
>> --- /dev/null
>> +++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h
>> @@ -0,0 +1,14 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
>> +
>> +#ifndef _WX_VF_LIB_H_
>> +#define _WX_VF_LIB_H_
>> +
>> +void wx_configure_msix_vf(struct wx *wx);
>> +int wx_write_uc_addr_list_vf(struct net_device *netdev);
>> +void wx_setup_psrtype_vf(struct wx *wx);
>> +void wx_setup_vfmrqc_vf(struct wx *wx);
>> +void wx_configure_tx_vf(struct wx *wx);
>> +void wx_configure_rx_ring_vf(struct wx *wx, struct wx_ring *ring);
>> +
>> +#endif /* _WX_VF_LIB_H_ */
>> --
>> 2.30.1
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH net-next 04/12] net: wangxun: add txgbevf build
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
` (2 preceding siblings ...)
2025-06-11 8:35 ` [PATCH net-next 03/12] net: libwx: add wangxun vf common api Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 05/12] net: txgbevf: add sw init pci info and reset hardware Mengyuan Lou
` (7 subsequent siblings)
11 siblings, 0 replies; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Add doc build infrastructure for txgbevf driver.
Implement the basic PCI driver loading and unloading interface.
Initialize the id_table which support 10/25/40G virtual
functions for Wangxun.
Ioremap the space of bar0 and bar4 which will be used.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
.../device_drivers/ethernet/index.rst | 1 +
.../ethernet/wangxun/txgbevf.rst | 16 ++
drivers/net/ethernet/wangxun/Kconfig | 18 ++
drivers/net/ethernet/wangxun/Makefile | 1 +
.../net/ethernet/wangxun/libwx/wx_vf_common.c | 38 +++++
.../net/ethernet/wangxun/libwx/wx_vf_common.h | 4 +
drivers/net/ethernet/wangxun/txgbevf/Makefile | 9 +
.../ethernet/wangxun/txgbevf/txgbevf_main.c | 154 ++++++++++++++++++
.../ethernet/wangxun/txgbevf/txgbevf_type.h | 20 +++
9 files changed, 261 insertions(+)
create mode 100644 Documentation/networking/device_drivers/ethernet/wangxun/txgbevf.rst
create mode 100644 drivers/net/ethernet/wangxun/txgbevf/Makefile
create mode 100644 drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
create mode 100644 drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h
diff --git a/Documentation/networking/device_drivers/ethernet/index.rst b/Documentation/networking/device_drivers/ethernet/index.rst
index 139b4c75a191..e93453410772 100644
--- a/Documentation/networking/device_drivers/ethernet/index.rst
+++ b/Documentation/networking/device_drivers/ethernet/index.rst
@@ -58,6 +58,7 @@ Contents:
ti/tlan
ti/icssg_prueth
wangxun/txgbe
+ wangxun/txgbevf
wangxun/ngbe
.. only:: subproject and html
diff --git a/Documentation/networking/device_drivers/ethernet/wangxun/txgbevf.rst b/Documentation/networking/device_drivers/ethernet/wangxun/txgbevf.rst
new file mode 100644
index 000000000000..b2f759b7b518
--- /dev/null
+++ b/Documentation/networking/device_drivers/ethernet/wangxun/txgbevf.rst
@@ -0,0 +1,16 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+===========================================================================
+Linux Base Virtual Function Driver for Wangxun(R) 10/25/40 Gigabit Ethernet
+===========================================================================
+
+WangXun 10/25/40 Gigabit Virtual Function Linux driver.
+Copyright(c) 2015 - 2025 Beijing WangXun Technology Co., Ltd.
+
+Support
+=======
+For general information, go to the website at:
+https://www.net-swift.com
+
+If you got any problem, contact Wangxun support team via nic-support@net-swift.com
+and Cc: netdev.
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index e5fc942c28cc..a6ec73e4f300 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -64,4 +64,22 @@ config TXGBE
To compile this driver as a module, choose M here. The module
will be called txgbe.
+config TXGBEVF
+ tristate "Wangxun(R) 10/25/40G Virtual Function Ethernet support"
+ depends on PCI
+ depends on PCI_MSI
+ select LIBWX
+ select PHYLINK
+ help
+ This driver supports virtual functions for SP1000A, WX1820AL,
+ WX5XXX, WX5XXXAL.
+
+ This driver was formerly named txgbevf.
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/device_drivers/ethernet/wangxun/txgbevf.rst>.
+
+ To compile this driver as a module, choose M here. MSI-X interrupt
+ support is required for this driver to work correctly.
+
endif # NET_VENDOR_WANGXUN
diff --git a/drivers/net/ethernet/wangxun/Makefile b/drivers/net/ethernet/wangxun/Makefile
index ca19311dbe38..71371d47a6ee 100644
--- a/drivers/net/ethernet/wangxun/Makefile
+++ b/drivers/net/ethernet/wangxun/Makefile
@@ -5,4 +5,5 @@
obj-$(CONFIG_LIBWX) += libwx/
obj-$(CONFIG_TXGBE) += txgbe/
+obj-$(CONFIG_TXGBEVF) += txgbevf/
obj-$(CONFIG_NGBE) += ngbe/
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
index 861adf97e801..6619a7abd1d8 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
@@ -11,6 +11,44 @@
#include "wx_vf_lib.h"
#include "wx_vf_common.h"
+int wxvf_suspend(struct device *dev_d)
+{
+ struct pci_dev *pdev = to_pci_dev(dev_d);
+ struct wx *wx = pci_get_drvdata(pdev);
+
+ netif_device_detach(wx->netdev);
+ pci_disable_device(pdev);
+
+ return 0;
+}
+EXPORT_SYMBOL(wxvf_suspend);
+
+void wxvf_shutdown(struct pci_dev *pdev)
+{
+ wxvf_suspend(&pdev->dev);
+}
+EXPORT_SYMBOL(wxvf_shutdown);
+
+int wxvf_resume(struct device *dev_d)
+{
+ struct pci_dev *pdev = to_pci_dev(dev_d);
+ struct wx *wx = pci_get_drvdata(pdev);
+
+ pci_set_master(pdev);
+ netif_device_attach(wx->netdev);
+
+ return 0;
+}
+EXPORT_SYMBOL(wxvf_resume);
+
+void wxvf_remove(struct pci_dev *pdev)
+{
+ pci_release_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM));
+ pci_disable_device(pdev);
+}
+EXPORT_SYMBOL(wxvf_remove);
+
static irqreturn_t wx_msix_misc_vf(int __always_unused irq, void *data)
{
struct wx *wx = data;
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
index 9bee9de86cb2..f3b31f33407b 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
@@ -4,6 +4,10 @@
#ifndef _WX_VF_COMMON_H_
#define _WX_VF_COMMON_H_
+int wxvf_suspend(struct device *dev_d);
+void wxvf_shutdown(struct pci_dev *pdev);
+int wxvf_resume(struct device *dev_d);
+void wxvf_remove(struct pci_dev *pdev);
int wx_request_msix_irqs_vf(struct wx *wx);
void wx_negotiate_api_vf(struct wx *wx);
void wx_reset_vf(struct wx *wx);
diff --git a/drivers/net/ethernet/wangxun/txgbevf/Makefile b/drivers/net/ethernet/wangxun/txgbevf/Makefile
new file mode 100644
index 000000000000..4c7e6de04424
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbevf/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd.
+#
+# Makefile for the Wangxun(R) 10/25/40GbE virtual functions driver
+#
+
+obj-$(CONFIG_TXGBE) += txgbevf.o
+
+txgbevf-objs := txgbevf_main.o
diff --git a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
new file mode 100644
index 000000000000..9e8ddec36913
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/etherdevice.h>
+
+#include "../libwx/wx_type.h"
+#include "../libwx/wx_vf_common.h"
+#include "txgbevf_type.h"
+
+/* txgbevf_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ * Class, Class Mask, private data (not used) }
+ */
+static const struct pci_device_id txgbevf_pci_tbl[] = {
+ { PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_SP1000), 0},
+ { PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_WX1820), 0},
+ { PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML500F), 0},
+ { PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML510F), 0},
+ { PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML5024), 0},
+ { PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML5124), 0},
+ { PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML503F), 0},
+ { PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML513F), 0},
+ /* required last entry */
+ { .device = 0 }
+};
+
+/**
+ * txgbevf_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in txgbevf_pci_tbl
+ *
+ * Return: return 0 on success, negative on failure
+ *
+ * txgbevf_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int txgbevf_probe(struct pci_dev *pdev,
+ const struct pci_device_id __always_unused *ent)
+{
+ struct net_device *netdev;
+ struct wx *wx = NULL;
+ int err;
+
+ err = pci_enable_device_mem(pdev);
+ if (err)
+ return err;
+
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (err) {
+ dev_err(&pdev->dev,
+ "No usable DMA configuration, aborting\n");
+ goto err_pci_disable_dev;
+ }
+
+ err = pci_request_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM),
+ dev_driver_string(&pdev->dev));
+ if (err) {
+ dev_err(&pdev->dev,
+ "pci_request_selected_regions failed 0x%x\n", err);
+ goto err_pci_disable_dev;
+ }
+
+ pci_set_master(pdev);
+
+ netdev = devm_alloc_etherdev_mqs(&pdev->dev,
+ sizeof(struct wx),
+ TXGBEVF_MAX_TX_QUEUES,
+ TXGBEVF_MAX_RX_QUEUES);
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_pci_release_regions;
+ }
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ wx = netdev_priv(netdev);
+ wx->netdev = netdev;
+ wx->pdev = pdev;
+
+ wx->msg_enable = netif_msg_init(-1, NETIF_MSG_DRV |
+ NETIF_MSG_PROBE | NETIF_MSG_LINK);
+ wx->hw_addr = devm_ioremap(&pdev->dev,
+ pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (!wx->hw_addr) {
+ err = -EIO;
+ goto err_pci_release_regions;
+ }
+
+ wx->b4_addr = devm_ioremap(&pdev->dev,
+ pci_resource_start(pdev, 4),
+ pci_resource_len(pdev, 4));
+ if (!wx->b4_addr) {
+ err = -EIO;
+ goto err_pci_release_regions;
+ }
+
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ pci_set_drvdata(pdev, wx);
+
+ return 0;
+
+err_pci_release_regions:
+ pci_release_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM));
+err_pci_disable_dev:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/**
+ * txgbevf_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * txgbevf_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void txgbevf_remove(struct pci_dev *pdev)
+{
+ wxvf_remove(pdev);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(txgbevf_pm_ops, wxvf_suspend, wxvf_resume);
+
+static struct pci_driver txgbevf_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = txgbevf_pci_tbl,
+ .probe = txgbevf_probe,
+ .remove = txgbevf_remove,
+ .shutdown = wxvf_shutdown,
+ /* Power Management Hooks */
+ .driver.pm = pm_sleep_ptr(&txgbevf_pm_ops)
+};
+
+module_pci_driver(txgbevf_driver);
+
+MODULE_DEVICE_TABLE(pci, txgbevf_pci_tbl);
+MODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@trustnetic.com>");
+MODULE_DESCRIPTION("WangXun(R) 10/25/40 Gigabit Virtual Function Network Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h
new file mode 100644
index 000000000000..2ba9d0cb63d5
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _TXGBEVF_TYPE_H_
+#define _TXGBEVF_TYPE_H_
+
+/* Device IDs */
+#define TXGBEVF_DEV_ID_SP1000 0x1000
+#define TXGBEVF_DEV_ID_WX1820 0x2000
+#define TXGBEVF_DEV_ID_AML500F 0x500F
+#define TXGBEVF_DEV_ID_AML510F 0x510F
+#define TXGBEVF_DEV_ID_AML5024 0x5024
+#define TXGBEVF_DEV_ID_AML5124 0x5124
+#define TXGBEVF_DEV_ID_AML503F 0x503f
+#define TXGBEVF_DEV_ID_AML513F 0x513f
+
+#define TXGBEVF_MAX_RX_QUEUES 4
+#define TXGBEVF_MAX_TX_QUEUES 4
+
+#endif /* _TXGBEVF_TYPE_H_ */
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net-next 05/12] net: txgbevf: add sw init pci info and reset hardware
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
` (3 preceding siblings ...)
2025-06-11 8:35 ` [PATCH net-next 04/12] net: wangxun: add txgbevf build Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 06/12] net: txgbevf: init interrupts and request irqs Mengyuan Lou
` (6 subsequent siblings)
11 siblings, 0 replies; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Add sw init and reset hw for txgbevf virtual functions
which initialize basic parameters, and then register netdev.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
drivers/net/ethernet/wangxun/libwx/wx_hw.c | 3 +-
.../net/ethernet/wangxun/libwx/wx_vf_common.c | 32 +++++
.../net/ethernet/wangxun/libwx/wx_vf_common.h | 2 +
.../ethernet/wangxun/txgbevf/txgbevf_main.c | 111 ++++++++++++++++++
.../ethernet/wangxun/txgbevf/txgbevf_type.h | 4 +
5 files changed, 151 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 27bb33788701..6e830436a19b 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -2369,7 +2369,8 @@ int wx_sw_init(struct wx *wx)
wx->bus.device = PCI_SLOT(pdev->devfn);
wx->bus.func = PCI_FUNC(pdev->devfn);
- if (wx->oem_svid == PCI_VENDOR_ID_WANGXUN) {
+ if (wx->oem_svid == PCI_VENDOR_ID_WANGXUN ||
+ pdev->is_virtfn) {
wx->subsystem_vendor_id = pdev->subsystem_vendor;
wx->subsystem_device_id = pdev->subsystem_device;
} else {
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
index 6619a7abd1d8..88e9ceeeecb9 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
@@ -43,6 +43,14 @@ EXPORT_SYMBOL(wxvf_resume);
void wxvf_remove(struct pci_dev *pdev)
{
+ struct wx *wx = pci_get_drvdata(pdev);
+ struct net_device *netdev;
+
+ netdev = wx->netdev;
+ unregister_netdev(netdev);
+ kfree(wx->vfinfo);
+ kfree(wx->rss_key);
+ kfree(wx->mac_table);
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
pci_disable_device(pdev);
@@ -230,3 +238,27 @@ int wx_set_mac_vf(struct net_device *netdev, void *p)
return 0;
}
EXPORT_SYMBOL(wx_set_mac_vf);
+
+int wxvf_open(struct net_device *netdev)
+{
+ return 0;
+}
+EXPORT_SYMBOL(wxvf_open);
+
+static void wxvf_down(struct wx *wx)
+{
+ struct net_device *netdev = wx->netdev;
+
+ netif_tx_disable(netdev);
+ wx_reset_vf(wx);
+}
+
+int wxvf_close(struct net_device *netdev)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ wxvf_down(wx);
+
+ return 0;
+}
+EXPORT_SYMBOL(wxvf_close);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
index f3b31f33407b..272743a3c878 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
@@ -14,5 +14,7 @@ void wx_reset_vf(struct wx *wx);
void wx_set_rx_mode_vf(struct net_device *netdev);
void wx_configure_vf(struct wx *wx);
int wx_set_mac_vf(struct net_device *netdev, void *p);
+int wxvf_open(struct net_device *netdev);
+int wxvf_close(struct net_device *netdev);
#endif /* _WX_VF_COMMON_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
index 9e8ddec36913..9918d5b2ee57 100644
--- a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
+++ b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
@@ -9,6 +9,9 @@
#include <linux/etherdevice.h>
#include "../libwx/wx_type.h"
+#include "../libwx/wx_hw.h"
+#include "../libwx/wx_mbx.h"
+#include "../libwx/wx_vf.h"
#include "../libwx/wx_vf_common.h"
#include "txgbevf_type.h"
@@ -33,6 +36,96 @@ static const struct pci_device_id txgbevf_pci_tbl[] = {
{ .device = 0 }
};
+static const struct net_device_ops txgbevf_netdev_ops = {
+ .ndo_open = wxvf_open,
+ .ndo_stop = wxvf_close,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = wx_set_mac_vf,
+};
+
+static void txgbevf_init_type_code(struct wx *wx)
+{
+ switch (wx->device_id) {
+ case TXGBEVF_DEV_ID_SP1000:
+ case TXGBEVF_DEV_ID_WX1820:
+ wx->mac.type = wx_mac_sp;
+ break;
+ case TXGBEVF_DEV_ID_AML500F:
+ case TXGBEVF_DEV_ID_AML510F:
+ case TXGBEVF_DEV_ID_AML5024:
+ case TXGBEVF_DEV_ID_AML5124:
+ case TXGBEVF_DEV_ID_AML503F:
+ case TXGBEVF_DEV_ID_AML513F:
+ wx->mac.type = wx_mac_aml;
+ break;
+ default:
+ wx->mac.type = wx_mac_unknown;
+ break;
+ }
+}
+
+static int txgbevf_sw_init(struct wx *wx)
+{
+ struct net_device *netdev = wx->netdev;
+ struct pci_dev *pdev = wx->pdev;
+ int err;
+
+ /* Initialize pcie info and common capability flags */
+ err = wx_sw_init(wx);
+ if (err < 0)
+ goto err_wx_sw_init;
+
+ /* Initialize the mailbox */
+ err = wx_init_mbx_params_vf(wx);
+ if (err)
+ goto err_init_mbx_params;
+
+ /* Initialize the device type */
+ txgbevf_init_type_code(wx);
+ /* lock to protect mailbox accesses */
+ spin_lock_init(&wx->mbx.mbx_lock);
+
+ err = wx_reset_hw_vf(wx);
+ if (err) {
+ wx_err(wx, "PF still in reset state. Is the PF interface up?\n");
+ goto err_reset_hw;
+ }
+ wx_init_hw_vf(wx);
+ wx_negotiate_api_vf(wx);
+ if (is_zero_ether_addr(wx->mac.addr))
+ dev_info(&pdev->dev,
+ "MAC address not assigned by administrator.\n");
+ eth_hw_addr_set(netdev, wx->mac.addr);
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ dev_info(&pdev->dev, "Assigning random MAC address\n");
+ eth_hw_addr_random(netdev);
+ ether_addr_copy(wx->mac.addr, netdev->dev_addr);
+ ether_addr_copy(wx->mac.perm_addr, netdev->dev_addr);
+ }
+
+ wx->mac.max_tx_queues = TXGBEVF_MAX_TX_QUEUES;
+ wx->mac.max_rx_queues = TXGBEVF_MAX_RX_QUEUES;
+ /* Enable dynamic interrupt throttling rates */
+ wx->rx_itr_setting = 1;
+ wx->tx_itr_setting = 1;
+ /* set default ring sizes */
+ wx->tx_ring_count = TXGBEVF_DEFAULT_TXD;
+ wx->rx_ring_count = TXGBEVF_DEFAULT_RXD;
+ /* set default work limits */
+ wx->tx_work_limit = TXGBEVF_DEFAULT_TX_WORK;
+ wx->rx_work_limit = TXGBEVF_DEFAULT_RX_WORK;
+
+ return 0;
+err_reset_hw:
+ kfree(wx->vfinfo);
+err_init_mbx_params:
+ kfree(wx->rss_key);
+ kfree(wx->mac_table);
+err_wx_sw_init:
+ return err;
+}
+
/**
* txgbevf_probe - Device Initialization Routine
* @pdev: PCI device information struct
@@ -106,12 +199,30 @@ static int txgbevf_probe(struct pci_dev *pdev,
goto err_pci_release_regions;
}
+ netdev->netdev_ops = &txgbevf_netdev_ops;
+
+ /* setup the private structure */
+ err = txgbevf_sw_init(wx);
+ if (err)
+ goto err_pci_release_regions;
+
netdev->features |= NETIF_F_HIGHDMA;
+ eth_hw_addr_set(netdev, wx->mac.perm_addr);
+ ether_addr_copy(netdev->perm_addr, wx->mac.addr);
+
+ err = register_netdev(netdev);
+ if (err)
+ goto err_register;
+
pci_set_drvdata(pdev, wx);
return 0;
+err_register:
+ kfree(wx->vfinfo);
+ kfree(wx->rss_key);
+ kfree(wx->mac_table);
err_pci_release_regions:
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
diff --git a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h
index 2ba9d0cb63d5..8f4f08ce06c0 100644
--- a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h
+++ b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h
@@ -16,5 +16,9 @@
#define TXGBEVF_MAX_RX_QUEUES 4
#define TXGBEVF_MAX_TX_QUEUES 4
+#define TXGBEVF_DEFAULT_TXD 128
+#define TXGBEVF_DEFAULT_RXD 128
+#define TXGBEVF_DEFAULT_TX_WORK 256
+#define TXGBEVF_DEFAULT_RX_WORK 256
#endif /* _TXGBEVF_TYPE_H_ */
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net-next 06/12] net: txgbevf: init interrupts and request irqs
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
` (4 preceding siblings ...)
2025-06-11 8:35 ` [PATCH net-next 05/12] net: txgbevf: add sw init pci info and reset hardware Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-11 22:39 ` kernel test robot
2025-06-11 8:35 ` [PATCH net-next 07/12] net: txgbevf: Support Rx and Tx process path Mengyuan Lou
` (5 subsequent siblings)
11 siblings, 1 reply; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Add irq alloc flow functions for vf.
Alloc pcie msix irqs for drivers and request_irq for tx/rx rings
and misc other events.
If the application is successful, config vertors for interrupts.
Enable interrupts mask in wxvf_irq_enable.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
drivers/net/ethernet/wangxun/libwx/wx_hw.c | 6 +++
drivers/net/ethernet/wangxun/libwx/wx_lib.c | 29 +++++++++---
drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 +
.../net/ethernet/wangxun/libwx/wx_vf_common.c | 35 ++++++++++++++
.../ethernet/wangxun/txgbevf/txgbevf_main.c | 47 +++++++++++++++++++
.../ethernet/wangxun/txgbevf/txgbevf_type.h | 2 +
6 files changed, 113 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 6e830436a19b..fe358a6329fa 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -11,6 +11,7 @@
#include "wx_type.h"
#include "wx_lib.h"
#include "wx_sriov.h"
+#include "wx_vf.h"
#include "wx_hw.h"
static int wx_phy_read_reg_mdi(struct mii_bus *bus, int phy_addr, int devnum, int regnum)
@@ -124,6 +125,11 @@ void wx_intr_enable(struct wx *wx, u64 qmask)
{
u32 mask;
+ if (wx->pdev->is_virtfn) {
+ wr32(wx, WX_VXIMC, qmask >> 1);
+ return;
+ }
+
mask = (qmask & U32_MAX);
if (mask)
wr32(wx, WX_PX_IMC(0), mask);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index 5c747509d56b..8c0ee4ed9601 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -1783,12 +1783,22 @@ static int wx_acquire_msix_vectors(struct wx *wx)
return nvecs;
}
- wx->msix_entry->entry = 0;
- wx->msix_entry->vector = pci_irq_vector(wx->pdev, 0);
nvecs -= 1;
- for (i = 0; i < nvecs; i++) {
- wx->msix_q_entries[i].entry = i;
- wx->msix_q_entries[i].vector = pci_irq_vector(wx->pdev, i + 1);
+ /* VF has a fixed interrupt mapping. */
+ if (wx->pdev->is_virtfn) {
+ for (i = 0; i < nvecs; i++) {
+ wx->msix_q_entries[i].entry = i;
+ wx->msix_q_entries[i].vector = pci_irq_vector(wx->pdev, i);
+ }
+ wx->msix_entry->entry = i;
+ wx->msix_entry->vector = pci_irq_vector(wx->pdev, i);
+ } else {
+ wx->msix_entry->entry = 0;
+ wx->msix_entry->vector = pci_irq_vector(wx->pdev, 0);
+ for (i = 0; i < nvecs; i++) {
+ wx->msix_q_entries[i].entry = i;
+ wx->msix_q_entries[i].vector = pci_irq_vector(wx->pdev, i + 1);
+ }
}
wx->num_q_vectors = nvecs;
@@ -1810,7 +1820,7 @@ static int wx_set_interrupt_capability(struct wx *wx)
/* We will try to get MSI-X interrupts first */
ret = wx_acquire_msix_vectors(wx);
- if (ret == 0 || (ret == -ENOMEM))
+ if (ret == 0 || (ret == -ENOMEM) || pdev->is_virtfn)
return ret;
/* Disable VMDq support */
@@ -2161,7 +2171,12 @@ int wx_init_interrupt_scheme(struct wx *wx)
int ret;
/* Number of supported queues */
- wx_set_num_queues(wx);
+ if (wx->pdev->is_virtfn) {
+ if (wx->set_num_queues)
+ wx->set_num_queues(wx);
+ } else {
+ wx_set_num_queues(wx);
+ }
/* Set interrupt mode */
ret = wx_set_interrupt_capability(wx);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 63bb7785fd19..ba5608416c4e 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -1323,6 +1323,7 @@ struct wx {
int (*setup_tc)(struct net_device *netdev, u8 tc);
void (*do_reset)(struct net_device *netdev);
int (*ptp_setup_sdp)(struct wx *wx);
+ void (*set_num_queues)(struct wx *wx);
bool pps_enabled;
u64 pps_width;
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
index 88e9ceeeecb9..c01ff91a057d 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
@@ -17,6 +17,7 @@ int wxvf_suspend(struct device *dev_d)
struct wx *wx = pci_get_drvdata(pdev);
netif_device_detach(wx->netdev);
+ wx_clear_interrupt_scheme(wx);
pci_disable_device(pdev);
return 0;
@@ -35,6 +36,7 @@ int wxvf_resume(struct device *dev_d)
struct wx *wx = pci_get_drvdata(pdev);
pci_set_master(pdev);
+ wx_init_interrupt_scheme(wx);
netif_device_attach(wx->netdev);
return 0;
@@ -51,6 +53,7 @@ void wxvf_remove(struct pci_dev *pdev)
kfree(wx->vfinfo);
kfree(wx->rss_key);
kfree(wx->mac_table);
+ wx_clear_interrupt_scheme(wx);
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
pci_disable_device(pdev);
@@ -239,9 +242,35 @@ int wx_set_mac_vf(struct net_device *netdev, void *p)
}
EXPORT_SYMBOL(wx_set_mac_vf);
+static void wxvf_irq_enable(struct wx *wx)
+{
+ wr32(wx, WX_VXIMC, wx->eims_enable_mask);
+}
+
+static void wxvf_up_complete(struct wx *wx)
+{
+ wx_configure_msix_vf(wx);
+
+ /* clear any pending interrupts, may auto mask */
+ wr32(wx, WX_VXICR, U32_MAX);
+ wxvf_irq_enable(wx);
+}
+
int wxvf_open(struct net_device *netdev)
{
+ struct wx *wx = netdev_priv(netdev);
+ int err;
+
+ err = wx_request_msix_irqs_vf(wx);
+ if (err)
+ goto err_reset;
+
+ wxvf_up_complete(wx);
+
return 0;
+err_reset:
+ wx_reset_vf(wx);
+ return err;
}
EXPORT_SYMBOL(wxvf_open);
@@ -249,8 +278,13 @@ static void wxvf_down(struct wx *wx)
{
struct net_device *netdev = wx->netdev;
+ netif_tx_stop_all_queues(netdev);
netif_tx_disable(netdev);
+ wx_napi_disable_all(wx);
wx_reset_vf(wx);
+
+ wx_clean_all_tx_rings(wx);
+ wx_clean_all_rx_rings(wx);
}
int wxvf_close(struct net_device *netdev)
@@ -258,6 +292,7 @@ int wxvf_close(struct net_device *netdev)
struct wx *wx = netdev_priv(netdev);
wxvf_down(wx);
+ wx_free_irq(wx);
return 0;
}
diff --git a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
index 9918d5b2ee57..64f171423b23 100644
--- a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
+++ b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
@@ -10,6 +10,7 @@
#include "../libwx/wx_type.h"
#include "../libwx/wx_hw.h"
+#include "../libwx/wx_lib.h"
#include "../libwx/wx_mbx.h"
#include "../libwx/wx_vf.h"
#include "../libwx/wx_vf_common.h"
@@ -43,6 +44,42 @@ static const struct net_device_ops txgbevf_netdev_ops = {
.ndo_set_mac_address = wx_set_mac_vf,
};
+static void txgbevf_set_num_queues(struct wx *wx)
+{
+ u32 def_q = 0, num_tcs = 0;
+ u16 rss, queue;
+ int ret = 0;
+
+ /* Start with base case */
+ wx->num_rx_queues = 1;
+ wx->num_tx_queues = 1;
+
+ spin_lock_bh(&wx->mbx.mbx_lock);
+ /* fetch queue configuration from the PF */
+ ret = wx_get_queues_vf(wx, &num_tcs, &def_q);
+ spin_unlock_bh(&wx->mbx.mbx_lock);
+
+ if (ret)
+ return;
+
+ /* we need as many queues as traffic classes */
+ if (num_tcs > 1) {
+ wx->num_rx_queues = num_tcs;
+ } else {
+ rss = min_t(u16, num_online_cpus(), TXGBEVF_MAX_RSS_NUM);
+ queue = min_t(u16, wx->mac.max_rx_queues, wx->mac.max_tx_queues);
+ rss = min_t(u16, queue, rss);
+
+ switch (wx->vfinfo->vf_api) {
+ case wx_mbox_api_13:
+ wx->num_rx_queues = rss;
+ wx->num_tx_queues = rss;
+ default:
+ break;
+ }
+ }
+}
+
static void txgbevf_init_type_code(struct wx *wx)
{
switch (wx->device_id) {
@@ -80,6 +117,8 @@ static int txgbevf_sw_init(struct wx *wx)
if (err)
goto err_init_mbx_params;
+ /* max q_vectors */
+ wx->mac.max_msix_vectors = TXGBEVF_MAX_MSIX_VECTORS;
/* Initialize the device type */
txgbevf_init_type_code(wx);
/* lock to protect mailbox accesses */
@@ -116,6 +155,8 @@ static int txgbevf_sw_init(struct wx *wx)
wx->tx_work_limit = TXGBEVF_DEFAULT_TX_WORK;
wx->rx_work_limit = TXGBEVF_DEFAULT_RX_WORK;
+ wx->set_num_queues = txgbevf_set_num_queues;
+
return 0;
err_reset_hw:
kfree(wx->vfinfo);
@@ -211,6 +252,10 @@ static int txgbevf_probe(struct pci_dev *pdev,
eth_hw_addr_set(netdev, wx->mac.perm_addr);
ether_addr_copy(netdev->perm_addr, wx->mac.addr);
+ err = wx_init_interrupt_scheme(wx);
+ if (err)
+ goto err_free_sw_init;
+
err = register_netdev(netdev);
if (err)
goto err_register;
@@ -220,6 +265,8 @@ static int txgbevf_probe(struct pci_dev *pdev,
return 0;
err_register:
+ wx_clear_interrupt_scheme(wx);
+err_free_sw_init:
kfree(wx->vfinfo);
kfree(wx->rss_key);
kfree(wx->mac_table);
diff --git a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h
index 8f4f08ce06c0..1364d2b58bb0 100644
--- a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h
+++ b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_type.h
@@ -14,6 +14,8 @@
#define TXGBEVF_DEV_ID_AML503F 0x503f
#define TXGBEVF_DEV_ID_AML513F 0x513f
+#define TXGBEVF_MAX_MSIX_VECTORS 2
+#define TXGBEVF_MAX_RSS_NUM 4
#define TXGBEVF_MAX_RX_QUEUES 4
#define TXGBEVF_MAX_TX_QUEUES 4
#define TXGBEVF_DEFAULT_TXD 128
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH net-next 06/12] net: txgbevf: init interrupts and request irqs
2025-06-11 8:35 ` [PATCH net-next 06/12] net: txgbevf: init interrupts and request irqs Mengyuan Lou
@ 2025-06-11 22:39 ` kernel test robot
0 siblings, 0 replies; 20+ messages in thread
From: kernel test robot @ 2025-06-11 22:39 UTC (permalink / raw)
To: Mengyuan Lou, netdev
Cc: llvm, oe-kbuild-all, kuba, pabeni, horms, andrew+netdev,
duanqiangwen, linglingzhang, jiawenwu, Mengyuan Lou
Hi Mengyuan,
kernel test robot noticed the following build warnings:
[auto build test WARNING on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Mengyuan-Lou/net-libwx-add-mailbox-api-for-wangxun-vf-drivers/20250611-165134
base: net-next/main
patch link: https://lore.kernel.org/r/20250611083559.14175-7-mengyuanlou%40net-swift.com
patch subject: [PATCH net-next 06/12] net: txgbevf: init interrupts and request irqs
config: s390-allmodconfig (https://download.01.org/0day-ci/archive/20250612/202506120658.JRvrXNTk-lkp@intel.com/config)
compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250612/202506120658.JRvrXNTk-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202506120658.JRvrXNTk-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c:77:3: warning: unannotated fall-through between switch labels [-Wimplicit-fallthrough]
77 | default:
| ^
drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c:77:3: note: insert 'break;' to avoid fall-through
77 | default:
| ^
| break;
1 warning generated.
vim +77 drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
46
47 static void txgbevf_set_num_queues(struct wx *wx)
48 {
49 u32 def_q = 0, num_tcs = 0;
50 u16 rss, queue;
51 int ret = 0;
52
53 /* Start with base case */
54 wx->num_rx_queues = 1;
55 wx->num_tx_queues = 1;
56
57 spin_lock_bh(&wx->mbx.mbx_lock);
58 /* fetch queue configuration from the PF */
59 ret = wx_get_queues_vf(wx, &num_tcs, &def_q);
60 spin_unlock_bh(&wx->mbx.mbx_lock);
61
62 if (ret)
63 return;
64
65 /* we need as many queues as traffic classes */
66 if (num_tcs > 1) {
67 wx->num_rx_queues = num_tcs;
68 } else {
69 rss = min_t(u16, num_online_cpus(), TXGBEVF_MAX_RSS_NUM);
70 queue = min_t(u16, wx->mac.max_rx_queues, wx->mac.max_tx_queues);
71 rss = min_t(u16, queue, rss);
72
73 switch (wx->vfinfo->vf_api) {
74 case wx_mbox_api_13:
75 wx->num_rx_queues = rss;
76 wx->num_tx_queues = rss;
> 77 default:
78 break;
79 }
80 }
81 }
82
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH net-next 07/12] net: txgbevf: Support Rx and Tx process path
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
` (5 preceding siblings ...)
2025-06-11 8:35 ` [PATCH net-next 06/12] net: txgbevf: init interrupts and request irqs Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 08/12] net: txgbevf: add phylink check flow Mengyuan Lou
` (4 subsequent siblings)
11 siblings, 0 replies; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Improve the configuration of Rx and Tx ring.
Setup and alloc resources.
Configure Rx and Tx unit on hardware.
Add .ndo_start_xmit support and start all queues.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
.../net/ethernet/wangxun/libwx/wx_vf_common.c | 25 ++++++++++++++++++-
.../ethernet/wangxun/txgbevf/txgbevf_main.c | 2 ++
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
index c01ff91a057d..51c93364aaf1 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
@@ -250,10 +250,14 @@ static void wxvf_irq_enable(struct wx *wx)
static void wxvf_up_complete(struct wx *wx)
{
wx_configure_msix_vf(wx);
+ smp_mb__before_atomic();
+ wx_napi_enable_all(wx);
/* clear any pending interrupts, may auto mask */
wr32(wx, WX_VXICR, U32_MAX);
wxvf_irq_enable(wx);
+ /* enable transmits */
+ netif_tx_start_all_queues(wx->netdev);
}
int wxvf_open(struct net_device *netdev)
@@ -261,13 +265,31 @@ int wxvf_open(struct net_device *netdev)
struct wx *wx = netdev_priv(netdev);
int err;
- err = wx_request_msix_irqs_vf(wx);
+ err = wx_setup_resources(wx);
if (err)
goto err_reset;
+ wx_configure_vf(wx);
+
+ err = wx_request_msix_irqs_vf(wx);
+ if (err)
+ goto err_free_resources;
+
+ /* Notify the stack of the actual queue counts. */
+ err = netif_set_real_num_tx_queues(netdev, wx->num_tx_queues);
+ if (err)
+ goto err_free_irq;
+
+ err = netif_set_real_num_rx_queues(netdev, wx->num_rx_queues);
+ if (err)
+ goto err_free_irq;
wxvf_up_complete(wx);
return 0;
+err_free_irq:
+ wx_free_irq(wx);
+err_free_resources:
+ wx_free_resources(wx);
err_reset:
wx_reset_vf(wx);
return err;
@@ -293,6 +315,7 @@ int wxvf_close(struct net_device *netdev)
wxvf_down(wx);
wx_free_irq(wx);
+ wx_free_resources(wx);
return 0;
}
diff --git a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
index 64f171423b23..448513cf882c 100644
--- a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
+++ b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
@@ -40,6 +40,7 @@ static const struct pci_device_id txgbevf_pci_tbl[] = {
static const struct net_device_ops txgbevf_netdev_ops = {
.ndo_open = wxvf_open,
.ndo_stop = wxvf_close,
+ .ndo_start_xmit = wx_xmit_frame,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = wx_set_mac_vf,
};
@@ -261,6 +262,7 @@ static int txgbevf_probe(struct pci_dev *pdev,
goto err_register;
pci_set_drvdata(pdev, wx);
+ netif_tx_stop_all_queues(netdev);
return 0;
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net-next 08/12] net: txgbevf: add phylink check flow
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
` (6 preceding siblings ...)
2025-06-11 8:35 ` [PATCH net-next 07/12] net: txgbevf: Support Rx and Tx process path Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 09/12] net: wangxun: add ngbevf build Mengyuan Lou
` (3 subsequent siblings)
11 siblings, 0 replies; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Add phylink support to wangxun 10/25/40G virtual functions.
Get link status from pf in mbox, and if it is failed then
check the vx_status, because vx_status switching is too slow.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
drivers/net/ethernet/wangxun/libwx/wx_vf.c | 121 ++++++++++++++++++
drivers/net/ethernet/wangxun/libwx/wx_vf.h | 14 ++
.../net/ethernet/wangxun/libwx/wx_vf_common.c | 43 +++++++
.../net/ethernet/wangxun/libwx/wx_vf_common.h | 9 ++
.../ethernet/wangxun/txgbevf/txgbevf_main.c | 88 +++++++++++++
5 files changed, 275 insertions(+)
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.c b/drivers/net/ethernet/wangxun/libwx/wx_vf.c
index a211329fd71a..cba6641a4c7b 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.c
@@ -519,3 +519,124 @@ int wx_get_queues_vf(struct wx *wx, u32 *num_tcs, u32 *default_tc)
return ret;
}
EXPORT_SYMBOL(wx_get_queues_vf);
+
+static int wx_get_link_status_from_pf(struct wx *wx, u32 *msgbuf)
+{
+ u32 links_reg = msgbuf[1];
+
+ if (msgbuf[1] & WX_PF_NOFITY_VF_NET_NOT_RUNNING)
+ wx->notify_down = true;
+ else
+ wx->notify_down = false;
+
+ if (wx->notify_down) {
+ wx->link = false;
+ wx->speed = SPEED_UNKNOWN;
+ return 0;
+ }
+
+ wx->link = WX_PFLINK_STATUS(links_reg);
+ wx->speed = WX_PFLINK_SPEED(links_reg);
+
+ return 0;
+}
+
+static int wx_pf_ping_vf(struct wx *wx, u32 *msgbuf)
+{
+ if (!(msgbuf[0] & WX_VT_MSGTYPE_CTS))
+ /* msg is not CTS, we need to do reset */
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct wx_link_reg_fields wx_speed_lookup_vf[] = {
+ {wx_mac_unknown},
+ {wx_mac_sp, SPEED_10000, SPEED_1000, SPEED_100, SPEED_UNKNOWN, SPEED_UNKNOWN},
+ {wx_mac_em, SPEED_1000, SPEED_100, SPEED_10, SPEED_UNKNOWN, SPEED_UNKNOWN},
+ {wx_mac_aml, SPEED_40000, SPEED_25000, SPEED_10000, SPEED_1000, SPEED_UNKNOWN},
+ {wx_mac_aml40, SPEED_40000, SPEED_25000, SPEED_10000, SPEED_1000, SPEED_UNKNOWN},
+};
+
+static void wx_check_physical_link(struct wx *wx, u32 link_val)
+{
+ wx->link = true;
+
+ switch (WX_VXSTATUS_SPEED(link_val)) {
+ case BIT(0):
+ wx->speed = wx_speed_lookup_vf[wx->mac.type].bit0_f;
+ break;
+ case BIT(1):
+ wx->speed = wx_speed_lookup_vf[wx->mac.type].bit1_f;
+ break;
+ case BIT(2):
+ wx->speed = wx_speed_lookup_vf[wx->mac.type].bit2_f;
+ break;
+ case BIT(3):
+ wx->speed = wx_speed_lookup_vf[wx->mac.type].bit3_f;
+ break;
+ case BIT(4):
+ default:
+ wx->speed = SPEED_UNKNOWN;
+ break;
+ }
+
+ if (wx->speed == SPEED_UNKNOWN)
+ wx->link = false;
+}
+
+int wx_check_mac_link_vf(struct wx *wx)
+{
+ struct wx_mbx_info *mbx = &wx->mbx;
+ u32 val, msgbuf[2] = {0};
+ int ret = 0;
+
+ /* If we were hit with a reset drop the link */
+ if (!wx_check_for_rst_vf(wx) || !mbx->timeout)
+ goto out;
+
+ if (!wx_check_for_msg_vf(wx))
+ ret = wx_read_mbx_vf(wx, msgbuf, 2);
+ if (ret)
+ goto out;
+
+ switch (msgbuf[0] & GENMASK(8, 0)) {
+ case WX_PF_NOFITY_VF_LINK_STATUS | WX_PF_CONTROL_MSG:
+ ret = wx_get_link_status_from_pf(wx, msgbuf);
+ goto out;
+ case WX_PF_CONTROL_MSG:
+ ret = wx_pf_ping_vf(wx, msgbuf);
+ goto out;
+ default:
+ break;
+ }
+
+ /* get link status from hw status reg */
+ /* for SFP+ modules and DA cables, it can take up to 500usecs
+ * before the link status is correct
+ */
+ ret = read_poll_timeout_atomic(rd32, val, val & BIT(0), 100,
+ 500, false, wx, WX_VXSTATUS);
+ if (ret)
+ goto out;
+
+ /* check link status */
+ wx_check_physical_link(wx, val);
+
+ if (!(msgbuf[0] & WX_VT_MSGTYPE_CTS)) {
+ /* msg is not CTS and is NACK we must have lost CTS status */
+ if (msgbuf[0] & WX_VT_MSGTYPE_NACK)
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* the pf is talking, if we timed out in the past we reinit */
+ if (!mbx->timeout) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(wx_check_mac_link_vf);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf.h b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
index 3bb70421622a..59bb4aa1ec93 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf.h
@@ -90,6 +90,19 @@
#define WX_VXMRQC_RSS_EN BIT(8)
#define WX_VXMRQC_RSS_HASH(f) FIELD_PREP(GENMASK(15, 13), f)
+#define WX_PFLINK_STATUS(g) FIELD_GET(BIT(0), g)
+#define WX_PFLINK_SPEED(g) FIELD_GET(GENMASK(31, 1), g)
+#define WX_VXSTATUS_SPEED(g) FIELD_GET(GENMASK(4, 1), g)
+
+struct wx_link_reg_fields {
+ u32 mac_type;
+ u32 bit0_f;
+ u32 bit1_f;
+ u32 bit2_f;
+ u32 bit3_f;
+ u32 bit4_f;
+};
+
void wx_start_hw_vf(struct wx *wx);
void wx_init_hw_vf(struct wx *wx);
int wx_reset_hw_vf(struct wx *wx);
@@ -106,5 +119,6 @@ int wx_update_xcast_mode_vf(struct wx *wx, int xcast_mode);
int wx_get_link_state_vf(struct wx *wx, u16 *link_state);
int wx_set_vfta_vf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on,
bool vlvf_bypass);
+int wx_check_mac_link_vf(struct wx *wx);
#endif /* _WX_VF_H_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
index 51c93364aaf1..c14d8fbcf990 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.c
@@ -53,6 +53,7 @@ void wxvf_remove(struct pci_dev *pdev)
kfree(wx->vfinfo);
kfree(wx->rss_key);
kfree(wx->mac_table);
+ phylink_destroy(wx->phylink);
wx_clear_interrupt_scheme(wx);
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
@@ -64,6 +65,7 @@ static irqreturn_t wx_msix_misc_vf(int __always_unused irq, void *data)
{
struct wx *wx = data;
+ phylink_mac_change(wx->phylink, wx->link);
/* Clear the interrupt */
if (netif_running(wx->netdev))
wr32(wx, WX_VXIMC, wx->eims_other);
@@ -242,6 +244,23 @@ int wx_set_mac_vf(struct net_device *netdev, void *p)
}
EXPORT_SYMBOL(wx_set_mac_vf);
+void wx_get_mac_link_vf(struct phylink_config *config,
+ struct phylink_link_state *state)
+{
+ struct wx *wx = phylink_to_wx(config);
+ int err;
+
+ spin_lock_bh(&wx->mbx.mbx_lock);
+ err = wx_check_mac_link_vf(wx);
+ spin_unlock_bh(&wx->mbx.mbx_lock);
+ if (err)
+ return;
+
+ state->link = wx->link;
+ state->speed = wx->speed;
+}
+EXPORT_SYMBOL(wx_get_mac_link_vf);
+
static void wxvf_irq_enable(struct wx *wx)
{
wr32(wx, WX_VXIMC, wx->eims_enable_mask);
@@ -258,6 +277,7 @@ static void wxvf_up_complete(struct wx *wx)
wxvf_irq_enable(wx);
/* enable transmits */
netif_tx_start_all_queues(wx->netdev);
+ phylink_start(wx->phylink);
}
int wxvf_open(struct net_device *netdev)
@@ -300,6 +320,7 @@ static void wxvf_down(struct wx *wx)
{
struct net_device *netdev = wx->netdev;
+ phylink_stop(wx->phylink);
netif_tx_stop_all_queues(netdev);
netif_tx_disable(netdev);
wx_napi_disable_all(wx);
@@ -320,3 +341,25 @@ int wxvf_close(struct net_device *netdev)
return 0;
}
EXPORT_SYMBOL(wxvf_close);
+
+void wxvf_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
+{
+}
+EXPORT_SYMBOL(wxvf_mac_config);
+
+void wxvf_mac_link_down(struct phylink_config *config,
+ unsigned int mode, phy_interface_t interface)
+{
+ struct wx *wx = phylink_to_wx(config);
+
+ wx->speed = SPEED_UNKNOWN;
+}
+EXPORT_SYMBOL(wxvf_mac_link_down);
+
+void wxvf_mac_link_up(struct phylink_config *config, struct phy_device *phy,
+ unsigned int mode, phy_interface_t interface,
+ int speed, int duplex, bool tx_pause, bool rx_pause)
+{
+}
+EXPORT_SYMBOL(wxvf_mac_link_up);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
index 272743a3c878..946a61bd4c3e 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_vf_common.h
@@ -14,7 +14,16 @@ void wx_reset_vf(struct wx *wx);
void wx_set_rx_mode_vf(struct net_device *netdev);
void wx_configure_vf(struct wx *wx);
int wx_set_mac_vf(struct net_device *netdev, void *p);
+void wx_get_mac_link_vf(struct phylink_config *config,
+ struct phylink_link_state *state);
int wxvf_open(struct net_device *netdev);
int wxvf_close(struct net_device *netdev);
+void wxvf_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state);
+void wxvf_mac_link_down(struct phylink_config *config, unsigned int mode,
+ phy_interface_t interface);
+void wxvf_mac_link_up(struct phylink_config *config, struct phy_device *phy,
+ unsigned int mode, phy_interface_t interface,
+ int speed, int duplex, bool tx_pause, bool rx_pause);
#endif /* _WX_VF_COMMON_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
index 448513cf882c..5a8eb8856a87 100644
--- a/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
+++ b/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c
@@ -37,6 +37,88 @@ static const struct pci_device_id txgbevf_pci_tbl[] = {
{ .device = 0 }
};
+static const struct phylink_mac_ops txgbevf_mac_ops = {
+ .mac_config = wxvf_mac_config,
+ .mac_link_down = wxvf_mac_link_down,
+ .mac_link_up = wxvf_mac_link_up,
+};
+
+static int txgbevf_interface_max_speed(phy_interface_t interface)
+{
+ switch (interface) {
+ case PHY_INTERFACE_MODE_10GBASER:
+ return SPEED_10000;
+ case PHY_INTERFACE_MODE_25GBASER:
+ return SPEED_25000;
+ case PHY_INTERFACE_MODE_XLGMII:
+ return SPEED_40000;
+ default:
+ /* No idea! Garbage in, unknown out */
+ return SPEED_UNKNOWN;
+ }
+
+ return SPEED_UNKNOWN;
+}
+
+static int txgbevf_phylink_init(struct wx *wx)
+{
+ struct phylink_link_state link_state;
+ struct phylink_config *phy_config;
+ phy_interface_t phy_mode;
+ struct phylink *phylink;
+ int err;
+
+ phy_config = &wx->phylink_config;
+ phy_config->dev = &wx->netdev->dev;
+ phy_config->type = PHYLINK_NETDEV;
+ phy_config->mac_capabilities = MAC_40000FD | MAC_25000FD | MAC_10000FD |
+ MAC_1000FD | MAC_100FD | MAC_10FD;
+ phy_config->get_fixed_state = wx_get_mac_link_vf;
+
+ if (wx->mac.type == wx_mac_aml40) {
+ phy_mode = PHY_INTERFACE_MODE_XLGMII;
+ __set_bit(PHY_INTERFACE_MODE_XLGMII,
+ phy_config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_10GBASER,
+ phy_config->supported_interfaces);
+ } else if (wx->mac.type == wx_mac_aml) {
+ phy_mode = PHY_INTERFACE_MODE_25GBASER;
+ __set_bit(PHY_INTERFACE_MODE_25GBASER,
+ phy_config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_10GBASER,
+ phy_config->supported_interfaces);
+ } else if (wx->mac.type == wx_mac_sp) {
+ phy_mode = PHY_INTERFACE_MODE_10GBASER;
+ __set_bit(PHY_INTERFACE_MODE_10GBASER,
+ phy_config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX,
+ phy_config->supported_interfaces);
+ } else {
+ wx_err(wx, "Unsupported MAC type for VF\n");
+ return -EINVAL;
+ }
+
+ /* Initialize the phylink */
+ phylink = phylink_create(phy_config, NULL,
+ phy_mode, &txgbevf_mac_ops);
+ if (IS_ERR(phylink)) {
+ wx_err(wx, "Failed to create phylink\n");
+ return PTR_ERR(phylink);
+ }
+
+ link_state.speed = txgbevf_interface_max_speed(phy_mode);
+ link_state.duplex = DUPLEX_FULL;
+ err = phylink_set_fixed_link(phylink, &link_state);
+ if (err) {
+ wx_err(wx, "Failed to set fixed link\n");
+ return err;
+ }
+
+ wx->phylink = phylink;
+
+ return 0;
+}
+
static const struct net_device_ops txgbevf_netdev_ops = {
.ndo_open = wxvf_open,
.ndo_stop = wxvf_close,
@@ -257,6 +339,10 @@ static int txgbevf_probe(struct pci_dev *pdev,
if (err)
goto err_free_sw_init;
+ err = txgbevf_phylink_init(wx);
+ if (err)
+ goto err_clear_interrupt_scheme;
+
err = register_netdev(netdev);
if (err)
goto err_register;
@@ -267,6 +353,8 @@ static int txgbevf_probe(struct pci_dev *pdev,
return 0;
err_register:
+ phylink_destroy(wx->phylink);
+err_clear_interrupt_scheme:
wx_clear_interrupt_scheme(wx);
err_free_sw_init:
kfree(wx->vfinfo);
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net-next 09/12] net: wangxun: add ngbevf build
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
` (7 preceding siblings ...)
2025-06-11 8:35 ` [PATCH net-next 08/12] net: txgbevf: add phylink check flow Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 10/12] net: ngbevf: add sw init pci info and reset hardware Mengyuan Lou
` (2 subsequent siblings)
11 siblings, 0 replies; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Add doc build infrastructure for ngbevf driver.
Implement the basic PCI driver loading and unloading interface.
Initialize the id_table which support 1G virtual
functions for Wangxun.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
.../device_drivers/ethernet/index.rst | 1 +
.../ethernet/wangxun/ngbevf.rst | 16 ++
drivers/net/ethernet/wangxun/Kconfig | 15 ++
drivers/net/ethernet/wangxun/Makefile | 1 +
drivers/net/ethernet/wangxun/ngbevf/Makefile | 9 ++
.../net/ethernet/wangxun/ngbevf/ngbevf_main.c | 149 ++++++++++++++++++
.../net/ethernet/wangxun/ngbevf/ngbevf_type.h | 24 +++
7 files changed, 215 insertions(+)
create mode 100644 Documentation/networking/device_drivers/ethernet/wangxun/ngbevf.rst
create mode 100644 drivers/net/ethernet/wangxun/ngbevf/Makefile
create mode 100644 drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
create mode 100644 drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h
diff --git a/Documentation/networking/device_drivers/ethernet/index.rst b/Documentation/networking/device_drivers/ethernet/index.rst
index e93453410772..40ac552641a3 100644
--- a/Documentation/networking/device_drivers/ethernet/index.rst
+++ b/Documentation/networking/device_drivers/ethernet/index.rst
@@ -60,6 +60,7 @@ Contents:
wangxun/txgbe
wangxun/txgbevf
wangxun/ngbe
+ wangxun/ngbevf
.. only:: subproject and html
diff --git a/Documentation/networking/device_drivers/ethernet/wangxun/ngbevf.rst b/Documentation/networking/device_drivers/ethernet/wangxun/ngbevf.rst
new file mode 100644
index 000000000000..a39e3d5a1038
--- /dev/null
+++ b/Documentation/networking/device_drivers/ethernet/wangxun/ngbevf.rst
@@ -0,0 +1,16 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+==================================================================
+Linux Base Virtual Function Driver for Wangxun(R) Gigabit Ethernet
+==================================================================
+
+WangXun Gigabit Virtual Function Linux driver.
+Copyright(c) 2015 - 2025 Beijing WangXun Technology Co., Ltd.
+
+Support
+=======
+For general information, go to the website at:
+https://www.net-swift.com
+
+If you got any problem, contact Wangxun support team via nic-support@net-swift.com
+and Cc: netdev.
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index a6ec73e4f300..c548f4e80565 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -82,4 +82,19 @@ config TXGBEVF
To compile this driver as a module, choose M here. MSI-X interrupt
support is required for this driver to work correctly.
+config NGBEVF
+ tristate "Wangxun(R) GbE Virtual Function Ethernet support"
+ depends on PCI_MSI
+ select LIBWX
+ help
+ This driver supports virtual functions for WX1860, WX1860AL.
+
+ This driver was formerly named ngbevf.
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/device_drivers/ethernet/wangxun/ngbevf.rst>.
+
+ To compile this driver as a module, choose M here. MSI-X interrupt
+ support is required for this driver to work correctly.
+
endif # NET_VENDOR_WANGXUN
diff --git a/drivers/net/ethernet/wangxun/Makefile b/drivers/net/ethernet/wangxun/Makefile
index 71371d47a6ee..0a71a710b717 100644
--- a/drivers/net/ethernet/wangxun/Makefile
+++ b/drivers/net/ethernet/wangxun/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_LIBWX) += libwx/
obj-$(CONFIG_TXGBE) += txgbe/
obj-$(CONFIG_TXGBEVF) += txgbevf/
obj-$(CONFIG_NGBE) += ngbe/
+obj-$(CONFIG_NGBEVF) += ngbevf/
diff --git a/drivers/net/ethernet/wangxun/ngbevf/Makefile b/drivers/net/ethernet/wangxun/ngbevf/Makefile
new file mode 100644
index 000000000000..11a4f15e2ce3
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/ngbevf/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd.
+#
+# Makefile for the Wangxun(R) 1GbE virtual functions driver
+#
+
+obj-$(CONFIG_NGBE) += ngbevf.o
+
+ngbevf-objs := ngbevf_main.o
diff --git a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
new file mode 100644
index 000000000000..77025e7deeeb
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/etherdevice.h>
+
+#include "../libwx/wx_type.h"
+#include "../libwx/wx_vf_common.h"
+#include "ngbevf_type.h"
+
+/* ngbevf_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ * Class, Class Mask, private data (not used) }
+ */
+static const struct pci_device_id ngbevf_pci_tbl[] = {
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL_W), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860A2), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860A2S), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860A4), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860A4S), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL2), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL2S), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL4), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL4S), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860NCSI), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860A1), 0},
+ { PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL1), 0},
+ /* required last entry */
+ { .device = 0 }
+};
+
+/**
+ * ngbevf_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in ngbevf_pci_tbl
+ *
+ * Return: return 0 on success, negative on failure
+ *
+ * ngbevf_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int ngbevf_probe(struct pci_dev *pdev,
+ const struct pci_device_id __always_unused *ent)
+{
+ struct net_device *netdev;
+ struct wx *wx = NULL;
+ int err;
+
+ err = pci_enable_device_mem(pdev);
+ if (err)
+ return err;
+
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (err) {
+ dev_err(&pdev->dev,
+ "No usable DMA configuration, aborting\n");
+ goto err_pci_disable_dev;
+ }
+
+ err = pci_request_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM),
+ dev_driver_string(&pdev->dev));
+ if (err) {
+ dev_err(&pdev->dev,
+ "pci_request_selected_regions failed 0x%x\n", err);
+ goto err_pci_disable_dev;
+ }
+
+ pci_set_master(pdev);
+
+ netdev = devm_alloc_etherdev_mqs(&pdev->dev,
+ sizeof(struct wx),
+ NGBEVF_MAX_TX_QUEUES,
+ NGBEVF_MAX_RX_QUEUES);
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_pci_release_regions;
+ }
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ wx = netdev_priv(netdev);
+ wx->netdev = netdev;
+ wx->pdev = pdev;
+
+ wx->msg_enable = netif_msg_init(-1, NETIF_MSG_DRV |
+ NETIF_MSG_PROBE | NETIF_MSG_LINK);
+ wx->hw_addr = devm_ioremap(&pdev->dev,
+ pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (!wx->hw_addr) {
+ err = -EIO;
+ goto err_pci_release_regions;
+ }
+
+ netdev->features |= NETIF_F_HIGHDMA;
+ pci_set_drvdata(pdev, wx);
+
+ return 0;
+
+err_pci_release_regions:
+ pci_release_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM));
+err_pci_disable_dev:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/**
+ * ngbevf_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * ngbevf_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void ngbevf_remove(struct pci_dev *pdev)
+{
+ wxvf_remove(pdev);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(ngbevf_pm_ops, wxvf_suspend, wxvf_resume);
+
+static struct pci_driver ngbevf_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ngbevf_pci_tbl,
+ .probe = ngbevf_probe,
+ .remove = ngbevf_remove,
+ .shutdown = wxvf_shutdown,
+ /* Power Management Hooks */
+ .driver.pm = pm_sleep_ptr(&ngbevf_pm_ops)
+};
+
+module_pci_driver(ngbevf_driver);
+
+MODULE_DEVICE_TABLE(pci, ngbevf_pci_tbl);
+MODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@trustnetic.com>");
+MODULE_DESCRIPTION("WangXun(R) Gigabit PCI Express Network Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h
new file mode 100644
index 000000000000..c71a244ec6b9
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _NGBEVF_TYPE_H_
+#define _NGBEVF_TYPE_H_
+
+/* Device IDs */
+#define NGBEVF_DEV_ID_EM_WX1860AL_W 0x0110
+#define NGBEVF_DEV_ID_EM_WX1860A2 0x0111
+#define NGBEVF_DEV_ID_EM_WX1860A2S 0x0112
+#define NGBEVF_DEV_ID_EM_WX1860A4 0x0113
+#define NGBEVF_DEV_ID_EM_WX1860A4S 0x0114
+#define NGBEVF_DEV_ID_EM_WX1860AL2 0x0115
+#define NGBEVF_DEV_ID_EM_WX1860AL2S 0x0116
+#define NGBEVF_DEV_ID_EM_WX1860AL4 0x0117
+#define NGBEVF_DEV_ID_EM_WX1860AL4S 0x0118
+#define NGBEVF_DEV_ID_EM_WX1860NCSI 0x0119
+#define NGBEVF_DEV_ID_EM_WX1860A1 0x011a
+#define NGBEVF_DEV_ID_EM_WX1860AL1 0x011b
+
+#define NGBEVF_MAX_RX_QUEUES 1
+#define NGBEVF_MAX_TX_QUEUES 1
+
+#endif /* _NGBEVF_TYPE_H_ */
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net-next 10/12] net: ngbevf: add sw init pci info and reset hardware
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
` (8 preceding siblings ...)
2025-06-11 8:35 ` [PATCH net-next 09/12] net: wangxun: add ngbevf build Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 11/12] net: ngbevf: init interrupts and request irqs Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 12/12] net: ngbevf: add phylink check flow Mengyuan Lou
11 siblings, 0 replies; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Do sw init and reset hw for ngbevf virtual functions, then
register netdev.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
.../net/ethernet/wangxun/ngbevf/ngbevf_main.c | 91 +++++++++++++++++++
.../net/ethernet/wangxun/ngbevf/ngbevf_type.h | 4 +
2 files changed, 95 insertions(+)
diff --git a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
index 77025e7deeeb..4eea682f024b 100644
--- a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
+++ b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
@@ -9,6 +9,9 @@
#include <linux/etherdevice.h>
#include "../libwx/wx_type.h"
+#include "../libwx/wx_hw.h"
+#include "../libwx/wx_mbx.h"
+#include "../libwx/wx_vf.h"
#include "../libwx/wx_vf_common.h"
#include "ngbevf_type.h"
@@ -37,6 +40,75 @@ static const struct pci_device_id ngbevf_pci_tbl[] = {
{ .device = 0 }
};
+static const struct net_device_ops ngbevf_netdev_ops = {
+ .ndo_open = wxvf_open,
+ .ndo_stop = wxvf_close,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = wx_set_mac_vf,
+};
+
+static int ngbevf_sw_init(struct wx *wx)
+{
+ struct net_device *netdev = wx->netdev;
+ struct pci_dev *pdev = wx->pdev;
+ int err;
+
+ /* Initialize pcie info and common capability flags */
+ err = wx_sw_init(wx);
+ if (err < 0)
+ goto err_wx_sw_init;
+
+ /* Initialize the mailbox */
+ err = wx_init_mbx_params_vf(wx);
+ if (err)
+ goto err_init_mbx_params;
+
+ /* Initialize the device type */
+ wx->mac.type = wx_mac_em;
+ /* lock to protect mailbox accesses */
+ spin_lock_init(&wx->mbx.mbx_lock);
+
+ err = wx_reset_hw_vf(wx);
+ if (err) {
+ wx_err(wx, "PF still in reset state. Is the PF interface up?\n");
+ goto err_reset_hw;
+ }
+ wx_init_hw_vf(wx);
+ wx_negotiate_api_vf(wx);
+ if (is_zero_ether_addr(wx->mac.addr))
+ dev_info(&pdev->dev,
+ "MAC address not assigned by administrator.\n");
+ eth_hw_addr_set(netdev, wx->mac.addr);
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ dev_info(&pdev->dev, "Assigning random MAC address\n");
+ eth_hw_addr_random(netdev);
+ ether_addr_copy(wx->mac.addr, netdev->dev_addr);
+ ether_addr_copy(wx->mac.perm_addr, netdev->dev_addr);
+ }
+
+ wx->mac.max_tx_queues = NGBEVF_MAX_TX_QUEUES;
+ wx->mac.max_rx_queues = NGBEVF_MAX_RX_QUEUES;
+ /* Enable dynamic interrupt throttling rates */
+ wx->rx_itr_setting = 1;
+ wx->tx_itr_setting = 1;
+ /* set default ring sizes */
+ wx->tx_ring_count = NGBEVF_DEFAULT_TXD;
+ wx->rx_ring_count = NGBEVF_DEFAULT_RXD;
+ /* set default work limits */
+ wx->tx_work_limit = NGBEVF_DEFAULT_TX_WORK;
+ wx->rx_work_limit = NGBEVF_DEFAULT_RX_WORK;
+
+ return 0;
+err_reset_hw:
+ kfree(wx->vfinfo);
+err_init_mbx_params:
+ kfree(wx->rss_key);
+ kfree(wx->mac_table);
+err_wx_sw_init:
+ return err;
+}
+
/**
* ngbevf_probe - Device Initialization Routine
* @pdev: PCI device information struct
@@ -102,11 +174,30 @@ static int ngbevf_probe(struct pci_dev *pdev,
goto err_pci_release_regions;
}
+ netdev->netdev_ops = &ngbevf_netdev_ops;
+
+ /* setup the private structure */
+ err = ngbevf_sw_init(wx);
+ if (err)
+ goto err_pci_release_regions;
+
netdev->features |= NETIF_F_HIGHDMA;
+
+ eth_hw_addr_set(netdev, wx->mac.perm_addr);
+ ether_addr_copy(netdev->perm_addr, wx->mac.addr);
+
+ err = register_netdev(netdev);
+ if (err)
+ goto err_register;
+
pci_set_drvdata(pdev, wx);
return 0;
+err_register:
+ kfree(wx->vfinfo);
+ kfree(wx->rss_key);
+ kfree(wx->mac_table);
err_pci_release_regions:
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
diff --git a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h
index c71a244ec6b9..dc29349304f1 100644
--- a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h
+++ b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h
@@ -20,5 +20,9 @@
#define NGBEVF_MAX_RX_QUEUES 1
#define NGBEVF_MAX_TX_QUEUES 1
+#define NGBEVF_DEFAULT_TXD 128
+#define NGBEVF_DEFAULT_RXD 128
+#define NGBEVF_DEFAULT_TX_WORK 256
+#define NGBEVF_DEFAULT_RX_WORK 256
#endif /* _NGBEVF_TYPE_H_ */
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net-next 11/12] net: ngbevf: init interrupts and request irqs
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
` (9 preceding siblings ...)
2025-06-11 8:35 ` [PATCH net-next 10/12] net: ngbevf: add sw init pci info and reset hardware Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
2025-06-11 8:35 ` [PATCH net-next 12/12] net: ngbevf: add phylink check flow Mengyuan Lou
11 siblings, 0 replies; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Add specific parameters for irq alloc, then use
wx_init_interrupt_scheme to initialize interrupt
allocation in probe.
Add .ndo_start_xmit support and start all queues.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
.../net/ethernet/wangxun/ngbevf/ngbevf_main.c | 18 ++++++++++++++++++
.../net/ethernet/wangxun/ngbevf/ngbevf_type.h | 1 +
2 files changed, 19 insertions(+)
diff --git a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
index 4eea682f024b..a629b645d3a1 100644
--- a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
+++ b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
@@ -10,6 +10,7 @@
#include "../libwx/wx_type.h"
#include "../libwx/wx_hw.h"
+#include "../libwx/wx_lib.h"
#include "../libwx/wx_mbx.h"
#include "../libwx/wx_vf.h"
#include "../libwx/wx_vf_common.h"
@@ -43,10 +44,18 @@ static const struct pci_device_id ngbevf_pci_tbl[] = {
static const struct net_device_ops ngbevf_netdev_ops = {
.ndo_open = wxvf_open,
.ndo_stop = wxvf_close,
+ .ndo_start_xmit = wx_xmit_frame,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = wx_set_mac_vf,
};
+static void ngbevf_set_num_queues(struct wx *wx)
+{
+ /* Start with base case */
+ wx->num_rx_queues = 1;
+ wx->num_tx_queues = 1;
+}
+
static int ngbevf_sw_init(struct wx *wx)
{
struct net_device *netdev = wx->netdev;
@@ -65,6 +74,7 @@ static int ngbevf_sw_init(struct wx *wx)
/* Initialize the device type */
wx->mac.type = wx_mac_em;
+ wx->mac.max_msix_vectors = NGBEVF_MAX_MSIX_VECTORS;
/* lock to protect mailbox accesses */
spin_lock_init(&wx->mbx.mbx_lock);
@@ -98,6 +108,7 @@ static int ngbevf_sw_init(struct wx *wx)
/* set default work limits */
wx->tx_work_limit = NGBEVF_DEFAULT_TX_WORK;
wx->rx_work_limit = NGBEVF_DEFAULT_RX_WORK;
+ wx->set_num_queues = ngbevf_set_num_queues;
return 0;
err_reset_hw:
@@ -186,15 +197,22 @@ static int ngbevf_probe(struct pci_dev *pdev,
eth_hw_addr_set(netdev, wx->mac.perm_addr);
ether_addr_copy(netdev->perm_addr, wx->mac.addr);
+ err = wx_init_interrupt_scheme(wx);
+ if (err)
+ goto err_free_sw_init;
+
err = register_netdev(netdev);
if (err)
goto err_register;
pci_set_drvdata(pdev, wx);
+ netif_tx_stop_all_queues(netdev);
return 0;
err_register:
+ wx_clear_interrupt_scheme(wx);
+err_free_sw_init:
kfree(wx->vfinfo);
kfree(wx->rss_key);
kfree(wx->mac_table);
diff --git a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h
index dc29349304f1..67e761089e99 100644
--- a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h
+++ b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_type.h
@@ -18,6 +18,7 @@
#define NGBEVF_DEV_ID_EM_WX1860A1 0x011a
#define NGBEVF_DEV_ID_EM_WX1860AL1 0x011b
+#define NGBEVF_MAX_MSIX_VECTORS 1
#define NGBEVF_MAX_RX_QUEUES 1
#define NGBEVF_MAX_TX_QUEUES 1
#define NGBEVF_DEFAULT_TXD 128
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH net-next 12/12] net: ngbevf: add phylink check flow
2025-06-11 8:35 [PATCH net-next 00/12] Add vf drivers for wangxun virtual functions Mengyuan Lou
` (10 preceding siblings ...)
2025-06-11 8:35 ` [PATCH net-next 11/12] net: ngbevf: init interrupts and request irqs Mengyuan Lou
@ 2025-06-11 8:35 ` Mengyuan Lou
11 siblings, 0 replies; 20+ messages in thread
From: Mengyuan Lou @ 2025-06-11 8:35 UTC (permalink / raw)
To: netdev
Cc: kuba, pabeni, horms, andrew+netdev, duanqiangwen, linglingzhang,
jiawenwu, Mengyuan Lou
Add phylink support to wangxun 1G virtual functions.
Get link status from pf in mbox, and if it is failed then
check the vx_status, because vx_status switching is too slow.
Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
.../net/ethernet/wangxun/ngbevf/ngbevf_main.c | 50 +++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
index a629b645d3a1..e5b7e1753213 100644
--- a/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
+++ b/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
@@ -120,6 +120,50 @@ static int ngbevf_sw_init(struct wx *wx)
return err;
}
+static const struct phylink_mac_ops ngbevf_mac_ops = {
+ .mac_config = wxvf_mac_config,
+ .mac_link_down = wxvf_mac_link_down,
+ .mac_link_up = wxvf_mac_link_up,
+};
+
+static int ngbevf_phylink_init(struct wx *wx)
+{
+ struct phylink_link_state link_state;
+ struct phylink_config *phy_config;
+ phy_interface_t phy_mode;
+ struct phylink *phylink;
+ int err;
+
+ phy_config = &wx->phylink_config;
+ phy_config->dev = &wx->netdev->dev;
+ phy_config->type = PHYLINK_NETDEV;
+ phy_config->mac_capabilities = MAC_1000FD | MAC_100FD | MAC_10FD;
+ phy_config->get_fixed_state = wx_get_mac_link_vf;
+
+ phy_mode = PHY_INTERFACE_MODE_RGMII;
+ __set_bit(PHY_INTERFACE_MODE_RGMII, phy_config->supported_interfaces);
+
+ /* Initialize the phylink */
+ phylink = phylink_create(phy_config, NULL,
+ phy_mode, &ngbevf_mac_ops);
+ if (IS_ERR(phylink)) {
+ wx_err(wx, "Failed to create phylink\n");
+ return PTR_ERR(phylink);
+ }
+
+ link_state.speed = SPEED_1000;
+ link_state.duplex = DUPLEX_FULL;
+ err = phylink_set_fixed_link(phylink, &link_state);
+ if (err) {
+ wx_err(wx, "Failed to set fixed link\n");
+ return err;
+ }
+
+ wx->phylink = phylink;
+
+ return 0;
+}
+
/**
* ngbevf_probe - Device Initialization Routine
* @pdev: PCI device information struct
@@ -201,6 +245,10 @@ static int ngbevf_probe(struct pci_dev *pdev,
if (err)
goto err_free_sw_init;
+ err = ngbevf_phylink_init(wx);
+ if (err)
+ goto err_clear_interrupt_scheme;
+
err = register_netdev(netdev);
if (err)
goto err_register;
@@ -211,6 +259,8 @@ static int ngbevf_probe(struct pci_dev *pdev,
return 0;
err_register:
+ phylink_destroy(wx->phylink);
+err_clear_interrupt_scheme:
wx_clear_interrupt_scheme(wx);
err_free_sw_init:
kfree(wx->vfinfo);
--
2.30.1
^ permalink raw reply related [flat|nested] 20+ messages in thread