From 1e1fdcbdde3b7663e5d8faeb2245b9b151417d22 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 22 Apr 2024 10:03:13 -0400 Subject: vhost/vsock: always initialize seqpacket_allow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two issues around seqpacket_allow: 1. seqpacket_allow is not initialized when socket is created. Thus if features are never set, it will be read uninitialized. 2. if VIRTIO_VSOCK_F_SEQPACKET is set and then cleared, then seqpacket_allow will not be cleared appropriately (existing apps I know about don't usually do this but it's legal and there's no way to be sure no one relies on this). To fix: - initialize seqpacket_allow after allocation - set it unconditionally in set_features Reported-by: syzbot+6c21aeb59d0e82eb2782@syzkaller.appspotmail.com Reported-by: Jeongjun Park Fixes: ced7b713711f ("vhost/vsock: support SEQPACKET for transport"). Tested-by: Arseny Krasnov Cc: David S. Miller Cc: Stefan Hajnoczi Message-ID: <20240422100010-mutt-send-email-mst@kernel.org> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang Reviewed-by: Stefano Garzarella Reviewed-by: Eugenio PĂ©rez Acked-by: Jakub Kicinski --- drivers/vhost/vsock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index ec20ecff85c7..bf664ec9341b 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -667,6 +667,7 @@ static int vhost_vsock_dev_open(struct inode *inode, struct file *file) } vsock->guest_cid = 0; /* no CID assigned yet */ + vsock->seqpacket_allow = false; atomic_set(&vsock->queued_replies, 0); @@ -810,8 +811,7 @@ static int vhost_vsock_set_features(struct vhost_vsock *vsock, u64 features) goto err; } - if (features & (1ULL << VIRTIO_VSOCK_F_SEQPACKET)) - vsock->seqpacket_allow = true; + vsock->seqpacket_allow = features & (1ULL << VIRTIO_VSOCK_F_SEQPACKET); for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) { vq = &vsock->vqs[i]; -- cgit v1.2.3 From 840b2d39a2dc1b96deb3f5c7fef76c9b24f08f51 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Thu, 6 Jun 2024 19:13:45 +0800 Subject: virtio_ring: fix KMSAN error for premapped mode Add kmsan for virtqueue_dma_map_single_attrs to fix: BUG: KMSAN: uninit-value in receive_buf+0x45ca/0x6990 receive_buf+0x45ca/0x6990 virtnet_poll+0x17e0/0x3130 net_rx_action+0x832/0x26e0 handle_softirqs+0x330/0x10f0 [...] Uninit was created at: __alloc_pages_noprof+0x62a/0xe60 alloc_pages_noprof+0x392/0x830 skb_page_frag_refill+0x21a/0x5c0 virtnet_rq_alloc+0x50/0x1500 try_fill_recv+0x372/0x54c0 virtnet_open+0x210/0xbe0 __dev_open+0x56e/0x920 __dev_change_flags+0x39c/0x2000 dev_change_flags+0xaa/0x200 do_setlink+0x197a/0x7420 rtnl_setlink+0x77c/0x860 [...] Signed-off-by: Xuan Zhuo Tested-by: Alexander Potapenko Message-Id: <20240606111345.93600-1-xuanzhuo@linux.alibaba.com> Signed-off-by: Michael S. Tsirkin Tested-by: Ilya Leoshkevich # s390x Acked-by: Jason Wang --- drivers/virtio/virtio_ring.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 2a972752ff1b..9d3a9942c8c8 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -3121,8 +3121,10 @@ dma_addr_t virtqueue_dma_map_single_attrs(struct virtqueue *_vq, void *ptr, { struct vring_virtqueue *vq = to_vvq(_vq); - if (!vq->use_dma_api) + if (!vq->use_dma_api) { + kmsan_handle_dma(virt_to_page(ptr), offset_in_page(ptr), size, dir); return (dma_addr_t)virt_to_phys(ptr); + } return dma_map_single_attrs(vring_dma_dev(vq), ptr, size, dir, attrs); } -- cgit v1.2.3 From ede9c33ec568eed53f8f6bb42ed1d04af712cf02 Mon Sep 17 00:00:00 2001 From: Yunseong Kim Date: Tue, 25 Jun 2024 02:49:06 +0900 Subject: tools/virtio: creating pipe assertion in vringh_test parallel_test() function in vringh_test needs to verify the creation of the guest/host pipe. Signed-off-by: Yunseong Kim Message-Id: <20240624174905.27980-2-yskelg@gmail.com> Signed-off-by: Michael S. Tsirkin --- tools/virtio/vringh_test.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/virtio/vringh_test.c b/tools/virtio/vringh_test.c index 98ff808d6f0c..43d3a6aa1dcf 100644 --- a/tools/virtio/vringh_test.c +++ b/tools/virtio/vringh_test.c @@ -139,7 +139,7 @@ static int parallel_test(u64 features, bool fast_vringh) { void *host_map, *guest_map; - int fd, mapsize, to_guest[2], to_host[2]; + int pipe_ret, fd, mapsize, to_guest[2], to_host[2]; unsigned long xfers = 0, notifies = 0, receives = 0; unsigned int first_cpu, last_cpu; cpu_set_t cpu_set; @@ -161,8 +161,11 @@ static int parallel_test(u64 features, host_map = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); guest_map = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - pipe(to_guest); - pipe(to_host); + pipe_ret = pipe(to_guest); + assert(!pipe_ret); + + pipe_ret = pipe(to_host); + assert(!pipe_ret); CPU_ZERO(&cpu_set); find_cpus(&first_cpu, &last_cpu); -- cgit v1.2.3 From e269d79c7d35aa3808b1f3c1737d63dab504ddc8 Mon Sep 17 00:00:00 2001 From: Denis Arefev Date: Thu, 13 Jun 2024 12:54:48 +0300 Subject: net: missing check virtio Two missing check in virtio_net_hdr_to_skb() allowed syzbot to crash kernels again 1. After the skb_segment function the buffer may become non-linear (nr_frags != 0), but since the SKBTX_SHARED_FRAG flag is not set anywhere the __skb_linearize function will not be executed, then the buffer will remain non-linear. Then the condition (offset >= skb_headlen(skb)) becomes true, which causes WARN_ON_ONCE in skb_checksum_help. 2. The struct sk_buff and struct virtio_net_hdr members must be mathematically related. (gso_size) must be greater than (needed) otherwise WARN_ON_ONCE. (remainder) must be greater than (needed) otherwise WARN_ON_ONCE. (remainder) may be 0 if division is without remainder. offset+2 (4191) > skb_headlen() (1116) WARNING: CPU: 1 PID: 5084 at net/core/dev.c:3303 skb_checksum_help+0x5e2/0x740 net/core/dev.c:3303 Modules linked in: CPU: 1 PID: 5084 Comm: syz-executor336 Not tainted 6.7.0-rc3-syzkaller-00014-gdf60cee26a2e #0 Hardware name: Google Compute Engine/Google Compute Engine, BIOS Google 11/10/2023 RIP: 0010:skb_checksum_help+0x5e2/0x740 net/core/dev.c:3303 Code: 89 e8 83 e0 07 83 c0 03 38 d0 7c 08 84 d2 0f 85 52 01 00 00 44 89 e2 2b 53 74 4c 89 ee 48 c7 c7 40 57 e9 8b e8 af 8f dd f8 90 <0f> 0b 90 90 e9 87 fe ff ff e8 40 0f 6e f9 e9 4b fa ff ff 48 89 ef RSP: 0018:ffffc90003a9f338 EFLAGS: 00010286 RAX: 0000000000000000 RBX: ffff888025125780 RCX: ffffffff814db209 RDX: ffff888015393b80 RSI: ffffffff814db216 RDI: 0000000000000001 RBP: ffff8880251257f4 R08: 0000000000000001 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000001 R12: 000000000000045c R13: 000000000000105f R14: ffff8880251257f0 R15: 000000000000105d FS: 0000555555c24380(0000) GS:ffff8880b9900000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000002000f000 CR3: 0000000023151000 CR4: 00000000003506f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: ip_do_fragment+0xa1b/0x18b0 net/ipv4/ip_output.c:777 ip_fragment.constprop.0+0x161/0x230 net/ipv4/ip_output.c:584 ip_finish_output_gso net/ipv4/ip_output.c:286 [inline] __ip_finish_output net/ipv4/ip_output.c:308 [inline] __ip_finish_output+0x49c/0x650 net/ipv4/ip_output.c:295 ip_finish_output+0x31/0x310 net/ipv4/ip_output.c:323 NF_HOOK_COND include/linux/netfilter.h:303 [inline] ip_output+0x13b/0x2a0 net/ipv4/ip_output.c:433 dst_output include/net/dst.h:451 [inline] ip_local_out+0xaf/0x1a0 net/ipv4/ip_output.c:129 iptunnel_xmit+0x5b4/0x9b0 net/ipv4/ip_tunnel_core.c:82 ipip6_tunnel_xmit net/ipv6/sit.c:1034 [inline] sit_tunnel_xmit+0xed2/0x28f0 net/ipv6/sit.c:1076 __netdev_start_xmit include/linux/netdevice.h:4940 [inline] netdev_start_xmit include/linux/netdevice.h:4954 [inline] xmit_one net/core/dev.c:3545 [inline] dev_hard_start_xmit+0x13d/0x6d0 net/core/dev.c:3561 __dev_queue_xmit+0x7c1/0x3d60 net/core/dev.c:4346 dev_queue_xmit include/linux/netdevice.h:3134 [inline] packet_xmit+0x257/0x380 net/packet/af_packet.c:276 packet_snd net/packet/af_packet.c:3087 [inline] packet_sendmsg+0x24ca/0x5240 net/packet/af_packet.c:3119 sock_sendmsg_nosec net/socket.c:730 [inline] __sock_sendmsg+0xd5/0x180 net/socket.c:745 __sys_sendto+0x255/0x340 net/socket.c:2190 __do_sys_sendto net/socket.c:2202 [inline] __se_sys_sendto net/socket.c:2198 [inline] __x64_sys_sendto+0xe0/0x1b0 net/socket.c:2198 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x40/0x110 arch/x86/entry/common.c:82 entry_SYSCALL_64_after_hwframe+0x63/0x6b Found by Linux Verification Center (linuxtesting.org) with Syzkaller Fixes: 0f6925b3e8da ("virtio_net: Do not pull payload in skb->head") Signed-off-by: Denis Arefev Message-Id: <20240613095448.27118-1-arefev@swemel.ru> Signed-off-by: Michael S. Tsirkin --- include/linux/virtio_net.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h index 4dfa9b69ca8d..d1d7825318c3 100644 --- a/include/linux/virtio_net.h +++ b/include/linux/virtio_net.h @@ -56,6 +56,7 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, unsigned int thlen = 0; unsigned int p_off = 0; unsigned int ip_proto; + u64 ret, remainder, gso_size; if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { @@ -98,6 +99,16 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, u32 off = __virtio16_to_cpu(little_endian, hdr->csum_offset); u32 needed = start + max_t(u32, thlen, off + sizeof(__sum16)); + if (hdr->gso_size) { + gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size); + ret = div64_u64_rem(skb->len, gso_size, &remainder); + if (!(ret && (hdr->gso_size > needed) && + ((remainder > needed) || (remainder == 0)))) { + return -EINVAL; + } + skb_shinfo(skb)->tx_flags |= SKBFL_SHARED_FRAG; + } + if (!pskb_may_pull(skb, needed)) return -EINVAL; -- cgit v1.2.3 From 8b6c724cdab85d8923dd8c474a5a9464228379c5 Mon Sep 17 00:00:00 2001 From: Srujana Challa Date: Fri, 14 Jun 2024 20:16:59 +0530 Subject: virtio: vdpa: vDPA driver for Marvell OCTEON DPU devices This commit introduces a new vDPA driver specifically designed for managing the virtio control plane over the vDPA bus for OCTEON DPU devices. The driver consists of two layers: 1. Octep HW Layer (Octeon Endpoint): Responsible for handling hardware operations and configurations related to the DPU device. 2. Octep Main Layer: Compliant with the vDPA bus framework, this layer implements device operations for the vDPA bus. It handles device probing, bus attachment, vring operations, and other relevant tasks. Signed-off-by: Srujana Challa Signed-off-by: Vamsi Attunuru Signed-off-by: Shijith Thotton Signed-off-by: Nithin Dabilpuram Acked-by: Jason Wang Message-Id: <20240614144659.1776067-1-schalla@marvell.com> Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 5 + drivers/vdpa/Kconfig | 11 + drivers/vdpa/Makefile | 1 + drivers/vdpa/octeon_ep/Makefile | 4 + drivers/vdpa/octeon_ep/octep_vdpa.h | 94 ++++ drivers/vdpa/octeon_ep/octep_vdpa_hw.c | 517 +++++++++++++++++++ drivers/vdpa/octeon_ep/octep_vdpa_main.c | 857 +++++++++++++++++++++++++++++++ 7 files changed, 1489 insertions(+) create mode 100644 drivers/vdpa/octeon_ep/Makefile create mode 100644 drivers/vdpa/octeon_ep/octep_vdpa.h create mode 100644 drivers/vdpa/octeon_ep/octep_vdpa_hw.c create mode 100644 drivers/vdpa/octeon_ep/octep_vdpa_main.c diff --git a/MAINTAINERS b/MAINTAINERS index cd2ca0c3158e..d0249d7538e1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13459,6 +13459,11 @@ S: Supported F: Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml F: drivers/mmc/host/sdhci-xenon* +MARVELL OCTEON ENDPOINT VIRTIO DATA PATH ACCELERATOR +R: schalla@marvell.com +R: vattunuru@marvell.com +F: drivers/vdpa/octeon_ep/ + MATROX FRAMEBUFFER DRIVER L: linux-fbdev@vger.kernel.org S: Orphan diff --git a/drivers/vdpa/Kconfig b/drivers/vdpa/Kconfig index 656c1cb541de..5265d09fc1c4 100644 --- a/drivers/vdpa/Kconfig +++ b/drivers/vdpa/Kconfig @@ -126,4 +126,15 @@ config PDS_VDPA With this driver, the VirtIO dataplane can be offloaded to an AMD/Pensando DSC device. +config OCTEONEP_VDPA + tristate "vDPA driver for Octeon DPU devices" + depends on m + depends on PCI_MSI + help + This is a vDPA driver designed for Marvell's Octeon DPU devices. + This driver enables the offloading of the VirtIO dataplane to an + Octeon DPU device. + Please note that this driver must be built as a module and it + cannot be loaded until the Octeon emulation software is running. + endif # VDPA diff --git a/drivers/vdpa/Makefile b/drivers/vdpa/Makefile index 8f53c6f3cca7..5654d36707af 100644 --- a/drivers/vdpa/Makefile +++ b/drivers/vdpa/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_VP_VDPA) += virtio_pci/ obj-$(CONFIG_ALIBABA_ENI_VDPA) += alibaba/ obj-$(CONFIG_SNET_VDPA) += solidrun/ obj-$(CONFIG_PDS_VDPA) += pds/ +obj-$(CONFIG_OCTEONEP_VDPA) += octeon_ep/ diff --git a/drivers/vdpa/octeon_ep/Makefile b/drivers/vdpa/octeon_ep/Makefile new file mode 100644 index 000000000000..e23e2ff14f33 --- /dev/null +++ b/drivers/vdpa/octeon_ep/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_OCTEONEP_VDPA) += octep_vdpa.o +octep_vdpa-$(CONFIG_OCTEONEP_VDPA) += octep_vdpa_main.o +octep_vdpa-$(CONFIG_OCTEONEP_VDPA) += octep_vdpa_hw.o diff --git a/drivers/vdpa/octeon_ep/octep_vdpa.h b/drivers/vdpa/octeon_ep/octep_vdpa.h new file mode 100644 index 000000000000..046710ec4d42 --- /dev/null +++ b/drivers/vdpa/octeon_ep/octep_vdpa.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * Copyright (C) 2024 Marvell. + */ +#ifndef __OCTEP_VDPA_H__ +#define __OCTEP_VDPA_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OCTEP_VDPA_DEVID_CN106K_PF 0xb900 +#define OCTEP_VDPA_DEVID_CN106K_VF 0xb903 +#define OCTEP_VDPA_DEVID_CN105K_PF 0xba00 +#define OCTEP_VDPA_DEVID_CN105K_VF 0xba03 +#define OCTEP_VDPA_DEVID_CN103K_PF 0xbd00 +#define OCTEP_VDPA_DEVID_CN103K_VF 0xbd03 + +#define OCTEP_HW_MBOX_BAR 0 +#define OCTEP_HW_CAPS_BAR 4 + +#define OCTEP_DEV_READY_SIGNATURE 0xBABABABA + +#define OCTEP_EPF_RINFO(x) (0x000209f0 | ((x) << 25)) +#define OCTEP_VF_MBOX_DATA(x) (0x00010210 | ((x) << 17)) +#define OCTEP_PF_MBOX_DATA(x) (0x00022000 | ((x) << 4)) + +#define OCTEP_EPF_RINFO_RPVF(val) (((val) >> 32) & 0xF) +#define OCTEP_EPF_RINFO_NVFS(val) (((val) >> 48) & 0x7F) + +#define OCTEP_FW_READY_SIGNATURE0 0xFEEDFEED +#define OCTEP_FW_READY_SIGNATURE1 0x3355ffaa + +enum octep_vdpa_dev_status { + OCTEP_VDPA_DEV_STATUS_INVALID, + OCTEP_VDPA_DEV_STATUS_ALLOC, + OCTEP_VDPA_DEV_STATUS_WAIT_FOR_BAR_INIT, + OCTEP_VDPA_DEV_STATUS_INIT, + OCTEP_VDPA_DEV_STATUS_READY, + OCTEP_VDPA_DEV_STATUS_UNINIT +}; + +struct octep_vring_info { + struct vdpa_callback cb; + void __iomem *notify_addr; + u32 __iomem *cb_notify_addr; + phys_addr_t notify_pa; + char msix_name[256]; +}; + +struct octep_hw { + struct pci_dev *pdev; + u8 __iomem *base[PCI_STD_NUM_BARS]; + struct virtio_pci_common_cfg __iomem *common_cfg; + u8 __iomem *dev_cfg; + u8 __iomem *isr; + void __iomem *notify_base; + phys_addr_t notify_base_pa; + u32 notify_off_multiplier; + u8 notify_bar; + struct octep_vring_info *vqs; + struct vdpa_callback config_cb; + u64 features; + u16 nr_vring; + u32 config_size; + int irq; +}; + +u8 octep_hw_get_status(struct octep_hw *oct_hw); +void octep_hw_set_status(struct octep_hw *dev, uint8_t status); +void octep_hw_reset(struct octep_hw *oct_hw); +void octep_write_queue_select(struct octep_hw *oct_hw, u16 queue_id); +void octep_notify_queue(struct octep_hw *oct_hw, u16 qid); +void octep_read_dev_config(struct octep_hw *oct_hw, u64 offset, void *dst, int length); +int octep_set_vq_address(struct octep_hw *oct_hw, u16 qid, u64 desc_area, u64 driver_area, + u64 device_area); +void octep_set_vq_num(struct octep_hw *oct_hw, u16 qid, u32 num); +void octep_set_vq_ready(struct octep_hw *oct_hw, u16 qid, bool ready); +bool octep_get_vq_ready(struct octep_hw *oct_hw, u16 qid); +int octep_set_vq_state(struct octep_hw *oct_hw, u16 qid, const struct vdpa_vq_state *state); +int octep_get_vq_state(struct octep_hw *oct_hw, u16 qid, struct vdpa_vq_state *state); +u16 octep_get_vq_size(struct octep_hw *oct_hw); +int octep_hw_caps_read(struct octep_hw *oct_hw, struct pci_dev *pdev); +u64 octep_hw_get_dev_features(struct octep_hw *oct_hw); +void octep_hw_set_drv_features(struct octep_hw *oct_hw, u64 features); +u64 octep_hw_get_drv_features(struct octep_hw *oct_hw); +int octep_verify_features(u64 features); + +#endif /* __OCTEP_VDPA_H__ */ diff --git a/drivers/vdpa/octeon_ep/octep_vdpa_hw.c b/drivers/vdpa/octeon_ep/octep_vdpa_hw.c new file mode 100644 index 000000000000..7fa0491bb201 --- /dev/null +++ b/drivers/vdpa/octeon_ep/octep_vdpa_hw.c @@ -0,0 +1,517 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2024 Marvell. */ + +#include + +#include "octep_vdpa.h" + +enum octep_mbox_ids { + OCTEP_MBOX_MSG_SET_VQ_STATE = 1, + OCTEP_MBOX_MSG_GET_VQ_STATE, +}; + +#define OCTEP_HW_TIMEOUT 10000000 + +#define MBOX_OFFSET 64 +#define MBOX_RSP_MASK 0x00000001 +#define MBOX_RC_MASK 0x0000FFFE + +#define MBOX_RSP_TO_ERR(val) (-(((val) & MBOX_RC_MASK) >> 2)) +#define MBOX_AVAIL(val) (((val) & MBOX_RSP_MASK)) +#define MBOX_RSP(val) ((val) & (MBOX_RC_MASK | MBOX_RSP_MASK)) + +#define DEV_RST_ACK_BIT 7 +#define FEATURE_SEL_ACK_BIT 15 +#define QUEUE_SEL_ACK_BIT 15 + +struct octep_mbox_hdr { + u8 ver; + u8 rsvd1; + u16 id; + u16 rsvd2; +#define MBOX_REQ_SIG (0xdead) +#define MBOX_RSP_SIG (0xbeef) + u16 sig; +}; + +struct octep_mbox_sts { + u16 rsp:1; + u16 rc:15; + u16 rsvd; +}; + +struct octep_mbox { + struct octep_mbox_hdr hdr; + struct octep_mbox_sts sts; + u64 rsvd; + u32 data[]; +}; + +static inline struct octep_mbox __iomem *octep_get_mbox(struct octep_hw *oct_hw) +{ + return (struct octep_mbox __iomem *)(oct_hw->dev_cfg + MBOX_OFFSET); +} + +static inline int octep_wait_for_mbox_avail(struct octep_mbox __iomem *mbox) +{ + u32 val; + + return readx_poll_timeout(ioread32, &mbox->sts, val, MBOX_AVAIL(val), 10, + OCTEP_HW_TIMEOUT); +} + +static inline int octep_wait_for_mbox_rsp(struct octep_mbox __iomem *mbox) +{ + u32 val; + + return readx_poll_timeout(ioread32, &mbox->sts, val, MBOX_RSP(val), 10, + OCTEP_HW_TIMEOUT); +} + +static inline void octep_write_hdr(struct octep_mbox __iomem *mbox, u16 id, u16 sig) +{ + iowrite16(id, &mbox->hdr.id); + iowrite16(sig, &mbox->hdr.sig); +} + +static inline u32 octep_read_sig(struct octep_mbox __iomem *mbox) +{ + return ioread16(&mbox->hdr.sig); +} + +static inline void octep_write_sts(struct octep_mbox __iomem *mbox, u32 sts) +{ + iowrite32(sts, &mbox->sts); +} + +static inline u32 octep_read_sts(struct octep_mbox __iomem *mbox) +{ + return ioread32(&mbox->sts); +} + +static inline u32 octep_read32_word(struct octep_mbox __iomem *mbox, u16 word_idx) +{ + return ioread32(&mbox->data[word_idx]); +} + +static inline void octep_write32_word(struct octep_mbox __iomem *mbox, u16 word_idx, u32 word) +{ + return iowrite32(word, &mbox->data[word_idx]); +} + +static int octep_process_mbox(struct octep_hw *oct_hw, u16 id, u16 qid, void *buffer, + u32 buf_size, bool write) +{ + struct octep_mbox __iomem *mbox = octep_get_mbox(oct_hw); + struct pci_dev *pdev = oct_hw->pdev; + u32 *p = (u32 *)buffer; + u16 data_wds; + int ret, i; + u32 val; + + if (!IS_ALIGNED(buf_size, 4)) + return -EINVAL; + + /* Make sure mbox space is available */ + ret = octep_wait_for_mbox_avail(mbox); + if (ret) { + dev_warn(&pdev->dev, "Timeout waiting for previous mbox data to be consumed\n"); + return ret; + } + data_wds = buf_size / 4; + + if (write) { + for (i = 1; i <= data_wds; i++) { + octep_write32_word(mbox, i, *p); + p++; + } + } + octep_write32_word(mbox, 0, (u32)qid); + octep_write_sts(mbox, 0); + + octep_write_hdr(mbox, id, MBOX_REQ_SIG); + + ret = octep_wait_for_mbox_rsp(mbox); + if (ret) { + dev_warn(&pdev->dev, "Timeout waiting for mbox : %d response\n", id); + return ret; + } + + val = octep_read_sig(mbox); + if ((val & 0xFFFF) != MBOX_RSP_SIG) { + dev_warn(&pdev->dev, "Invalid Signature from mbox : %d response\n", id); + return ret; + } + + val = octep_read_sts(mbox); + if (val & MBOX_RC_MASK) { + ret = MBOX_RSP_TO_ERR(val); + dev_warn(&pdev->dev, "Error while processing mbox : %d, err %d\n", id, ret); + return ret; + } + + if (!write) + for (i = 1; i <= data_wds; i++) + *p++ = octep_read32_word(mbox, i); + + return 0; +} + +static void octep_mbox_init(struct octep_mbox __iomem *mbox) +{ + iowrite32(1, &mbox->sts); +} + +int octep_verify_features(u64 features) +{ + /* Minimum features to expect */ + if (!(features & BIT_ULL(VIRTIO_F_VERSION_1))) + return -EOPNOTSUPP; + + if (!(features & BIT_ULL(VIRTIO_F_NOTIFICATION_DATA))) + return -EOPNOTSUPP; + + if (!(features & BIT_ULL(VIRTIO_F_RING_PACKED))) + return -EOPNOTSUPP; + + return 0; +} + +u8 octep_hw_get_status(struct octep_hw *oct_hw) +{ + return ioread8(&oct_hw->common_cfg->device_status); +} + +void octep_hw_set_status(struct octep_hw *oct_hw, u8 status) +{ + iowrite8(status, &oct_hw->common_cfg->device_status); +} + +void octep_hw_reset(struct octep_hw *oct_hw) +{ + u8 val; + + octep_hw_set_status(oct_hw, 0 | BIT(DEV_RST_ACK_BIT)); + if (readx_poll_timeout(ioread8, &oct_hw->common_cfg->device_status, val, !val, 10, + OCTEP_HW_TIMEOUT)) { + dev_warn(&oct_hw->pdev->dev, "Octeon device reset timeout\n"); + return; + } +} + +static int feature_sel_write_with_timeout(struct octep_hw *oct_hw, u32 select, void __iomem *addr) +{ + u32 val; + + iowrite32(select | BIT(FEATURE_SEL_ACK_BIT), addr); + + if (readx_poll_timeout(ioread32, addr, val, val == select, 10, OCTEP_HW_TIMEOUT)) { + dev_warn(&oct_hw->pdev->dev, "Feature select%d write timeout\n", select); + return -1; + } + return 0; +} + +u64 octep_hw_get_dev_features(struct octep_hw *oct_hw) +{ + u32 features_lo, features_hi; + + if (feature_sel_write_with_timeout(oct_hw, 0, &oct_hw->common_cfg->device_feature_select)) + return 0; + + features_lo = ioread32(&oct_hw->common_cfg->device_feature); + + if (feature_sel_write_with_timeout(oct_hw, 1, &oct_hw->common_cfg->device_feature_select)) + return 0; + + features_hi = ioread32(&oct_hw->common_cfg->device_feature); + + return ((u64)features_hi << 32) | features_lo; +} + +u64 octep_hw_get_drv_features(struct octep_hw *oct_hw) +{ + u32 features_lo, features_hi; + + if (feature_sel_write_with_timeout(oct_hw, 0, &oct_hw->common_cfg->guest_feature_select)) + return 0; + + features_lo = ioread32(&oct_hw->common_cfg->guest_feature); + + if (feature_sel_write_with_timeout(oct_hw, 1, &oct_hw->common_cfg->guest_feature_select)) + return 0; + + features_hi = ioread32(&oct_hw->common_cfg->guest_feature); + + return ((u64)features_hi << 32) | features_lo; +} + +void octep_hw_set_drv_features(struct octep_hw *oct_hw, u64 features) +{ + if (feature_sel_write_with_timeout(oct_hw, 0, &oct_hw->common_cfg->guest_feature_select)) + return; + + iowrite32(features & (BIT_ULL(32) - 1), &oct_hw->common_cfg->guest_feature); + + if (feature_sel_write_with_timeout(oct_hw, 1, &oct_hw->common_cfg->guest_feature_select)) + return; + + iowrite32(features >> 32, &oct_hw->common_cfg->guest_feature); +} + +void octep_write_queue_select(struct octep_hw *oct_hw, u16 queue_id) +{ + u16 val; + + iowrite16(queue_id | BIT(QUEUE_SEL_ACK_BIT), &oct_hw->common_cfg->queue_select); + + if (readx_poll_timeout(ioread16, &oct_hw->common_cfg->queue_select, val, val == queue_id, + 10, OCTEP_HW_TIMEOUT)) { + dev_warn(&oct_hw->pdev->dev, "Queue select write timeout\n"); + return; + } +} + +void octep_notify_queue(struct octep_hw *oct_hw, u16 qid) +{ + iowrite16(qid, oct_hw->vqs[qid].notify_addr); +} + +void octep_read_dev_config(struct octep_hw *oct_hw, u64 offset, void *dst, int length) +{ + u8 old_gen, new_gen, *p; + int i; + + if (WARN_ON(offset + length > oct_hw->config_size)) + return; + + do { + old_gen = ioread8(&oct_hw->common_cfg->config_generation); + p = dst; + for (i = 0; i < length; i++) + *p++ = ioread8(oct_hw->dev_cfg + offset + i); + + new_gen = ioread8(&oct_hw->common_cfg->config_generation); + } while (old_gen != new_gen); +} + +int octep_set_vq_address(struct octep_hw *oct_hw, u16 qid, u64 desc_area, u64 driver_area, + u64 device_area) +{ + struct virtio_pci_common_cfg __iomem *cfg = oct_hw->common_cfg; + + octep_write_queue_select(oct_hw, qid); + vp_iowrite64_twopart(desc_area, &cfg->queue_desc_lo, + &cfg->queue_desc_hi); + vp_iowrite64_twopart(driver_area, &cfg->queue_avail_lo, + &cfg->queue_avail_hi); + vp_iowrite64_twopart(device_area, &cfg->queue_used_lo, + &cfg->queue_used_hi); + + return 0; +} + +int octep_get_vq_state(struct octep_hw *oct_hw, u16 qid, struct vdpa_vq_state *state) +{ + return octep_process_mbox(oct_hw, OCTEP_MBOX_MSG_GET_VQ_STATE, qid, state, + sizeof(*state), 0); +} + +int octep_set_vq_state(struct octep_hw *oct_hw, u16 qid, const struct vdpa_vq_state *state) +{ + struct vdpa_vq_state q_state; + + memcpy(&q_state, state, sizeof(struct vdpa_vq_state)); + return octep_process_mbox(oct_hw, OCTEP_MBOX_MSG_SET_VQ_STATE, qid, &q_state, + sizeof(*state), 1); +} + +void octep_set_vq_num(struct octep_hw *oct_hw, u16 qid, u32 num) +{ + struct virtio_pci_common_cfg __iomem *cfg = oct_hw->common_cfg; + + octep_write_queue_select(oct_hw, qid); + iowrite16(num, &cfg->queue_size); +} + +void octep_set_vq_ready(struct octep_hw *oct_hw, u16 qid, bool ready) +{ + struct virtio_pci_common_cfg __iomem *cfg = oct_hw->common_cfg; + + octep_write_queue_select(oct_hw, qid); + iowrite16(ready, &cfg->queue_enable); +} + +bool octep_get_vq_ready(struct octep_hw *oct_hw, u16 qid) +{ + struct virtio_pci_common_cfg __iomem *cfg = oct_hw->common_cfg; + + octep_write_queue_select(oct_hw, qid); + return ioread16(&cfg->queue_enable); +} + +u16 octep_get_vq_size(struct octep_hw *oct_hw) +{ + octep_write_queue_select(oct_hw, 0); + return ioread16(&oct_hw->common_cfg->queue_size); +} + +static u32 octep_get_config_size(struct octep_hw *oct_hw) +{ + return sizeof(struct virtio_net_config); +} + +static void __iomem *octep_get_cap_addr(struct octep_hw *oct_hw, struct virtio_pci_cap *cap) +{ + struct device *dev = &oct_hw->pdev->dev; + u32 length = le32_to_cpu(cap->length); + u32 offset = le32_to_cpu(cap->offset); + u8 bar = cap->bar; + u32 len; + + if (bar != OCTEP_HW_CAPS_BAR) { + dev_err(dev, "Invalid bar: %u\n", bar); + return NULL; + } + if (offset + length < offset) { + dev_err(dev, "offset(%u) + length(%u) overflows\n", + offset, length); + return NULL; + } + len = pci_resource_len(oct_hw->pdev, bar); + if (offset + length > len) { + dev_err(dev, "invalid cap: overflows bar space: %u > %u\n", + offset + length, len); + return NULL; + } + return oct_hw->base[bar] + offset; +} + +/* In Octeon DPU device, the virtio config space is completely + * emulated by the device's firmware. So, the standard pci config + * read apis can't be used for reading the virtio capability. + */ +static void octep_pci_caps_read(struct octep_hw *oct_hw, void *buf, size_t len, off_t offset) +{ + u8 __iomem *bar = oct_hw->base[OCTEP_HW_CAPS_BAR]; + u8 *p = buf; + size_t i; + + for (i = 0; i < len; i++) + *p++ = ioread8(bar + offset + i); +} + +static int octep_pci_signature_verify(struct octep_hw *oct_hw) +{ + u32 signature[2]; + + octep_pci_caps_read(oct_hw, &signature, sizeof(signature), 0); + + if (signature[0] != OCTEP_FW_READY_SIGNATURE0) + return -1; + + if (signature[1] != OCTEP_FW_READY_SIGNATURE1) + return -1; + + return 0; +} + +int octep_hw_caps_read(struct octep_hw *oct_hw, struct pci_dev *pdev) +{ + struct octep_mbox __iomem *mbox; + struct device *dev = &pdev->dev; + struct virtio_pci_cap cap; + u16 notify_off; + int i, ret; + u8 pos; + + oct_hw->pdev = pdev; + ret = octep_pci_signature_verify(oct_hw); + if (ret) { + dev_err(dev, "Octeon Virtio FW is not initialized\n"); + return -EIO; + } + + octep_pci_caps_read(oct_hw, &pos, 1, PCI_CAPABILITY_LIST); + + while (pos) { + octep_pci_caps_read(oct_hw, &cap, 2, pos); + + if (cap.cap_vndr != PCI_CAP_ID_VNDR) { + dev_err(dev, "Found invalid capability vndr id: %d\n", cap.cap_vndr); + break; + } + + octep_pci_caps_read(oct_hw, &cap, sizeof(cap), pos); + + dev_info(dev, "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u\n", + pos, cap.cfg_type, cap.bar, cap.offset, cap.length); + + switch (cap.cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + oct_hw->common_cfg = octep_get_cap_addr(oct_hw, &cap); + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + octep_pci_caps_read(oct_hw, &oct_hw->notify_off_multiplier, + 4, pos + sizeof(cap)); + + oct_hw->notify_base = octep_get_cap_addr(oct_hw, &cap); + oct_hw->notify_bar = cap.bar; + oct_hw->notify_base_pa = pci_resource_start(pdev, cap.bar) + + le32_to_cpu(cap.offset); + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + oct_hw->dev_cfg = octep_get_cap_addr(oct_hw, &cap); + break; + case VIRTIO_PCI_CAP_ISR_CFG: + oct_hw->isr = octep_get_cap_addr(oct_hw, &cap); + break; + } + + pos = cap.cap_next; + } + if (!oct_hw->common_cfg || !oct_hw->notify_base || + !oct_hw->dev_cfg || !oct_hw->isr) { + dev_err(dev, "Incomplete PCI capabilities"); + return -EIO; + } + dev_info(dev, "common cfg mapped at: 0x%016llx\n", (u64)(uintptr_t)oct_hw->common_cfg); + dev_info(dev, "device cfg mapped at: 0x%016llx\n", (u64)(uintptr_t)oct_hw->dev_cfg); + dev_info(dev, "isr cfg mapped at: 0x%016llx\n", (u64)(uintptr_t)oct_hw->isr); + dev_info(dev, "notify base: 0x%016llx, notify off multiplier: %u\n", + (u64)(uintptr_t)oct_hw->notify_base, oct_hw->notify_off_multiplier); + + oct_hw->config_size = octep_get_config_size(oct_hw); + oct_hw->features = octep_hw_get_dev_features(oct_hw); + + ret = octep_verify_features(oct_hw->features); + if (ret) { + dev_err(&pdev->dev, "Couldn't read features from the device FW\n"); + return ret; + } + oct_hw->nr_vring = vp_ioread16(&oct_hw->common_cfg->num_queues); + + oct_hw->vqs = devm_kcalloc(&pdev->dev, oct_hw->nr_vring, sizeof(*oct_hw->vqs), GFP_KERNEL); + if (!oct_hw->vqs) + return -ENOMEM; + + oct_hw->irq = -1; + + dev_info(&pdev->dev, "Device features : %llx\n", oct_hw->features); + dev_info(&pdev->dev, "Maximum queues : %u\n", oct_hw->nr_vring); + + for (i = 0; i < oct_hw->nr_vring; i++) { + octep_write_queue_select(oct_hw, i); + notify_off = vp_ioread16(&oct_hw->common_cfg->queue_notify_off); + oct_hw->vqs[i].notify_addr = oct_hw->notify_base + + notify_off * oct_hw->notify_off_multiplier; + oct_hw->vqs[i].cb_notify_addr = (u32 __iomem *)oct_hw->vqs[i].notify_addr + 1; + oct_hw->vqs[i].notify_pa = oct_hw->notify_base_pa + + notify_off * oct_hw->notify_off_multiplier; + } + mbox = octep_get_mbox(oct_hw); + octep_mbox_init(mbox); + dev_info(dev, "mbox mapped at: 0x%016llx\n", (u64)(uintptr_t)mbox); + + return 0; +} diff --git a/drivers/vdpa/octeon_ep/octep_vdpa_main.c b/drivers/vdpa/octeon_ep/octep_vdpa_main.c new file mode 100644 index 000000000000..cd55b1aac151 --- /dev/null +++ b/drivers/vdpa/octeon_ep/octep_vdpa_main.c @@ -0,0 +1,857 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2024 Marvell. */ + +#include +#include +#include +#include +#include "octep_vdpa.h" + +#define OCTEP_VDPA_DRIVER_NAME "octep_vdpa" + +struct octep_pf { + u8 __iomem *base[PCI_STD_NUM_BARS]; + struct pci_dev *pdev; + struct resource res; + u64 vf_base; + int enabled_vfs; + u32 vf_stride; + u16 vf_devid; +}; + +struct octep_vdpa { + struct vdpa_device vdpa; + struct octep_hw *oct_hw; + struct pci_dev *pdev; +}; + +struct octep_vdpa_mgmt_dev { + struct vdpa_mgmt_dev mdev; + struct octep_hw oct_hw; + struct pci_dev *pdev; + /* Work entry to handle device setup */ + struct work_struct setup_task; + /* Device status */ + atomic_t status; +}; + +static struct octep_hw *vdpa_to_octep_hw(struct vdpa_device *vdpa_dev) +{ + struct octep_vdpa *oct_vdpa; + + oct_vdpa = container_of(vdpa_dev, struct octep_vdpa, vdpa); + + return oct_vdpa->oct_hw; +} + +static irqreturn_t octep_vdpa_intr_handler(int irq, void *data) +{ + struct octep_hw *oct_hw = data; + int i; + + for (i = 0; i < oct_hw->nr_vring; i++) { + if (oct_hw->vqs[i].cb.callback && ioread32(oct_hw->vqs[i].cb_notify_addr)) { + /* Acknowledge the per queue notification to the device */ + iowrite32(0, oct_hw->vqs[i].cb_notify_addr); + oct_hw->vqs[i].cb.callback(oct_hw->vqs[i].cb.private); + } + } + + return IRQ_HANDLED; +} + +static void octep_free_irqs(struct octep_hw *oct_hw) +{ + struct pci_dev *pdev = oct_hw->pdev; + + if (oct_hw->irq != -1) { + devm_free_irq(&pdev->dev, oct_hw->irq, oct_hw); + oct_hw->irq = -1; + } + pci_free_irq_vectors(pdev); +} + +static int octep_request_irqs(struct octep_hw *oct_hw) +{ + struct pci_dev *pdev = oct_hw->pdev; + int ret, irq; + + /* Currently HW device provisions one IRQ per VF, hence + * allocate one IRQ for all virtqueues call interface. + */ + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to alloc msix vector"); + return ret; + } + + snprintf(oct_hw->vqs->msix_name, sizeof(oct_hw->vqs->msix_name), + OCTEP_VDPA_DRIVER_NAME "-vf-%d", pci_iov_vf_id(pdev)); + + irq = pci_irq_vector(pdev, 0); + ret = devm_request_irq(&pdev->dev, irq, octep_vdpa_intr_handler, 0, + oct_hw->vqs->msix_name, oct_hw); + if (ret) { + dev_err(&pdev->dev, "Failed to register interrupt handler\n"); + goto free_irq_vec; + } + oct_hw->irq = irq; + + return 0; + +free_irq_vec: + pci_free_irq_vectors(pdev); + return ret; +} + +static u64 octep_vdpa_get_device_features(struct vdpa_device *vdpa_dev) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + return oct_hw->features; +} + +static int octep_vdpa_set_driver_features(struct vdpa_device *vdpa_dev, u64 features) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + int ret; + + pr_debug("Driver Features: %llx\n", features); + + ret = octep_verify_features(features); + if (ret) { + dev_warn(&oct_hw->pdev->dev, + "Must negotiate minimum features 0x%llx for this device", + BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_NOTIFICATION_DATA) | + BIT_ULL(VIRTIO_F_RING_PACKED)); + return ret; + } + octep_hw_set_drv_features(oct_hw, features); + + return 0; +} + +static u64 octep_vdpa_get_driver_features(struct vdpa_device *vdpa_dev) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + return octep_hw_get_drv_features(oct_hw); +} + +static u8 octep_vdpa_get_status(struct vdpa_device *vdpa_dev) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + return octep_hw_get_status(oct_hw); +} + +static void octep_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + u8 status_old; + + status_old = octep_hw_get_status(oct_hw); + + if (status_old == status) + return; + + if ((status & VIRTIO_CONFIG_S_DRIVER_OK) && + !(status_old & VIRTIO_CONFIG_S_DRIVER_OK)) { + if (octep_request_irqs(oct_hw)) + status = status_old | VIRTIO_CONFIG_S_FAILED; + } + octep_hw_set_status(oct_hw, status); +} + +static int octep_vdpa_reset(struct vdpa_device *vdpa_dev) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + u8 status = octep_hw_get_status(oct_hw); + u16 qid; + + if (status == 0) + return 0; + + for (qid = 0; qid < oct_hw->nr_vring; qid++) { + oct_hw->vqs[qid].cb.callback = NULL; + oct_hw->vqs[qid].cb.private = NULL; + oct_hw->config_cb.callback = NULL; + oct_hw->config_cb.private = NULL; + } + octep_hw_reset(oct_hw); + + if (status & VIRTIO_CONFIG_S_DRIVER_OK) + octep_free_irqs(oct_hw); + + return 0; +} + +static u16 octep_vdpa_get_vq_num_max(struct vdpa_device *vdpa_dev) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + return octep_get_vq_size(oct_hw); +} + +static int octep_vdpa_get_vq_state(struct vdpa_device *vdpa_dev, u16 qid, + struct vdpa_vq_state *state) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + return octep_get_vq_state(oct_hw, qid, state); +} + +static int octep_vdpa_set_vq_state(struct vdpa_device *vdpa_dev, u16 qid, + const struct vdpa_vq_state *state) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + return octep_set_vq_state(oct_hw, qid, state); +} + +static void octep_vdpa_set_vq_cb(struct vdpa_device *vdpa_dev, u16 qid, struct vdpa_callback *cb) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + oct_hw->vqs[qid].cb = *cb; +} + +static void octep_vdpa_set_vq_ready(struct vdpa_device *vdpa_dev, u16 qid, bool ready) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + octep_set_vq_ready(oct_hw, qid, ready); +} + +static bool octep_vdpa_get_vq_ready(struct vdpa_device *vdpa_dev, u16 qid) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + return octep_get_vq_ready(oct_hw, qid); +} + +static void octep_vdpa_set_vq_num(struct vdpa_device *vdpa_dev, u16 qid, u32 num) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + octep_set_vq_num(oct_hw, qid, num); +} + +static int octep_vdpa_set_vq_address(struct vdpa_device *vdpa_dev, u16 qid, u64 desc_area, + u64 driver_area, u64 device_area) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + pr_debug("qid[%d]: desc_area: %llx\n", qid, desc_area); + pr_debug("qid[%d]: driver_area: %llx\n", qid, driver_area); + pr_debug("qid[%d]: device_area: %llx\n\n", qid, device_area); + + return octep_set_vq_address(oct_hw, qid, desc_area, driver_area, device_area); +} + +static void octep_vdpa_kick_vq(struct vdpa_device *vdpa_dev, u16 qid) +{ + /* Not supported */ +} + +static void octep_vdpa_kick_vq_with_data(struct vdpa_device *vdpa_dev, u32 data) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + u16 idx = data & 0xFFFF; + + vp_iowrite32(data, oct_hw->vqs[idx].notify_addr); +} + +static u32 octep_vdpa_get_generation(struct vdpa_device *vdpa_dev) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + return vp_ioread8(&oct_hw->common_cfg->config_generation); +} + +static u32 octep_vdpa_get_device_id(struct vdpa_device *vdpa_dev) +{ + return VIRTIO_ID_NET; +} + +static u32 octep_vdpa_get_vendor_id(struct vdpa_device *vdpa_dev) +{ + return PCI_VENDOR_ID_CAVIUM; +} + +static u32 octep_vdpa_get_vq_align(struct vdpa_device *vdpa_dev) +{ + return PAGE_SIZE; +} + +static size_t octep_vdpa_get_config_size(struct vdpa_device *vdpa_dev) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + return oct_hw->config_size; +} + +static void octep_vdpa_get_config(struct vdpa_device *vdpa_dev, unsigned int offset, void *buf, + unsigned int len) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + octep_read_dev_config(oct_hw, offset, buf, len); +} + +static void octep_vdpa_set_config(struct vdpa_device *vdpa_dev, unsigned int offset, + const void *buf, unsigned int len) +{ + /* Not supported */ +} + +static void octep_vdpa_set_config_cb(struct vdpa_device *vdpa_dev, struct vdpa_callback *cb) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + + oct_hw->config_cb.callback = cb->callback; + oct_hw->config_cb.private = cb->private; +} + +static struct vdpa_notification_area octep_get_vq_notification(struct vdpa_device *vdpa_dev, + u16 idx) +{ + struct octep_hw *oct_hw = vdpa_to_octep_hw(vdpa_dev); + struct vdpa_notification_area area; + + area.addr = oct_hw->vqs[idx].notify_pa; + area.size = PAGE_SIZE; + + return area; +} + +static struct vdpa_config_ops octep_vdpa_ops = { + .get_device_features = octep_vdpa_get_device_features, + .set_driver_features = octep_vdpa_set_driver_features, + .get_driver_features = octep_vdpa_get_driver_features, + .get_status = octep_vdpa_get_status, + .set_status = octep_vdpa_set_status, + .reset = octep_vdpa_reset, + .get_vq_num_max = octep_vdpa_get_vq_num_max, + .get_vq_state = octep_vdpa_get_vq_state, + .set_vq_state = octep_vdpa_set_vq_state, + .set_vq_cb = octep_vdpa_set_vq_cb, + .set_vq_ready = octep_vdpa_set_vq_ready, + .get_vq_ready = octep_vdpa_get_vq_ready, + .set_vq_num = octep_vdpa_set_vq_num, + .set_vq_address = octep_vdpa_set_vq_address, + .get_vq_irq = NULL, + .kick_vq = octep_vdpa_kick_vq, + .kick_vq_with_data = octep_vdpa_kick_vq_with_data, + .get_generation = octep_vdpa_get_generation, + .get_device_id = octep_vdpa_get_device_id, + .get_vendor_id = octep_vdpa_get_vendor_id, + .get_vq_align = octep_vdpa_get_vq_align, + .get_config_size = octep_vdpa_get_config_size, + .get_config = octep_vdpa_get_config, + .set_config = octep_vdpa_set_config, + .set_config_cb = octep_vdpa_set_config_cb, + .get_vq_notification = octep_get_vq_notification, +}; + +static int octep_iomap_region(struct pci_dev *pdev, u8 __iomem **tbl, u8 bar) +{ + int ret; + + ret = pci_request_region(pdev, bar, OCTEP_VDPA_DRIVER_NAME); + if (ret) { + dev_err(&pdev->dev, "Failed to request BAR:%u region\n", bar); + return ret; + } + + tbl[bar] = pci_iomap(pdev, bar, pci_resource_len(pdev, bar)); + if (!tbl[bar]) { + dev_err(&pdev->dev, "Failed to iomap BAR:%u\n", bar); + pci_release_region(pdev, bar); + ret = -ENOMEM; + } + + return ret; +} + +static void octep_iounmap_region(struct pci_dev *pdev, u8 __iomem **tbl, u8 bar) +{ + pci_iounmap(pdev, tbl[bar]); + pci_release_region(pdev, bar); +} + +static void octep_vdpa_pf_bar_shrink(struct octep_pf *octpf) +{ + struct pci_dev *pf_dev = octpf->pdev; + struct resource *res = pf_dev->resource + PCI_STD_RESOURCES + 4; + struct pci_bus_region bus_region; + + octpf->res.start = res->start; + octpf->res.end = res->end; + octpf->vf_base = res->start; + + bus_region.start = res->start; + bus_region.end = res->start - 1; + + pcibios_bus_to_resource(pf_dev->bus, res, &bus_region); +} + +static void octep_vdpa_pf_bar_expand(struct octep_pf *octpf) +{ + struct pci_dev *pf_dev = octpf->pdev; + struct resource *res = pf_dev->resource + PCI_STD_RESOURCES + 4; + struct pci_bus_region bus_region; + + bus_region.start = octpf->res.start; + bus_region.end = octpf->res.end; + + pcibios_bus_to_resource(pf_dev->bus, res, &bus_region); +} + +static void octep_vdpa_remove_pf(struct pci_dev *pdev) +{ + struct octep_pf *octpf = pci_get_drvdata(pdev); + + pci_disable_sriov(pdev); + + if (octpf->base[OCTEP_HW_CAPS_BAR]) + octep_iounmap_region(pdev, octpf->base, OCTEP_HW_CAPS_BAR); + + if (octpf->base[OCTEP_HW_MBOX_BAR]) + octep_iounmap_region(pdev, octpf->base, OCTEP_HW_MBOX_BAR); + + octep_vdpa_pf_bar_expand(octpf); +} + +static void octep_vdpa_vf_bar_shrink(struct pci_dev *pdev) +{ + struct resource *vf_res = pdev->resource + PCI_STD_RESOURCES + 4; + + memset(vf_res, 0, sizeof(*vf_res)); +} + +static void octep_vdpa_remove_vf(struct pci_dev *pdev) +{ + struct octep_vdpa_mgmt_dev *mgmt_dev = pci_get_drvdata(pdev); + struct octep_hw *oct_hw; + int status; + + oct_hw = &mgmt_dev->oct_hw; + status = atomic_read(&mgmt_dev->status); + atomic_set(&mgmt_dev->status, OCTEP_VDPA_DEV_STATUS_UNINIT); + + cancel_work_sync(&mgmt_dev->setup_task); + if (status == OCTEP_VDPA_DEV_STATUS_READY) + vdpa_mgmtdev_unregister(&mgmt_dev->mdev); + + if (oct_hw->base[OCTEP_HW_CAPS_BAR]) + octep_iounmap_region(pdev, oct_hw->base, OCTEP_HW_CAPS_BAR); + + if (oct_hw->base[OCTEP_HW_MBOX_BAR]) + octep_iounmap_region(pdev, oct_hw->base, OCTEP_HW_MBOX_BAR); + + octep_vdpa_vf_bar_shrink(pdev); +} + +static void octep_vdpa_remove(struct pci_dev *pdev) +{ + if (pdev->is_virtfn) + octep_vdpa_remove_vf(pdev); + else + octep_vdpa_remove_pf(pdev); +} + +static int octep_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, + const struct vdpa_dev_set_config *config) +{ + struct octep_vdpa_mgmt_dev *mgmt_dev = container_of(mdev, struct octep_vdpa_mgmt_dev, mdev); + struct octep_hw *oct_hw = &mgmt_dev->oct_hw; + struct pci_dev *pdev = oct_hw->pdev; + struct vdpa_device *vdpa_dev; + struct octep_vdpa *oct_vdpa; + u64 device_features; + int ret; + + oct_vdpa = vdpa_alloc_device(struct octep_vdpa, vdpa, &pdev->dev, &octep_vdpa_ops, 1, 1, + NULL, false); + if (IS_ERR(oct_vdpa)) { + dev_err(&pdev->dev, "Failed to allocate vDPA structure for octep vdpa device"); + return PTR_ERR(oct_vdpa); + } + + oct_vdpa->pdev = pdev; + oct_vdpa->vdpa.dma_dev = &pdev->dev; + oct_vdpa->vdpa.mdev = mdev; + oct_vdpa->oct_hw = oct_hw; + vdpa_dev = &oct_vdpa->vdpa; + + device_features = oct_hw->features; + if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { + if (config->device_features & ~device_features) { + dev_err(&pdev->dev, "The provisioned features 0x%llx are not supported by this device with features 0x%llx\n", + config->device_features, device_features); + ret = -EINVAL; + goto vdpa_dev_put; + } + device_features &= config->device_features; + } + + oct_hw->features = device_features; + dev_info(&pdev->dev, "Vdpa management device features : %llx\n", device_features); + + ret = octep_verify_features(device_features); + if (ret) { + dev_warn(mdev->device, + "Must provision minimum features 0x%llx for this device", + BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_ACCESS_PLATFORM) | + BIT_ULL(VIRTIO_F_NOTIFICATION_DATA) | BIT_ULL(VIRTIO_F_RING_PACKED)); + goto vdpa_dev_put; + } + if (name) + ret = dev_set_name(&vdpa_dev->dev, "%s", name); + else + ret = dev_set_name(&vdpa_dev->dev, "vdpa%u", vdpa_dev->index); + + ret = _vdpa_register_device(&oct_vdpa->vdpa, oct_hw->nr_vring); + if (ret) { + dev_err(&pdev->dev, "Failed to register to vDPA bus"); + goto vdpa_dev_put; + } + return 0; + +vdpa_dev_put: + put_device(&oct_vdpa->vdpa.dev); + return ret; +} + +static void octep_vdpa_dev_del(struct vdpa_mgmt_dev *mdev, struct vdpa_device *vdpa_dev) +{ + _vdpa_unregister_device(vdpa_dev); +} + +static const struct vdpa_mgmtdev_ops octep_vdpa_mgmt_dev_ops = { + .dev_add = octep_vdpa_dev_add, + .dev_del = octep_vdpa_dev_del +}; + +static bool get_device_ready_status(u8 __iomem *addr) +{ + u64 signature = readq(addr + OCTEP_VF_MBOX_DATA(0)); + + if (signature == OCTEP_DEV_READY_SIGNATURE) { + writeq(0, addr + OCTEP_VF_MBOX_DATA(0)); + return true; + } + + return false; +} + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static void octep_vdpa_setup_task(struct work_struct *work) +{ + struct octep_vdpa_mgmt_dev *mgmt_dev = container_of(work, struct octep_vdpa_mgmt_dev, + setup_task); + struct pci_dev *pdev = mgmt_dev->pdev; + struct device *dev = &pdev->dev; + struct octep_hw *oct_hw; + unsigned long timeout; + int ret; + + oct_hw = &mgmt_dev->oct_hw; + + atomic_set(&mgmt_dev->status, OCTEP_VDPA_DEV_STATUS_WAIT_FOR_BAR_INIT); + + /* Wait for a maximum of 5 sec */ + timeout = jiffies + msecs_to_jiffies(5000); + while (!time_after(jiffies, timeout)) { + if (get_device_ready_status(oct_hw->base[OCTEP_HW_MBOX_BAR])) { + atomic_set(&mgmt_dev->status, OCTEP_VDPA_DEV_STATUS_INIT); + break; + } + + if (atomic_read(&mgmt_dev->status) >= OCTEP_VDPA_DEV_STATUS_READY) { + dev_info(dev, "Stopping vDPA setup task.\n"); + return; + } + + usleep_range(1000, 1500); + } + + if (atomic_read(&mgmt_dev->status) != OCTEP_VDPA_DEV_STATUS_INIT) { + dev_err(dev, "BAR initialization is timed out\n"); + return; + } + + ret = octep_iomap_region(pdev, oct_hw->base, OCTEP_HW_CAPS_BAR); + if (ret) + return; + + ret = octep_hw_caps_read(oct_hw, pdev); + if (ret < 0) + goto unmap_region; + + mgmt_dev->mdev.ops = &octep_vdpa_mgmt_dev_ops; + mgmt_dev->mdev.id_table = id_table; + mgmt_dev->mdev.max_supported_vqs = oct_hw->nr_vring; + mgmt_dev->mdev.supported_features = oct_hw->features; + mgmt_dev->mdev.config_attr_mask = (1 << VDPA_ATTR_DEV_FEATURES); + mgmt_dev->mdev.device = dev; + + ret = vdpa_mgmtdev_register(&mgmt_dev->mdev); + if (ret) { + dev_err(dev, "Failed to register vdpa management interface\n"); + goto unmap_region; + } + + atomic_set(&mgmt_dev->status, OCTEP_VDPA_DEV_STATUS_READY); + + return; + +unmap_region: + octep_iounmap_region(pdev, oct_hw->base, OCTEP_HW_CAPS_BAR); + oct_hw->base[OCTEP_HW_CAPS_BAR] = NULL; +} + +static int octep_vdpa_probe_vf(struct pci_dev *pdev) +{ + struct octep_vdpa_mgmt_dev *mgmt_dev; + struct device *dev = &pdev->dev; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) { + dev_err(dev, "Failed to enable device\n"); + return ret; + } + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) { + dev_err(dev, "No usable DMA configuration\n"); + return ret; + } + pci_set_master(pdev); + + mgmt_dev = devm_kzalloc(dev, sizeof(struct octep_vdpa_mgmt_dev), GFP_KERNEL); + if (!mgmt_dev) + return -ENOMEM; + + ret = octep_iomap_region(pdev, mgmt_dev->oct_hw.base, OCTEP_HW_MBOX_BAR); + if (ret) + return ret; + + mgmt_dev->pdev = pdev; + pci_set_drvdata(pdev, mgmt_dev); + + atomic_set(&mgmt_dev->status, OCTEP_VDPA_DEV_STATUS_ALLOC); + INIT_WORK(&mgmt_dev->setup_task, octep_vdpa_setup_task); + schedule_work(&mgmt_dev->setup_task); + dev_info(&pdev->dev, "octep vdpa mgmt device setup task is queued\n"); + + return 0; +} + +static void octep_vdpa_assign_barspace(struct pci_dev *vf_dev, struct pci_dev *pf_dev, u8 idx) +{ + struct resource *vf_res = vf_dev->resource + PCI_STD_RESOURCES + 4; + struct resource *pf_res = pf_dev->resource + PCI_STD_RESOURCES + 4; + struct octep_pf *pf = pci_get_drvdata(pf_dev); + struct pci_bus_region bus_region; + + vf_res->name = pci_name(vf_dev); + vf_res->flags = pf_res->flags; + vf_res->parent = (pf_dev->resource + PCI_STD_RESOURCES)->parent; + + bus_region.start = pf->vf_base + idx * pf->vf_stride; + bus_region.end = bus_region.start + pf->vf_stride - 1; + pcibios_bus_to_resource(vf_dev->bus, vf_res, &bus_region); +} + +static int octep_sriov_enable(struct pci_dev *pdev, int num_vfs) +{ + struct octep_pf *pf = pci_get_drvdata(pdev); + u8 __iomem *addr = pf->base[OCTEP_HW_MBOX_BAR]; + struct pci_dev *vf_pdev = NULL; + bool done = false; + int index = 0; + int ret, i; + + ret = pci_enable_sriov(pdev, num_vfs); + if (ret) + return ret; + + pf->enabled_vfs = num_vfs; + + while ((vf_pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, PCI_ANY_ID, vf_pdev))) { + if (vf_pdev->device != pf->vf_devid) + continue; + + octep_vdpa_assign_barspace(vf_pdev, pdev, index); + if (++index == num_vfs) { + done = true; + break; + } + } + + if (done) { + for (i = 0; i < pf->enabled_vfs; i++) + writeq(OCTEP_DEV_READY_SIGNATURE, addr + OCTEP_PF_MBOX_DATA(i)); + } + + return num_vfs; +} + +static int octep_sriov_disable(struct pci_dev *pdev) +{ + struct octep_pf *pf = pci_get_drvdata(pdev); + + if (!pci_num_vf(pdev)) + return 0; + + pci_disable_sriov(pdev); + pf->enabled_vfs = 0; + + return 0; +} + +static int octep_vdpa_sriov_configure(struct pci_dev *pdev, int num_vfs) +{ + if (num_vfs > 0) + return octep_sriov_enable(pdev, num_vfs); + else + return octep_sriov_disable(pdev); +} + +static u16 octep_get_vf_devid(struct pci_dev *pdev) +{ + u16 did; + + switch (pdev->device) { + case OCTEP_VDPA_DEVID_CN106K_PF: + did = OCTEP_VDPA_DEVID_CN106K_VF; + break; + case OCTEP_VDPA_DEVID_CN105K_PF: + did = OCTEP_VDPA_DEVID_CN105K_VF; + break; + case OCTEP_VDPA_DEVID_CN103K_PF: + did = OCTEP_VDPA_DEVID_CN103K_VF; + break; + default: + did = 0xFFFF; + break; + } + + return did; +} + +static int octep_vdpa_pf_setup(struct octep_pf *octpf) +{ + u8 __iomem *addr = octpf->base[OCTEP_HW_MBOX_BAR]; + struct pci_dev *pdev = octpf->pdev; + int totalvfs; + size_t len; + u64 val; + + totalvfs = pci_sriov_get_totalvfs(pdev); + if (unlikely(!totalvfs)) { + dev_info(&pdev->dev, "Total VFs are %d in PF sriov configuration\n", totalvfs); + return 0; + } + + addr = octpf->base[OCTEP_HW_MBOX_BAR]; + val = readq(addr + OCTEP_EPF_RINFO(0)); + if (val == 0) { + dev_err(&pdev->dev, "Invalid device configuration\n"); + return -EINVAL; + } + + if (OCTEP_EPF_RINFO_RPVF(val) != BIT_ULL(0)) { + val &= ~GENMASK_ULL(35, 32); + val |= BIT_ULL(32); + writeq(val, addr + OCTEP_EPF_RINFO(0)); + } + + len = pci_resource_len(pdev, OCTEP_HW_CAPS_BAR); + + octpf->vf_stride = len / totalvfs; + octpf->vf_devid = octep_get_vf_devid(pdev); + + octep_vdpa_pf_bar_shrink(octpf); + + return 0; +} + +static int octep_vdpa_probe_pf(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct octep_pf *octpf; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) { + dev_err(dev, "Failed to enable device\n"); + return ret; + } + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) { + dev_err(dev, "No usable DMA configuration\n"); + return ret; + } + octpf = devm_kzalloc(dev, sizeof(*octpf), GFP_KERNEL); + if (!octpf) + return -ENOMEM; + + ret = octep_iomap_region(pdev, octpf->base, OCTEP_HW_MBOX_BAR); + if (ret) + return ret; + + pci_set_master(pdev); + pci_set_drvdata(pdev, octpf); + octpf->pdev = pdev; + + ret = octep_vdpa_pf_setup(octpf); + if (ret) + goto unmap_region; + + return 0; + +unmap_region: + octep_iounmap_region(pdev, octpf->base, OCTEP_HW_MBOX_BAR); + return ret; +} + +static int octep_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + if (pdev->is_virtfn) + return octep_vdpa_probe_vf(pdev); + else + return octep_vdpa_probe_pf(pdev); +} + +static struct pci_device_id octep_pci_vdpa_map[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_VDPA_DEVID_CN106K_PF) }, + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_VDPA_DEVID_CN106K_VF) }, + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_VDPA_DEVID_CN105K_PF) }, + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_VDPA_DEVID_CN105K_VF) }, + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_VDPA_DEVID_CN103K_PF) }, + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_VDPA_DEVID_CN103K_VF) }, + { 0 }, +}; + +static struct pci_driver octep_pci_vdpa = { + .name = OCTEP_VDPA_DRIVER_NAME, + .id_table = octep_pci_vdpa_map, + .probe = octep_vdpa_probe, + .remove = octep_vdpa_remove, + .sriov_configure = octep_vdpa_sriov_configure +}; + +module_pci_driver(octep_pci_vdpa); + +MODULE_AUTHOR("Marvell"); +MODULE_DESCRIPTION("Marvell Octeon PCIe endpoint vDPA driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From fdba68d2adf8d9ae680e23e8b8ba79330baa45bc Mon Sep 17 00:00:00 2001 From: zhenwei pi Date: Tue, 23 Apr 2024 11:41:06 +0800 Subject: virtio_balloon: separate vm events into a function All the VM events related statistics have dependence on 'CONFIG_VM_EVENT_COUNTERS', separate these events into a function to make code clean. Then we can remove 'CONFIG_VM_EVENT_COUNTERS' from 'update_balloon_stats'. Signed-off-by: zhenwei pi Message-Id: <20240423034109.1552866-2-pizhenwei@bytedance.com> Signed-off-by: Michael S. Tsirkin Reviewed-by: David Hildenbrand --- drivers/virtio/virtio_balloon.c | 43 +++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index c0a63638f95e..9a61febbd2f7 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -349,34 +349,49 @@ static inline void update_stat(struct virtio_balloon *vb, int idx, #define pages_to_bytes(x) ((u64)(x) << PAGE_SHIFT) -static unsigned int update_balloon_stats(struct virtio_balloon *vb) +#ifdef CONFIG_VM_EVENT_COUNTERS +/* Return the number of entries filled by vm events */ +static inline unsigned int update_balloon_vm_stats(struct virtio_balloon *vb) { unsigned long events[NR_VM_EVENT_ITEMS]; - struct sysinfo i; unsigned int idx = 0; - long available; - unsigned long caches; all_vm_events(events); - si_meminfo(&i); - - available = si_mem_available(); - caches = global_node_page_state(NR_FILE_PAGES); - -#ifdef CONFIG_VM_EVENT_COUNTERS update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_IN, - pages_to_bytes(events[PSWPIN])); + pages_to_bytes(events[PSWPIN])); update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_OUT, - pages_to_bytes(events[PSWPOUT])); + pages_to_bytes(events[PSWPOUT])); update_stat(vb, idx++, VIRTIO_BALLOON_S_MAJFLT, events[PGMAJFAULT]); update_stat(vb, idx++, VIRTIO_BALLOON_S_MINFLT, events[PGFAULT]); + #ifdef CONFIG_HUGETLB_PAGE update_stat(vb, idx++, VIRTIO_BALLOON_S_HTLB_PGALLOC, events[HTLB_BUDDY_PGALLOC]); update_stat(vb, idx++, VIRTIO_BALLOON_S_HTLB_PGFAIL, events[HTLB_BUDDY_PGALLOC_FAIL]); -#endif -#endif +#endif /* CONFIG_HUGETLB_PAGE */ + + return idx; +} +#else /* CONFIG_VM_EVENT_COUNTERS */ +static inline unsigned int update_balloon_vm_stats(struct virtio_balloon *vb) +{ + return 0; +} +#endif /* CONFIG_VM_EVENT_COUNTERS */ + +static unsigned int update_balloon_stats(struct virtio_balloon *vb) +{ + struct sysinfo i; + unsigned int idx; + long available; + unsigned long caches; + + idx = update_balloon_vm_stats(vb); + + si_meminfo(&i); + available = si_mem_available(); + caches = global_node_page_state(NR_FILE_PAGES); update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMFREE, pages_to_bytes(i.freeram)); update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMTOT, -- cgit v1.2.3 From 7ad4723976672b7d359403a555e0ce5c75529153 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 30 Apr 2024 09:27:48 +1000 Subject: vhost: move smp_rmb() into vhost_get_avail_idx() All callers of vhost_get_avail_idx() use smp_rmb() to order the available ring entry read and avail_idx read. Make vhost_get_avail_idx() call smp_rmb() itself whenever the avail_idx is accessed. This way, the callers don't need to worry about the memory barrier. As a side benefit, we also validate the index on all paths now, which will hopefully help prevent/catch earlier future bugs. Note that current code is inconsistent in how the errors are handled. They are treated as an empty ring in some places, but as non-empty ring in other places. This patch doesn't attempt to change the existing behaviour. No functional change intended. Signed-off-by: Michael S. Tsirkin Reviewed-by: Gavin Shan Acked-by: Will Deacon Message-Id: <20240429232748.642356-1-gshan@redhat.com> --- drivers/vhost/vhost.c | 105 ++++++++++++++++++++------------------------------ 1 file changed, 42 insertions(+), 63 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index b60955682474..9ac25d08f473 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1346,10 +1346,36 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d) mutex_unlock(&d->vqs[i]->mutex); } -static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq, - __virtio16 *idx) +static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq) { - return vhost_get_avail(vq, *idx, &vq->avail->idx); + __virtio16 idx; + int r; + + r = vhost_get_avail(vq, idx, &vq->avail->idx); + if (unlikely(r < 0)) { + vq_err(vq, "Failed to access available index at %p (%d)\n", + &vq->avail->idx, r); + return r; + } + + /* Check it isn't doing very strange thing with available indexes */ + vq->avail_idx = vhost16_to_cpu(vq, idx); + if (unlikely((u16)(vq->avail_idx - vq->last_avail_idx) > vq->num)) { + vq_err(vq, "Invalid available index change from %u to %u", + vq->last_avail_idx, vq->avail_idx); + return -EINVAL; + } + + /* We're done if there is nothing new */ + if (vq->avail_idx == vq->last_avail_idx) + return 0; + + /* + * We updated vq->avail_idx so we need a memory barrier between + * the index read above and the caller reading avail ring entries. + */ + smp_rmb(); + return 1; } static inline int vhost_get_avail_head(struct vhost_virtqueue *vq, @@ -2554,38 +2580,17 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq, { struct vring_desc desc; unsigned int i, head, found = 0; - u16 last_avail_idx; - __virtio16 avail_idx; + u16 last_avail_idx = vq->last_avail_idx; __virtio16 ring_head; int ret, access; - /* Check it isn't doing very strange things with descriptor numbers. */ - last_avail_idx = vq->last_avail_idx; - if (vq->avail_idx == vq->last_avail_idx) { - if (unlikely(vhost_get_avail_idx(vq, &avail_idx))) { - vq_err(vq, "Failed to access avail idx at %p\n", - &vq->avail->idx); - return -EFAULT; - } - vq->avail_idx = vhost16_to_cpu(vq, avail_idx); - - if (unlikely((u16)(vq->avail_idx - last_avail_idx) > vq->num)) { - vq_err(vq, "Guest moved avail index from %u to %u", - last_avail_idx, vq->avail_idx); - return -EFAULT; - } + ret = vhost_get_avail_idx(vq); + if (unlikely(ret < 0)) + return ret; - /* If there's nothing new since last we looked, return - * invalid. - */ - if (vq->avail_idx == last_avail_idx) + if (!ret) return vq->num; - - /* Only get avail ring entries after they have been - * exposed by guest. - */ - smp_rmb(); } /* Grab the next descriptor number they're advertising, and increment @@ -2846,35 +2851,21 @@ EXPORT_SYMBOL_GPL(vhost_add_used_and_signal_n); /* return true if we're sure that avaiable ring is empty */ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq) { - __virtio16 avail_idx; int r; if (vq->avail_idx != vq->last_avail_idx) return false; - r = vhost_get_avail_idx(vq, &avail_idx); - if (unlikely(r)) - return false; - - vq->avail_idx = vhost16_to_cpu(vq, avail_idx); - if (vq->avail_idx != vq->last_avail_idx) { - /* Since we have updated avail_idx, the following - * call to vhost_get_vq_desc() will read available - * ring entries. Make sure that read happens after - * the avail_idx read. - */ - smp_rmb(); - return false; - } + r = vhost_get_avail_idx(vq); - return true; + /* Note: we treat error as non-empty here */ + return r == 0; } EXPORT_SYMBOL_GPL(vhost_vq_avail_empty); /* OK, now we need to know about added descriptors. */ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) { - __virtio16 avail_idx; int r; if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY)) @@ -2898,25 +2889,13 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) /* They could have slipped one in as we were doing that: make * sure it's written, then check again. */ smp_mb(); - r = vhost_get_avail_idx(vq, &avail_idx); - if (r) { - vq_err(vq, "Failed to check avail idx at %p: %d\n", - &vq->avail->idx, r); - return false; - } - vq->avail_idx = vhost16_to_cpu(vq, avail_idx); - if (vq->avail_idx != vq->last_avail_idx) { - /* Since we have updated avail_idx, the following - * call to vhost_get_vq_desc() will read available - * ring entries. Make sure that read happens after - * the avail_idx read. - */ - smp_rmb(); - return true; - } + r = vhost_get_avail_idx(vq); + /* Note: we treat error as empty here */ + if (unlikely(r < 0)) + return false; - return false; + return r; } EXPORT_SYMBOL_GPL(vhost_enable_notify); -- cgit v1.2.3 From 9be237df09ce0c58b09fa979452bfe3f217e41ce Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Wed, 15 May 2024 00:51:25 +0800 Subject: MAINTAINERS: Change lingshan's email to kernel.org This commit changes lingshan's email from intel.com to kernel.org. Signed-off-by: Zhu Lingshan Message-Id: <20240514165125.74802-1-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index d0249d7538e1..8eefd032c87e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10654,7 +10654,7 @@ F: net/ieee802154/ F: net/mac802154/ Intel VIRTIO DATA PATH ACCELERATOR -M: Zhu Lingshan +M: Zhu Lingshan L: virtualization@lists.linux.dev S: Supported F: drivers/vdpa/ifcvf/ -- cgit v1.2.3 From e400ddf0fb76f451bcf0c7de8a1dbdb1fa0359d5 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 16 May 2024 18:57:32 -0700 Subject: vringh: add MODULE_DESCRIPTION() Fix the allmodconfig 'make w=1' issue: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/vhost/vringh.o Signed-off-by: Jeff Johnson Message-Id: <20240516-md-vringh-v1-1-31bf37779a5a@quicinc.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- drivers/vhost/vringh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index 7b8fd977f71c..73e153f9b449 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -1614,4 +1614,5 @@ EXPORT_SYMBOL(vringh_need_notify_iotlb); #endif +MODULE_DESCRIPTION("host side of a virtio ring"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ab0727f3ddb808d63f862a6fcd658ee65884a22d Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 2 Jul 2024 13:10:18 -0700 Subject: virtio: add missing MODULE_DESCRIPTION() macros With ARCH=sh, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/virtio/virtio.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/virtio/virtio_ring.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Message-Id: <20240702-md-sh-drivers-virtio-v1-1-cf7325ab6ccc@quicinc.com> Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio.c | 1 + drivers/virtio/virtio_ring.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index b968b2aa5f4d..396d3cd49a1b 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -609,4 +609,5 @@ static void __exit virtio_exit(void) core_initcall(virtio_init); module_exit(virtio_exit); +MODULE_DESCRIPTION("Virtio core interface"); MODULE_LICENSE("GPL"); diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 9d3a9942c8c8..be7309b1e860 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -3246,4 +3246,5 @@ void virtqueue_dma_sync_single_range_for_device(struct virtqueue *_vq, } EXPORT_SYMBOL_GPL(virtqueue_dma_sync_single_range_for_device); +MODULE_DESCRIPTION("Virtio ring implementation"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e7909ad6cbab24b9fa0f4b81645d0590ce4ec413 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 11 Jun 2024 12:22:08 -0700 Subject: vDPA: add missing MODULE_DESCRIPTION() macros With ARCH=x86, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/vdpa/vdpa.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/vdpa/ifcvf/ifcvf.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Message-Id: <20240611-md-drivers-vdpa-v1-1-efaf2de15152@quicinc.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/ifcvf/ifcvf_main.c | 1 + drivers/vdpa/vdpa.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index 80d0a0460885..ccf64d7bbfaa 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -894,4 +894,5 @@ static struct pci_driver ifcvf_driver = { module_pci_driver(ifcvf_driver); +MODULE_DESCRIPTION("Intel IFC VF NIC driver for virtio dataplane offloading"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c index 8d391947eb8d..1ca445e31acb 100644 --- a/drivers/vdpa/vdpa.c +++ b/drivers/vdpa/vdpa.c @@ -1538,4 +1538,5 @@ core_initcall(vdpa_init); module_exit(vdpa_exit); MODULE_AUTHOR("Jason Wang "); +MODULE_DESCRIPTION("vDPA bus"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 2106e1f444d9d79f5c3784e5847bfdb6cc3ca69f Mon Sep 17 00:00:00 2001 From: Peter-Jan Gootzen Date: Fri, 17 May 2024 21:04:34 +0200 Subject: virtio-fs: let -ENOMEM bubble up or burst gently Currently, when the enqueueing of a request or forget operation fails with -ENOMEM, the enqueueing is retried after a timeout. This patch removes this behavior and treats -ENOMEM in these scenarios like any other error. By bubbling up the error to user space in the case of a request, and by dropping the operation in case of a forget. This behavior matches that of the FUSE layer above, and also simplifies the error handling. The latter will come in handy for upcoming patches that optimize the retrying of operations in case of -ENOSPC. Signed-off-by: Peter-Jan Gootzen Reviewed-by: Max Gurtovoy Reviewed-by: Yoray Zack Message-Id: <20240517190435.152096-2-pgootzen@nvidia.com> Signed-off-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi --- fs/fuse/virtio_fs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 1a52a51b6b07..3cc2a1f81014 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -447,7 +447,7 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work) ret = virtio_fs_enqueue_req(fsvq, req, true); if (ret < 0) { - if (ret == -ENOMEM || ret == -ENOSPC) { + if (ret == -ENOSPC) { spin_lock(&fsvq->lock); list_add_tail(&req->list, &fsvq->queued_reqs); schedule_delayed_work(&fsvq->dispatch_work, @@ -494,7 +494,7 @@ static int send_forget_request(struct virtio_fs_vq *fsvq, ret = virtqueue_add_outbuf(vq, &sg, 1, forget, GFP_ATOMIC); if (ret < 0) { - if (ret == -ENOMEM || ret == -ENOSPC) { + if (ret == -ENOSPC) { pr_debug("virtio-fs: Could not queue FORGET: err=%d. Will try later\n", ret); list_add_tail(&forget->list, &fsvq->queued_reqs); @@ -1367,7 +1367,7 @@ __releases(fiq->lock) fsvq = &fs->vqs[queue_id]; ret = virtio_fs_enqueue_req(fsvq, req, false); if (ret < 0) { - if (ret == -ENOMEM || ret == -ENOSPC) { + if (ret == -ENOSPC) { /* * Virtqueue full. Retry submission from worker * context as we might be holding fc->bg_lock. -- cgit v1.2.3 From 106e4df1206b2c239ba13a9ec2fd1e9b754bd455 Mon Sep 17 00:00:00 2001 From: Peter-Jan Gootzen Date: Fri, 17 May 2024 21:04:35 +0200 Subject: virtio-fs: improved request latencies when Virtio queue is full Currently, when the Virtio queue is full, a work item is scheduled to execute in 1ms that retries adding the request to the queue. This is a large amount of time on the scale on which a virtio-fs device can operate. When using a DPU this is around 30-40us baseline without going to a remote server (4k, QD=1). This patch changes the retrying behavior to immediately filling the Virtio queue up again when a completion has been received. This reduces the 99.9th percentile latencies in our tests by 60x and slightly increases the overall throughput, when using a workload IO depth 2x the size of the Virtio queue and a DPU-powered virtio-fs device (NVIDIA BlueField DPU). Signed-off-by: Peter-Jan Gootzen Reviewed-by: Max Gurtovoy Reviewed-by: Yoray Zack Message-Id: <20240517190435.152096-3-pgootzen@nvidia.com> Signed-off-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi --- fs/fuse/virtio_fs.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 3cc2a1f81014..728f14e077bd 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -51,7 +51,7 @@ struct virtio_fs_vq { struct work_struct done_work; struct list_head queued_reqs; struct list_head end_reqs; /* End these requests */ - struct delayed_work dispatch_work; + struct work_struct dispatch_work; struct fuse_dev *fud; bool connected; long in_flight; @@ -233,7 +233,7 @@ static void virtio_fs_drain_queue(struct virtio_fs_vq *fsvq) } flush_work(&fsvq->done_work); - flush_delayed_work(&fsvq->dispatch_work); + flush_work(&fsvq->dispatch_work); } static void virtio_fs_drain_all_queues_locked(struct virtio_fs *fs) @@ -408,6 +408,10 @@ static void virtio_fs_hiprio_done_work(struct work_struct *work) dec_in_flight_req(fsvq); } } while (!virtqueue_enable_cb(vq)); + + if (!list_empty(&fsvq->queued_reqs)) + schedule_work(&fsvq->dispatch_work); + spin_unlock(&fsvq->lock); } @@ -415,7 +419,7 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work) { struct fuse_req *req; struct virtio_fs_vq *fsvq = container_of(work, struct virtio_fs_vq, - dispatch_work.work); + dispatch_work); int ret; pr_debug("virtio-fs: worker %s called.\n", __func__); @@ -450,8 +454,6 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work) if (ret == -ENOSPC) { spin_lock(&fsvq->lock); list_add_tail(&req->list, &fsvq->queued_reqs); - schedule_delayed_work(&fsvq->dispatch_work, - msecs_to_jiffies(1)); spin_unlock(&fsvq->lock); return; } @@ -498,8 +500,6 @@ static int send_forget_request(struct virtio_fs_vq *fsvq, pr_debug("virtio-fs: Could not queue FORGET: err=%d. Will try later\n", ret); list_add_tail(&forget->list, &fsvq->queued_reqs); - schedule_delayed_work(&fsvq->dispatch_work, - msecs_to_jiffies(1)); if (!in_flight) inc_in_flight_req(fsvq); /* Queue is full */ @@ -531,7 +531,7 @@ static void virtio_fs_hiprio_dispatch_work(struct work_struct *work) { struct virtio_fs_forget *forget; struct virtio_fs_vq *fsvq = container_of(work, struct virtio_fs_vq, - dispatch_work.work); + dispatch_work); pr_debug("virtio-fs: worker %s called.\n", __func__); while (1) { spin_lock(&fsvq->lock); @@ -709,6 +709,12 @@ static void virtio_fs_requests_done_work(struct work_struct *work) virtio_fs_request_complete(req, fsvq); } } + + /* Try to push previously queued requests, as the queue might no longer be full */ + spin_lock(&fsvq->lock); + if (!list_empty(&fsvq->queued_reqs)) + schedule_work(&fsvq->dispatch_work); + spin_unlock(&fsvq->lock); } static void virtio_fs_map_queues(struct virtio_device *vdev, struct virtio_fs *fs) @@ -770,12 +776,12 @@ static void virtio_fs_init_vq(struct virtio_fs_vq *fsvq, char *name, if (vq_type == VQ_REQUEST) { INIT_WORK(&fsvq->done_work, virtio_fs_requests_done_work); - INIT_DELAYED_WORK(&fsvq->dispatch_work, - virtio_fs_request_dispatch_work); + INIT_WORK(&fsvq->dispatch_work, + virtio_fs_request_dispatch_work); } else { INIT_WORK(&fsvq->done_work, virtio_fs_hiprio_done_work); - INIT_DELAYED_WORK(&fsvq->dispatch_work, - virtio_fs_hiprio_dispatch_work); + INIT_WORK(&fsvq->dispatch_work, + virtio_fs_hiprio_dispatch_work); } } @@ -1375,8 +1381,6 @@ __releases(fiq->lock) spin_lock(&fsvq->lock); list_add_tail(&req->list, &fsvq->queued_reqs); inc_in_flight_req(fsvq); - schedule_delayed_work(&fsvq->dispatch_work, - msecs_to_jiffies(1)); spin_unlock(&fsvq->lock); return; } @@ -1386,7 +1390,7 @@ __releases(fiq->lock) /* Can't end request in submission context. Use a worker */ spin_lock(&fsvq->lock); list_add_tail(&req->list, &fsvq->end_reqs); - schedule_delayed_work(&fsvq->dispatch_work, 0); + schedule_work(&fsvq->dispatch_work); spin_unlock(&fsvq->lock); return; } -- cgit v1.2.3 From 1f5d6476f12152bfdfcc362b3413f58ab8be397c Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:37 +0300 Subject: vdpa/mlx5: Clarify meaning thorough function rename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setup_driver()/teardown_driver() are a bit vague. These functions are used for virtqueue resources. Same for alloc_resources()/teardown_resources(): they represent fixed resources that are meant to exist during the device lifetime. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-1-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index ecfc16151d61..3422da0e344b 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -144,10 +144,10 @@ static bool is_index_valid(struct mlx5_vdpa_dev *mvdev, u16 idx) return idx <= mvdev->max_idx; } -static void free_resources(struct mlx5_vdpa_net *ndev); +static void free_fixed_resources(struct mlx5_vdpa_net *ndev); static void init_mvqs(struct mlx5_vdpa_net *ndev); -static int setup_driver(struct mlx5_vdpa_dev *mvdev); -static void teardown_driver(struct mlx5_vdpa_net *ndev); +static int setup_vq_resources(struct mlx5_vdpa_dev *mvdev); +static void teardown_vq_resources(struct mlx5_vdpa_net *ndev); static bool mlx5_vdpa_debug; @@ -2848,7 +2848,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, if (err) return err; - teardown_driver(ndev); + teardown_vq_resources(ndev); } mlx5_vdpa_update_mr(mvdev, new_mr, asid); @@ -2862,7 +2862,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, if (teardown) { restore_channels_info(ndev); - err = setup_driver(mvdev); + err = setup_vq_resources(mvdev); if (err) return err; } @@ -2873,7 +2873,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, } /* reslock must be held for this function */ -static int setup_driver(struct mlx5_vdpa_dev *mvdev) +static int setup_vq_resources(struct mlx5_vdpa_dev *mvdev) { struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); int err; @@ -2931,7 +2931,7 @@ out: } /* reslock must be held for this function */ -static void teardown_driver(struct mlx5_vdpa_net *ndev) +static void teardown_vq_resources(struct mlx5_vdpa_net *ndev) { WARN_ON(!rwsem_is_locked(&ndev->reslock)); @@ -2997,7 +2997,7 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) goto err_setup; } register_link_notifier(ndev); - err = setup_driver(mvdev); + err = setup_vq_resources(mvdev); if (err) { mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); goto err_driver; @@ -3040,7 +3040,7 @@ static int mlx5_vdpa_compat_reset(struct vdpa_device *vdev, u32 flags) down_write(&ndev->reslock); unregister_link_notifier(ndev); - teardown_driver(ndev); + teardown_vq_resources(ndev); clear_vqs_ready(ndev); if (flags & VDPA_RESET_F_CLEAN_MAP) mlx5_vdpa_destroy_mr_resources(&ndev->mvdev); @@ -3197,7 +3197,7 @@ static void mlx5_vdpa_free(struct vdpa_device *vdev) ndev = to_mlx5_vdpa_ndev(mvdev); - free_resources(ndev); + free_fixed_resources(ndev); mlx5_vdpa_destroy_mr_resources(mvdev); if (!is_zero_ether_addr(ndev->config.mac)) { pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev)); @@ -3467,7 +3467,7 @@ static int query_mtu(struct mlx5_core_dev *mdev, u16 *mtu) return 0; } -static int alloc_resources(struct mlx5_vdpa_net *ndev) +static int alloc_fixed_resources(struct mlx5_vdpa_net *ndev) { struct mlx5_vdpa_net_resources *res = &ndev->res; int err; @@ -3494,7 +3494,7 @@ err_tis: return err; } -static void free_resources(struct mlx5_vdpa_net *ndev) +static void free_fixed_resources(struct mlx5_vdpa_net *ndev) { struct mlx5_vdpa_net_resources *res = &ndev->res; @@ -3735,7 +3735,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, goto err_res; } - err = alloc_resources(ndev); + err = alloc_fixed_resources(ndev); if (err) goto err_mr; @@ -3758,7 +3758,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, err_reg: destroy_workqueue(mvdev->wq); err_res2: - free_resources(ndev); + free_fixed_resources(ndev); err_mr: mlx5_vdpa_destroy_mr_resources(mvdev); err_res: -- cgit v1.2.3 From 63f0cbad9781ae69b421f33114f26079c903a024 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:38 +0300 Subject: vdpa/mlx5: Make setup/teardown_vq_resources() symmetrical MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... by changing the setup_vq_resources() parameter type. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-2-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 3422da0e344b..1ad281cbc541 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -146,7 +146,7 @@ static bool is_index_valid(struct mlx5_vdpa_dev *mvdev, u16 idx) static void free_fixed_resources(struct mlx5_vdpa_net *ndev); static void init_mvqs(struct mlx5_vdpa_net *ndev); -static int setup_vq_resources(struct mlx5_vdpa_dev *mvdev); +static int setup_vq_resources(struct mlx5_vdpa_net *ndev); static void teardown_vq_resources(struct mlx5_vdpa_net *ndev); static bool mlx5_vdpa_debug; @@ -2862,7 +2862,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, if (teardown) { restore_channels_info(ndev); - err = setup_vq_resources(mvdev); + err = setup_vq_resources(ndev); if (err) return err; } @@ -2873,9 +2873,9 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, } /* reslock must be held for this function */ -static int setup_vq_resources(struct mlx5_vdpa_dev *mvdev) +static int setup_vq_resources(struct mlx5_vdpa_net *ndev) { - struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); + struct mlx5_vdpa_dev *mvdev = &ndev->mvdev; int err; WARN_ON(!rwsem_is_locked(&ndev->reslock)); @@ -2997,7 +2997,7 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) goto err_setup; } register_link_notifier(ndev); - err = setup_vq_resources(mvdev); + err = setup_vq_resources(ndev); if (err) { mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); goto err_driver; -- cgit v1.2.3 From 4c90a60ac2e09bcf615f7276d2fd1b2ba96bdce0 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:39 +0300 Subject: vdpa/mlx5: Drop redundant code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Originally, the second loop initialized the CVQ. But (acde3929492b ("vdpa/mlx5: Use consistent RQT size") initialized all the queues in the first loop, so the second iteration in init_mvqs() is never called because the first one will iterate up to max_vqs. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-3-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 1ad281cbc541..b4d9ef4f66c8 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -3519,12 +3519,6 @@ static void init_mvqs(struct mlx5_vdpa_net *ndev) mvq->fwqp.fw = true; mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_NONE; } - for (; i < ndev->mvdev.max_vqs; i++) { - mvq = &ndev->vqs[i]; - memset(mvq, 0, offsetof(struct mlx5_vdpa_virtqueue, ri)); - mvq->index = i; - mvq->ndev = ndev; - } } struct mlx5_vdpa_mgmtdev { -- cgit v1.2.3 From ad80739262b5aed3621accbd6015d55a6e662294 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:40 +0300 Subject: vdpa/mlx5: Drop redundant check in teardown_virtqueues() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The check is done inside teardown_vq(). Reviewed-by: Cosmin Ratiu Reviewed-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-4-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index b4d9ef4f66c8..96782b34e2b2 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2559,16 +2559,10 @@ err_vq: static void teardown_virtqueues(struct mlx5_vdpa_net *ndev) { - struct mlx5_vdpa_virtqueue *mvq; int i; - for (i = ndev->mvdev.max_vqs - 1; i >= 0; i--) { - mvq = &ndev->vqs[i]; - if (!mvq->initialized) - continue; - - teardown_vq(ndev, mvq); - } + for (i = ndev->mvdev.max_vqs - 1; i >= 0; i--) + teardown_vq(ndev, &ndev->vqs[i]); } static void update_cvq_info(struct mlx5_vdpa_dev *mvdev) -- cgit v1.2.3 From 34bd86c7202222ee588a33aee993fa29cd181e83 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:41 +0300 Subject: vdpa/mlx5: Iterate over active VQs during suspend/resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to iterate over max number of VQs. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-5-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 96782b34e2b2..51630b1935f4 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1504,7 +1504,7 @@ static void suspend_vqs(struct mlx5_vdpa_net *ndev) { int i; - for (i = 0; i < ndev->mvdev.max_vqs; i++) + for (i = 0; i < ndev->cur_num_vqs; i++) suspend_vq(ndev, &ndev->vqs[i]); } @@ -1522,7 +1522,7 @@ static void resume_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mv static void resume_vqs(struct mlx5_vdpa_net *ndev) { - for (int i = 0; i < ndev->mvdev.max_vqs; i++) + for (int i = 0; i < ndev->cur_num_vqs; i++) resume_vq(ndev, &ndev->vqs[i]); } -- cgit v1.2.3 From a366465b4828b55e12f3a4cc0738bd5755d7077d Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:42 +0300 Subject: vdpa/mlx5: Remove duplicate suspend code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the dedicated suspend_vqs() function instead. Reviewed-by: Cosmin Ratiu Reviewed-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-6-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 51630b1935f4..eca6f68c2eda 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -3355,17 +3355,12 @@ static int mlx5_vdpa_suspend(struct vdpa_device *vdev) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); - struct mlx5_vdpa_virtqueue *mvq; - int i; mlx5_vdpa_info(mvdev, "suspending device\n"); down_write(&ndev->reslock); unregister_link_notifier(ndev); - for (i = 0; i < ndev->cur_num_vqs; i++) { - mvq = &ndev->vqs[i]; - suspend_vq(ndev, mvq); - } + suspend_vqs(ndev); mlx5_vdpa_cvq_suspend(mvdev); mvdev->suspended = true; up_write(&ndev->reslock); -- cgit v1.2.3 From 1835ed4a5d49d2280731cfcc43a55473d77ea666 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:43 +0300 Subject: vdpa/mlx5: Initialize and reset device with one queue pair MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The virtio spec says that a vdpa device should start off with one queue pair. The driver is already compliant. This patch moves the initialization to device add and reset times. This is done in preparation for the pre-creation of hardware virtqueues at device add time. Signed-off-by: Dragos Tatulea Reviewed-by: Cosmin Ratiu Message-Id: <20240626-stage-vdpa-vq-precreate-v2-7-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin Acked-by: Eugenio PĂ©rez --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index eca6f68c2eda..c8b5c87f001d 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -48,6 +48,16 @@ MODULE_LICENSE("Dual BSD/GPL"); #define MLX5V_UNTAGGED 0x1000 +/* Device must start with 1 queue pair, as per VIRTIO v1.2 spec, section + * 5.1.6.5.5 "Device operation in multiqueue mode": + * + * Multiqueue is disabled by default. + * The driver enables multiqueue by sending a command using class + * VIRTIO_NET_CTRL_MQ. The command selects the mode of multiqueue + * operation, as follows: ... + */ +#define MLX5V_DEFAULT_VQ_COUNT 2 + struct mlx5_vdpa_cq_buf { struct mlx5_frag_buf_ctrl fbc; struct mlx5_frag_buf frag_buf; @@ -2713,16 +2723,6 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) else ndev->rqt_size = 1; - /* Device must start with 1 queue pair, as per VIRTIO v1.2 spec, section - * 5.1.6.5.5 "Device operation in multiqueue mode": - * - * Multiqueue is disabled by default. - * The driver enables multiqueue by sending a command using class - * VIRTIO_NET_CTRL_MQ. The command selects the mode of multiqueue - * operation, as follows: ... - */ - ndev->cur_num_vqs = 2; - update_cvq_info(mvdev); return err; } @@ -3040,7 +3040,7 @@ static int mlx5_vdpa_compat_reset(struct vdpa_device *vdev, u32 flags) mlx5_vdpa_destroy_mr_resources(&ndev->mvdev); ndev->mvdev.status = 0; ndev->mvdev.suspended = false; - ndev->cur_num_vqs = 0; + ndev->cur_num_vqs = MLX5V_DEFAULT_VQ_COUNT; ndev->mvdev.cvq.received_desc = 0; ndev->mvdev.cvq.completed_desc = 0; memset(ndev->event_cbs, 0, sizeof(*ndev->event_cbs) * (mvdev->max_vqs + 1)); @@ -3643,6 +3643,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, err = -ENOMEM; goto err_alloc; } + ndev->cur_num_vqs = MLX5V_DEFAULT_VQ_COUNT; init_mvqs(ndev); allocate_irqs(ndev); -- cgit v1.2.3 From e5bcbd1de67611201873806d4d11ddfd172d0d12 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:44 +0300 Subject: vdpa/mlx5: Clear and reinitialize software VQ data on reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardware VQ configuration is mirrored by data in struct mlx5_vdpa_virtqueue . Instead of clearing just a few fields at reset, fully clear the struct and initialize with the appropriate default values. As clear_vqs_ready() is used only during reset, get rid of it. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-8-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index c8b5c87f001d..de013b5a2815 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2941,18 +2941,6 @@ static void teardown_vq_resources(struct mlx5_vdpa_net *ndev) ndev->setup = false; } -static void clear_vqs_ready(struct mlx5_vdpa_net *ndev) -{ - int i; - - for (i = 0; i < ndev->mvdev.max_vqs; i++) { - ndev->vqs[i].ready = false; - ndev->vqs[i].modified_fields = 0; - } - - ndev->mvdev.cvq.ready = false; -} - static int setup_cvq_vring(struct mlx5_vdpa_dev *mvdev) { struct mlx5_control_vq *cvq = &mvdev->cvq; @@ -3035,12 +3023,14 @@ static int mlx5_vdpa_compat_reset(struct vdpa_device *vdev, u32 flags) down_write(&ndev->reslock); unregister_link_notifier(ndev); teardown_vq_resources(ndev); - clear_vqs_ready(ndev); + init_mvqs(ndev); + if (flags & VDPA_RESET_F_CLEAN_MAP) mlx5_vdpa_destroy_mr_resources(&ndev->mvdev); ndev->mvdev.status = 0; ndev->mvdev.suspended = false; ndev->cur_num_vqs = MLX5V_DEFAULT_VQ_COUNT; + ndev->mvdev.cvq.ready = false; ndev->mvdev.cvq.received_desc = 0; ndev->mvdev.cvq.completed_desc = 0; memset(ndev->event_cbs, 0, sizeof(*ndev->event_cbs) * (mvdev->max_vqs + 1)); -- cgit v1.2.3 From 4a19f2942a0fe5e4aba7925eda4dc845bd276d25 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:45 +0300 Subject: vdpa/mlx5: Rename init_mvqs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function is used to set default values, so name it accordingly. Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-9-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin Reviewed-by: Eugenio PĂ©rez --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index de013b5a2815..739c2886fc33 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -155,7 +155,7 @@ static bool is_index_valid(struct mlx5_vdpa_dev *mvdev, u16 idx) } static void free_fixed_resources(struct mlx5_vdpa_net *ndev); -static void init_mvqs(struct mlx5_vdpa_net *ndev); +static void mvqs_set_defaults(struct mlx5_vdpa_net *ndev); static int setup_vq_resources(struct mlx5_vdpa_net *ndev); static void teardown_vq_resources(struct mlx5_vdpa_net *ndev); @@ -2810,7 +2810,7 @@ static void restore_channels_info(struct mlx5_vdpa_net *ndev) int i; mlx5_clear_vqs(ndev); - init_mvqs(ndev); + mvqs_set_defaults(ndev); for (i = 0; i < ndev->mvdev.max_vqs; i++) { mvq = &ndev->vqs[i]; ri = &mvq->ri; @@ -3023,7 +3023,7 @@ static int mlx5_vdpa_compat_reset(struct vdpa_device *vdev, u32 flags) down_write(&ndev->reslock); unregister_link_notifier(ndev); teardown_vq_resources(ndev); - init_mvqs(ndev); + mvqs_set_defaults(ndev); if (flags & VDPA_RESET_F_CLEAN_MAP) mlx5_vdpa_destroy_mr_resources(&ndev->mvdev); @@ -3485,7 +3485,7 @@ static void free_fixed_resources(struct mlx5_vdpa_net *ndev) res->valid = false; } -static void init_mvqs(struct mlx5_vdpa_net *ndev) +static void mvqs_set_defaults(struct mlx5_vdpa_net *ndev) { struct mlx5_vdpa_virtqueue *mvq; int i; @@ -3635,7 +3635,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, } ndev->cur_num_vqs = MLX5V_DEFAULT_VQ_COUNT; - init_mvqs(ndev); + mvqs_set_defaults(ndev); allocate_irqs(ndev); init_rwsem(&ndev->reslock); config = &ndev->config; -- cgit v1.2.3 From f70080c5bc39716f434e7c0888662aa077eb4405 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:46 +0300 Subject: vdpa/mlx5: Add support for modifying the virtio_version VQ field This is done in preparation for the pre-creation of hardware virtqueues at device add time. Signed-off-by: Dragos Tatulea Reviewed-by: Cosmin Ratiu Message-Id: <20240626-stage-vdpa-vq-precreate-v2-10-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 16 ++++++++++++++++ include/linux/mlx5/mlx5_ifc_vdpa.h | 1 + 2 files changed, 17 insertions(+) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 739c2886fc33..b104849f8477 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1283,6 +1283,10 @@ static int modify_virtqueue(struct mlx5_vdpa_net *ndev, if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_USED_IDX) MLX5_SET(virtio_net_q_object, obj_context, hw_used_index, mvq->used_idx); + if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_QUEUE_VIRTIO_VERSION) + MLX5_SET(virtio_q, vq_ctx, virtio_version_1_0, + !!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_F_VERSION_1))); + if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY) { vq_mr = mvdev->mr[mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP]]; @@ -2709,6 +2713,7 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); + u64 old_features = mvdev->actual_features; int err; print_features(mvdev, features, true); @@ -2723,6 +2728,17 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) else ndev->rqt_size = 1; + /* Interested in changes of vq features only. */ + if (get_features(old_features) != get_features(mvdev->actual_features)) { + for (int i = 0; i < mvdev->max_vqs; ++i) { + struct mlx5_vdpa_virtqueue *mvq = &ndev->vqs[i]; + + mvq->modified_fields |= ( + MLX5_VIRTQ_MODIFY_MASK_QUEUE_VIRTIO_VERSION + ); + } + } + update_cvq_info(mvdev); return err; } diff --git a/include/linux/mlx5/mlx5_ifc_vdpa.h b/include/linux/mlx5/mlx5_ifc_vdpa.h index 40371c916cf9..34f27c01cec9 100644 --- a/include/linux/mlx5/mlx5_ifc_vdpa.h +++ b/include/linux/mlx5/mlx5_ifc_vdpa.h @@ -148,6 +148,7 @@ enum { MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_ADDRS = (u64)1 << 6, MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_AVAIL_IDX = (u64)1 << 7, MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_USED_IDX = (u64)1 << 8, + MLX5_VIRTQ_MODIFY_MASK_QUEUE_VIRTIO_VERSION = (u64)1 << 10, MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY = (u64)1 << 11, MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY = (u64)1 << 14, }; -- cgit v1.2.3 From cdc3c7eaae695738b37f374866950602ec5af9c2 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:47 +0300 Subject: vdpa/mlx5: Add support for modifying the VQ features field This is done in preparation for the pre-creation of hardware virtqueues at device add time. Signed-off-by: Dragos Tatulea Reviewed-by: Cosmin Ratiu Message-Id: <20240626-stage-vdpa-vq-precreate-v2-11-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 12 +++++++++++- include/linux/mlx5/mlx5_ifc_vdpa.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index b104849f8477..db86e541b788 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1287,6 +1287,15 @@ static int modify_virtqueue(struct mlx5_vdpa_net *ndev, MLX5_SET(virtio_q, vq_ctx, virtio_version_1_0, !!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_F_VERSION_1))); + if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_QUEUE_FEATURES) { + u16 mlx_features = get_features(ndev->mvdev.actual_features); + + MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_12_3, + mlx_features >> 3); + MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_2_0, + mlx_features & 7); + } + if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY) { vq_mr = mvdev->mr[mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP]]; @@ -2734,7 +2743,8 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) struct mlx5_vdpa_virtqueue *mvq = &ndev->vqs[i]; mvq->modified_fields |= ( - MLX5_VIRTQ_MODIFY_MASK_QUEUE_VIRTIO_VERSION + MLX5_VIRTQ_MODIFY_MASK_QUEUE_VIRTIO_VERSION | + MLX5_VIRTQ_MODIFY_MASK_QUEUE_FEATURES ); } } diff --git a/include/linux/mlx5/mlx5_ifc_vdpa.h b/include/linux/mlx5/mlx5_ifc_vdpa.h index 34f27c01cec9..58dfa2ee7c83 100644 --- a/include/linux/mlx5/mlx5_ifc_vdpa.h +++ b/include/linux/mlx5/mlx5_ifc_vdpa.h @@ -150,6 +150,7 @@ enum { MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_USED_IDX = (u64)1 << 8, MLX5_VIRTQ_MODIFY_MASK_QUEUE_VIRTIO_VERSION = (u64)1 << 10, MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY = (u64)1 << 11, + MLX5_VIRTQ_MODIFY_MASK_QUEUE_FEATURES = (u64)1 << 12, MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY = (u64)1 << 14, }; -- cgit v1.2.3 From ad9758fdafeeee52b4b31cad20acfaa8adca8b6a Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:48 +0300 Subject: vdpa/mlx5: Set an initial size on the VQ The virtqueue size is a pre-requisite for setting up any virtqueue resources. For the upcoming optimization of creating virtqueues at device add, the virtqueue size has to be configured. The queue size check in setup_vq() will always be false. So remove it. Signed-off-by: Dragos Tatulea Reviewed-by: Cosmin Ratiu Message-Id: <20240626-stage-vdpa-vq-precreate-v2-12-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index db86e541b788..406cc590fe42 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -58,6 +58,8 @@ MODULE_LICENSE("Dual BSD/GPL"); */ #define MLX5V_DEFAULT_VQ_COUNT 2 +#define MLX5V_DEFAULT_VQ_SIZE 256 + struct mlx5_vdpa_cq_buf { struct mlx5_frag_buf_ctrl fbc; struct mlx5_frag_buf frag_buf; @@ -1445,9 +1447,6 @@ static int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) u16 idx = mvq->index; int err; - if (!mvq->num_ent) - return 0; - if (mvq->initialized) return 0; @@ -3523,6 +3522,7 @@ static void mvqs_set_defaults(struct mlx5_vdpa_net *ndev) mvq->ndev = ndev; mvq->fwqp.fw = true; mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_NONE; + mvq->num_ent = MLX5V_DEFAULT_VQ_SIZE; } } -- cgit v1.2.3 From 1e8dac7bb6ca9cdd7263d1526fa974353cf4ef05 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:49 +0300 Subject: vdpa/mlx5: Start off rqt_size with max VQPs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently rqt_size is initialized during device flag configuration. That's because it is the earliest moment when device knows if MQ (multi queue) is on or off. Shift this configuration earlier to device creation time. This implies that non-MQ devices will have a larger RQT size. But the configuration will still be correct. This is done in preparation for the pre-creation of hardware virtqueues at device add time. When that change will be added, RQT will be created at device creation time so it needs to be initialized to its max size. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-13-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 406cc590fe42..7f1551aa1f78 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2731,10 +2731,6 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) return err; ndev->mvdev.actual_features = features & ndev->mvdev.mlx_features; - if (ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_MQ)) - ndev->rqt_size = mlx5vdpa16_to_cpu(mvdev, ndev->config.max_virtqueue_pairs); - else - ndev->rqt_size = 1; /* Interested in changes of vq features only. */ if (get_features(old_features) != get_features(mvdev->actual_features)) { @@ -3718,8 +3714,12 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, goto err_alloc; } - if (device_features & BIT_ULL(VIRTIO_NET_F_MQ)) + if (device_features & BIT_ULL(VIRTIO_NET_F_MQ)) { config->max_virtqueue_pairs = cpu_to_mlx5vdpa16(mvdev, max_vqs / 2); + ndev->rqt_size = max_vqs / 2; + } else { + ndev->rqt_size = 1; + } ndev->mvdev.mlx_features = device_features; mvdev->vdev.dma_dev = &mdev->pdev->dev; -- cgit v1.2.3 From ebebaf45e8a5da3c23459e91fbc441ee98bef8fd Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:50 +0300 Subject: vdpa/mlx5: Set mkey modified flags on all VQs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise, when virtqueues are moved from INIT to READY the latest mkey will not be set appropriately. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-14-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 7f1551aa1f78..a8ac542f30f7 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2868,7 +2868,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, mlx5_vdpa_update_mr(mvdev, new_mr, asid); - for (int i = 0; i < ndev->cur_num_vqs; i++) + for (int i = 0; i < mvdev->max_vqs; i++) ndev->vqs[i].modified_fields |= MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY | MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY; -- cgit v1.2.3 From e60e9eeb3659776d3e450a5a86ca8b6f6594bced Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:51 +0300 Subject: vdpa/mlx5: Allow creation of blank VQs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on the filled flag, create VQs that are filled or blank. Blank VQs will be filled in later through VQ modify. Downstream patches will make use of this to pre-create blank VQs at vdpa device creation. Signed-off-by: Dragos Tatulea Reviewed-by: Cosmin Ratiu Message-Id: <20240626-stage-vdpa-vq-precreate-v2-15-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin Acked-by: Eugenio PĂ©rez Acked-by: Eugenio PĂ©rez --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 85 +++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index a8ac542f30f7..0a62ce0b4af8 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -158,7 +158,7 @@ static bool is_index_valid(struct mlx5_vdpa_dev *mvdev, u16 idx) static void free_fixed_resources(struct mlx5_vdpa_net *ndev); static void mvqs_set_defaults(struct mlx5_vdpa_net *ndev); -static int setup_vq_resources(struct mlx5_vdpa_net *ndev); +static int setup_vq_resources(struct mlx5_vdpa_net *ndev, bool filled); static void teardown_vq_resources(struct mlx5_vdpa_net *ndev); static bool mlx5_vdpa_debug; @@ -874,13 +874,16 @@ static bool msix_mode_supported(struct mlx5_vdpa_dev *mvdev) pci_msix_can_alloc_dyn(mvdev->mdev->pdev); } -static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) +static int create_virtqueue(struct mlx5_vdpa_net *ndev, + struct mlx5_vdpa_virtqueue *mvq, + bool filled) { int inlen = MLX5_ST_SZ_BYTES(create_virtio_net_q_in); u32 out[MLX5_ST_SZ_DW(create_virtio_net_q_out)] = {}; struct mlx5_vdpa_dev *mvdev = &ndev->mvdev; struct mlx5_vdpa_mr *vq_mr; struct mlx5_vdpa_mr *vq_desc_mr; + u64 features = filled ? mvdev->actual_features : mvdev->mlx_features; void *obj_context; u16 mlx_features; void *cmd_hdr; @@ -898,7 +901,7 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque goto err_alloc; } - mlx_features = get_features(ndev->mvdev.actual_features); + mlx_features = get_features(features); cmd_hdr = MLX5_ADDR_OF(create_virtio_net_q_in, in, general_obj_in_cmd_hdr); MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); @@ -906,8 +909,6 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid); obj_context = MLX5_ADDR_OF(create_virtio_net_q_in, in, obj_context); - MLX5_SET(virtio_net_q_object, obj_context, hw_available_index, mvq->avail_idx); - MLX5_SET(virtio_net_q_object, obj_context, hw_used_index, mvq->used_idx); MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_12_3, mlx_features >> 3); MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_2_0, @@ -929,17 +930,36 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque MLX5_SET(virtio_q, vq_ctx, queue_index, mvq->index); MLX5_SET(virtio_q, vq_ctx, queue_size, mvq->num_ent); MLX5_SET(virtio_q, vq_ctx, virtio_version_1_0, - !!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_F_VERSION_1))); - MLX5_SET64(virtio_q, vq_ctx, desc_addr, mvq->desc_addr); - MLX5_SET64(virtio_q, vq_ctx, used_addr, mvq->device_addr); - MLX5_SET64(virtio_q, vq_ctx, available_addr, mvq->driver_addr); - vq_mr = mvdev->mr[mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP]]; - if (vq_mr) - MLX5_SET(virtio_q, vq_ctx, virtio_q_mkey, vq_mr->mkey); - - vq_desc_mr = mvdev->mr[mvdev->group2asid[MLX5_VDPA_DATAVQ_DESC_GROUP]]; - if (vq_desc_mr && MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, desc_group_mkey_supported)) - MLX5_SET(virtio_q, vq_ctx, desc_group_mkey, vq_desc_mr->mkey); + !!(features & BIT_ULL(VIRTIO_F_VERSION_1))); + + if (filled) { + MLX5_SET(virtio_net_q_object, obj_context, hw_available_index, mvq->avail_idx); + MLX5_SET(virtio_net_q_object, obj_context, hw_used_index, mvq->used_idx); + + MLX5_SET64(virtio_q, vq_ctx, desc_addr, mvq->desc_addr); + MLX5_SET64(virtio_q, vq_ctx, used_addr, mvq->device_addr); + MLX5_SET64(virtio_q, vq_ctx, available_addr, mvq->driver_addr); + + vq_mr = mvdev->mr[mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP]]; + if (vq_mr) + MLX5_SET(virtio_q, vq_ctx, virtio_q_mkey, vq_mr->mkey); + + vq_desc_mr = mvdev->mr[mvdev->group2asid[MLX5_VDPA_DATAVQ_DESC_GROUP]]; + if (vq_desc_mr && + MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, desc_group_mkey_supported)) + MLX5_SET(virtio_q, vq_ctx, desc_group_mkey, vq_desc_mr->mkey); + } else { + /* If there is no mr update, make sure that the existing ones are set + * modify to ready. + */ + vq_mr = mvdev->mr[mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP]]; + if (vq_mr) + mvq->modified_fields |= MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY; + + vq_desc_mr = mvdev->mr[mvdev->group2asid[MLX5_VDPA_DATAVQ_DESC_GROUP]]; + if (vq_desc_mr) + mvq->modified_fields |= MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY; + } MLX5_SET(virtio_q, vq_ctx, umem_1_id, mvq->umem1.id); MLX5_SET(virtio_q, vq_ctx, umem_1_size, mvq->umem1.size); @@ -959,12 +979,15 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque kfree(in); mvq->virtq_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); - mlx5_vdpa_get_mr(mvdev, vq_mr); - mvq->vq_mr = vq_mr; + if (filled) { + mlx5_vdpa_get_mr(mvdev, vq_mr); + mvq->vq_mr = vq_mr; - if (vq_desc_mr && MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, desc_group_mkey_supported)) { - mlx5_vdpa_get_mr(mvdev, vq_desc_mr); - mvq->desc_mr = vq_desc_mr; + if (vq_desc_mr && + MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, desc_group_mkey_supported)) { + mlx5_vdpa_get_mr(mvdev, vq_desc_mr); + mvq->desc_mr = vq_desc_mr; + } } return 0; @@ -1442,7 +1465,9 @@ static void dealloc_vector(struct mlx5_vdpa_net *ndev, } } -static int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) +static int setup_vq(struct mlx5_vdpa_net *ndev, + struct mlx5_vdpa_virtqueue *mvq, + bool filled) { u16 idx = mvq->index; int err; @@ -1471,7 +1496,7 @@ static int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) goto err_connect; alloc_vector(ndev, mvq); - err = create_virtqueue(ndev, mvq); + err = create_virtqueue(ndev, mvq, filled); if (err) goto err_vq; @@ -2062,7 +2087,7 @@ static int change_num_qps(struct mlx5_vdpa_dev *mvdev, int newqps) } else { ndev->cur_num_vqs = 2 * newqps; for (i = cur_qps * 2; i < 2 * newqps; i++) { - err = setup_vq(ndev, &ndev->vqs[i]); + err = setup_vq(ndev, &ndev->vqs[i], true); if (err) goto clean_added; } @@ -2558,14 +2583,14 @@ static int verify_driver_features(struct mlx5_vdpa_dev *mvdev, u64 features) return 0; } -static int setup_virtqueues(struct mlx5_vdpa_dev *mvdev) +static int setup_virtqueues(struct mlx5_vdpa_dev *mvdev, bool filled) { struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); int err; int i; for (i = 0; i < mvdev->max_vqs; i++) { - err = setup_vq(ndev, &ndev->vqs[i]); + err = setup_vq(ndev, &ndev->vqs[i], filled); if (err) goto err_vq; } @@ -2877,7 +2902,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, if (teardown) { restore_channels_info(ndev); - err = setup_vq_resources(ndev); + err = setup_vq_resources(ndev, true); if (err) return err; } @@ -2888,7 +2913,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, } /* reslock must be held for this function */ -static int setup_vq_resources(struct mlx5_vdpa_net *ndev) +static int setup_vq_resources(struct mlx5_vdpa_net *ndev, bool filled) { struct mlx5_vdpa_dev *mvdev = &ndev->mvdev; int err; @@ -2906,7 +2931,7 @@ static int setup_vq_resources(struct mlx5_vdpa_net *ndev) if (err) goto err_setup; - err = setup_virtqueues(mvdev); + err = setup_virtqueues(mvdev, filled); if (err) { mlx5_vdpa_warn(mvdev, "setup_virtqueues\n"); goto err_setup; @@ -3000,7 +3025,7 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) goto err_setup; } register_link_notifier(ndev); - err = setup_vq_resources(ndev); + err = setup_vq_resources(ndev, true); if (err) { mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); goto err_driver; -- cgit v1.2.3 From fc9af25d04d635ea4590681d044284f97766da48 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:52 +0300 Subject: vdpa/mlx5: Accept Init -> Ready VQ transition in resume_vq() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now resume_vq() was used only for the suspend/resume scenario. This change also allows calling resume_vq() to bring it from Init to Ready state (VQ initialization). Signed-off-by: Dragos Tatulea Reviewed-by: Cosmin Ratiu Message-Id: <20240626-stage-vdpa-vq-precreate-v2-16-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin Acked-by: Eugenio PĂ©rez Acked-by: Eugenio PĂ©rez --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 0a62ce0b4af8..adcc4d63cf83 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1557,11 +1557,31 @@ static void suspend_vqs(struct mlx5_vdpa_net *ndev) static void resume_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) { - if (!mvq->initialized || !is_resumable(ndev)) + if (!mvq->initialized) return; - if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND) + switch (mvq->fw_state) { + case MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT: + /* Due to a FW quirk we need to modify the VQ fields first then change state. + * This should be fixed soon. After that, a single command can be used. + */ + if (modify_virtqueue(ndev, mvq, 0)) + mlx5_vdpa_warn(&ndev->mvdev, + "modify vq properties failed for vq %u\n", mvq->index); + break; + case MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND: + if (!is_resumable(ndev)) { + mlx5_vdpa_warn(&ndev->mvdev, "vq %d is not resumable\n", mvq->index); + return; + } + break; + case MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY: return; + default: + mlx5_vdpa_warn(&ndev->mvdev, "resume vq %u called from bad state %d\n", + mvq->index, mvq->fw_state); + return; + } if (modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY)) mlx5_vdpa_warn(&ndev->mvdev, "modify to resume failed for vq %u\n", mvq->index); -- cgit v1.2.3 From b89bb349f276d7d6688527312eef03d12493b9d4 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:53 +0300 Subject: vdpa/mlx5: Add error code for suspend/resume VQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of blindly calling suspend/resume_vqs(), make then return error codes. To keep compatibility, keep suspending or resuming VQs on error and return the last error code. The assumption here is that the error code would be the same. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-17-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 77 +++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index adcc4d63cf83..8ab5cf1bbc43 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1526,71 +1526,102 @@ err_fwqp: return err; } -static void suspend_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) +static int suspend_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) { struct mlx5_virtq_attr attr; + int err; if (!mvq->initialized) - return; + return 0; if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) - return; + return 0; - if (modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND)) - mlx5_vdpa_warn(&ndev->mvdev, "modify to suspend failed\n"); + err = modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND); + if (err) { + mlx5_vdpa_warn(&ndev->mvdev, "modify to suspend failed, err: %d\n", err); + return err; + } - if (query_virtqueue(ndev, mvq, &attr)) { - mlx5_vdpa_warn(&ndev->mvdev, "failed to query virtqueue\n"); - return; + err = query_virtqueue(ndev, mvq, &attr); + if (err) { + mlx5_vdpa_warn(&ndev->mvdev, "failed to query virtqueue, err: %d\n", err); + return err; } + mvq->avail_idx = attr.available_index; mvq->used_idx = attr.used_index; + + return 0; } -static void suspend_vqs(struct mlx5_vdpa_net *ndev) +static int suspend_vqs(struct mlx5_vdpa_net *ndev) { + int err = 0; int i; - for (i = 0; i < ndev->cur_num_vqs; i++) - suspend_vq(ndev, &ndev->vqs[i]); + for (i = 0; i < ndev->cur_num_vqs; i++) { + int local_err = suspend_vq(ndev, &ndev->vqs[i]); + + err = local_err ? local_err : err; + } + + return err; } -static void resume_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) +static int resume_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) { + int err; + if (!mvq->initialized) - return; + return 0; switch (mvq->fw_state) { case MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT: /* Due to a FW quirk we need to modify the VQ fields first then change state. * This should be fixed soon. After that, a single command can be used. */ - if (modify_virtqueue(ndev, mvq, 0)) + err = modify_virtqueue(ndev, mvq, 0); + if (err) { mlx5_vdpa_warn(&ndev->mvdev, - "modify vq properties failed for vq %u\n", mvq->index); + "modify vq properties failed for vq %u, err: %d\n", + mvq->index, err); + return err; + } break; case MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND: if (!is_resumable(ndev)) { mlx5_vdpa_warn(&ndev->mvdev, "vq %d is not resumable\n", mvq->index); - return; + return -EINVAL; } break; case MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY: - return; + return 0; default: mlx5_vdpa_warn(&ndev->mvdev, "resume vq %u called from bad state %d\n", mvq->index, mvq->fw_state); - return; + return -EINVAL; } - if (modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY)) - mlx5_vdpa_warn(&ndev->mvdev, "modify to resume failed for vq %u\n", mvq->index); + err = modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY); + if (err) + mlx5_vdpa_warn(&ndev->mvdev, "modify to resume failed for vq %u, err: %d\n", + mvq->index, err); + + return err; } -static void resume_vqs(struct mlx5_vdpa_net *ndev) +static int resume_vqs(struct mlx5_vdpa_net *ndev) { - for (int i = 0; i < ndev->cur_num_vqs; i++) - resume_vq(ndev, &ndev->vqs[i]); + int err = 0; + + for (int i = 0; i < ndev->cur_num_vqs; i++) { + int local_err = resume_vq(ndev, &ndev->vqs[i]); + + err = local_err ? local_err : err; + } + + return err; } static void teardown_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq) -- cgit v1.2.3 From 843250271bdb16f3b38ed1d6f727a9e9e8632893 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:54 +0300 Subject: vdpa/mlx5: Consolidate all VQ modify to Ready to use resume_vq() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are a few more places modifying the VQ to Ready directly. Let's consolidate them into resume_vq(). The redundant warnings for resume_vq() errors can also be dropped. There is one special case that needs to be handled for virtio-vdpa: the initialized flag must be set to true earlier in setup_vq() so that resume_vq() doesn't return early. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-18-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 8ab5cf1bbc43..e65d488f7a08 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -160,6 +160,7 @@ static void free_fixed_resources(struct mlx5_vdpa_net *ndev); static void mvqs_set_defaults(struct mlx5_vdpa_net *ndev); static int setup_vq_resources(struct mlx5_vdpa_net *ndev, bool filled); static void teardown_vq_resources(struct mlx5_vdpa_net *ndev); +static int resume_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq); static bool mlx5_vdpa_debug; @@ -1500,16 +1501,14 @@ static int setup_vq(struct mlx5_vdpa_net *ndev, if (err) goto err_vq; + mvq->initialized = true; + if (mvq->ready) { - err = modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY); - if (err) { - mlx5_vdpa_warn(&ndev->mvdev, "failed to modify to ready vq idx %d(%d)\n", - idx, err); + err = resume_vq(ndev, mvq); + if (err) goto err_modify; - } } - mvq->initialized = true; return 0; err_modify: @@ -2422,7 +2421,6 @@ static void mlx5_vdpa_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); struct mlx5_vdpa_virtqueue *mvq; - int err; if (!mvdev->actual_features) return; @@ -2439,14 +2437,10 @@ static void mlx5_vdpa_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready if (!ready) { suspend_vq(ndev, mvq); } else { - err = modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY); - if (err) { - mlx5_vdpa_warn(mvdev, "modify VQ %d to ready failed (%d)\n", idx, err); + if (resume_vq(ndev, mvq)) ready = false; - } } - mvq->ready = ready; } -- cgit v1.2.3 From ac85cd904dc9a5e83643ec9da0c43b0a95193158 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:55 +0300 Subject: vdpa/mlx5: Forward error in suspend/resume device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Start using the suspend/resume_vq() error return codes previously added. Reviewed-by: Cosmin Ratiu Reviewed-by: Zhu Yanjun Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-19-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin Reviewed-by: Eugenio PĂ©rez Reviewed-by: Eugenio PĂ©rez --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index e65d488f7a08..ce1f6a1f36cd 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -3436,22 +3436,25 @@ static int mlx5_vdpa_suspend(struct vdpa_device *vdev) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); + int err; mlx5_vdpa_info(mvdev, "suspending device\n"); down_write(&ndev->reslock); unregister_link_notifier(ndev); - suspend_vqs(ndev); + err = suspend_vqs(ndev); mlx5_vdpa_cvq_suspend(mvdev); mvdev->suspended = true; up_write(&ndev->reslock); - return 0; + + return err; } static int mlx5_vdpa_resume(struct vdpa_device *vdev) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); struct mlx5_vdpa_net *ndev; + int err; ndev = to_mlx5_vdpa_ndev(mvdev); @@ -3459,10 +3462,11 @@ static int mlx5_vdpa_resume(struct vdpa_device *vdev) down_write(&ndev->reslock); mvdev->suspended = false; - resume_vqs(ndev); + err = resume_vqs(ndev); register_link_notifier(ndev); up_write(&ndev->reslock); - return 0; + + return err; } static int mlx5_set_group_asid(struct vdpa_device *vdev, u32 group, -- cgit v1.2.3 From 3b3adb3bbfce275400b21f7a0d54db0ba0a46cc9 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:56 +0300 Subject: vdpa/mlx5: Use suspend/resume during VQP change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resume a VQ if it is already created when the number of VQ pairs increases. This is done in preparation for VQ pre-creation which is coming in a later patch. It is necessary because calling setup_vq() on an already created VQ will return early and will not enable the queue. For symmetry, suspend a VQ instead of tearing it down when the number of VQ pairs decreases. But only if the resume operation is supported. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-20-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index ce1f6a1f36cd..324604b16b91 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2130,14 +2130,22 @@ static int change_num_qps(struct mlx5_vdpa_dev *mvdev, int newqps) if (err) return err; - for (i = ndev->cur_num_vqs - 1; i >= 2 * newqps; i--) - teardown_vq(ndev, &ndev->vqs[i]); + for (i = ndev->cur_num_vqs - 1; i >= 2 * newqps; i--) { + struct mlx5_vdpa_virtqueue *mvq = &ndev->vqs[i]; + + if (is_resumable(ndev)) + suspend_vq(ndev, mvq); + else + teardown_vq(ndev, mvq); + } ndev->cur_num_vqs = 2 * newqps; } else { ndev->cur_num_vqs = 2 * newqps; for (i = cur_qps * 2; i < 2 * newqps; i++) { - err = setup_vq(ndev, &ndev->vqs[i], true); + struct mlx5_vdpa_virtqueue *mvq = &ndev->vqs[i]; + + err = mvq->initialized ? resume_vq(ndev, mvq) : setup_vq(ndev, mvq, true); if (err) goto clean_added; } -- cgit v1.2.3 From ffb1aae43ed5078598318042bac1ae1057e57e2d Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:57 +0300 Subject: vdpa/mlx5: Pre-create hardware VQs at vdpa .dev_add time Currently, hardware VQs are created right when the vdpa device gets into DRIVER_OK state. That is easier because most of the VQ state is known by then. This patch switches to creating all VQs and their associated resources at device creation time. The motivation is to reduce the vdpa device live migration downtime by moving the expensive operation of creating all the hardware VQs and their associated resources out of downtime on the destination VM. The VQs are now created in a blank state. The VQ configuration will happen later, on DRIVER_OK. Then the configuration will be applied when the VQs are moved to the Ready state. When .set_vq_ready() is called on a VQ before DRIVER_OK, special care is needed: now that the VQ is already created a resume_vq() will be triggered too early when no mr has been configured yet. Skip calling resume_vq() in this case, let it be handled during DRIVER_OK. For virtio-vdpa, the device configuration is done earlier during .vdpa_dev_add() by vdpa_register_device(). Avoid calling setup_vq_resources() a second time in that case. On a 64 CPU, 256 GB VM with 1 vDPA device of 16 VQps, the full VQ resource creation + resume time was ~370ms. Now it's down to 60 ms (only VQ config and resume). The measurements were done on a ConnectX6DX based vDPA device. Signed-off-by: Dragos Tatulea Reviewed-by: Cosmin Ratiu Message-Id: <20240626-stage-vdpa-vq-precreate-v2-21-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 324604b16b91..8ef703f4c23d 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2444,7 +2444,7 @@ static void mlx5_vdpa_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready mvq = &ndev->vqs[idx]; if (!ready) { suspend_vq(ndev, mvq); - } else { + } else if (mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK) { if (resume_vq(ndev, mvq)) ready = false; } @@ -3078,10 +3078,18 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) goto err_setup; } register_link_notifier(ndev); - err = setup_vq_resources(ndev, true); - if (err) { - mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); - goto err_driver; + if (ndev->setup) { + err = resume_vqs(ndev); + if (err) { + mlx5_vdpa_warn(mvdev, "failed to resume VQs\n"); + goto err_driver; + } + } else { + err = setup_vq_resources(ndev, true); + if (err) { + mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); + goto err_driver; + } } } else { mlx5_vdpa_warn(mvdev, "did not expect DRIVER_OK to be cleared\n"); @@ -3142,6 +3150,7 @@ static int mlx5_vdpa_compat_reset(struct vdpa_device *vdev, u32 flags) if (mlx5_vdpa_create_dma_mr(mvdev)) mlx5_vdpa_warn(mvdev, "create MR failed\n"); } + setup_vq_resources(ndev, false); up_write(&ndev->reslock); return 0; @@ -3835,8 +3844,21 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, goto err_reg; mgtdev->ndev = ndev; + + /* For virtio-vdpa, the device was set up during device register. */ + if (ndev->setup) + return 0; + + down_write(&ndev->reslock); + err = setup_vq_resources(ndev, false); + up_write(&ndev->reslock); + if (err) + goto err_setup_vq_res; + return 0; +err_setup_vq_res: + _vdpa_unregister_device(&mvdev->vdev); err_reg: destroy_workqueue(mvdev->wq); err_res2: @@ -3862,6 +3884,11 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device * unregister_link_notifier(ndev); _vdpa_unregister_device(dev); + + down_write(&ndev->reslock); + teardown_vq_resources(ndev); + up_write(&ndev->reslock); + wq = mvdev->wq; mvdev->wq = NULL; destroy_workqueue(wq); -- cgit v1.2.3 From 0fe963d6fc162cd8c9b6c82205ea62e69088c063 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:58 +0300 Subject: vdpa/mlx5: Re-create HW VQs under certain conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are a few conditions under which the hardware VQs need a full teardown and setup: - VQ size changed to something else than default value. Hardware VQ size modification is not supported. - User turns off certain device features: mergeable buffers, checksum virtio 1.0 compliance. In these cases, the TIR and RQT need to be re-created. Add a needs_teardown configuration variable and set it when detecting the above scenarios. On next DRIVER_OK, the resources will be torn down first. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-22-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 15 +++++++++++++++ drivers/vdpa/mlx5/net/mlx5_vnet.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 8ef703f4c23d..ea4bfd9afce9 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2390,6 +2390,7 @@ static void mlx5_vdpa_set_vq_num(struct vdpa_device *vdev, u16 idx, u32 num) } mvq = &ndev->vqs[idx]; + ndev->needs_teardown = num != mvq->num_ent; mvq->num_ent = num; } @@ -2800,6 +2801,7 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); u64 old_features = mvdev->actual_features; + u64 diff_features; int err; print_features(mvdev, features, true); @@ -2822,6 +2824,14 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) } } + /* When below features diverge from initial device features, VQs need a full teardown. */ +#define NEEDS_TEARDOWN_MASK (BIT_ULL(VIRTIO_NET_F_MRG_RXBUF) | \ + BIT_ULL(VIRTIO_NET_F_CSUM) | \ + BIT_ULL(VIRTIO_F_VERSION_1)) + + diff_features = mvdev->mlx_features ^ mvdev->actual_features; + ndev->needs_teardown = !!(diff_features & NEEDS_TEARDOWN_MASK); + update_cvq_info(mvdev); return err; } @@ -3038,6 +3048,7 @@ static void teardown_vq_resources(struct mlx5_vdpa_net *ndev) destroy_rqt(ndev); teardown_virtqueues(ndev); ndev->setup = false; + ndev->needs_teardown = false; } static int setup_cvq_vring(struct mlx5_vdpa_dev *mvdev) @@ -3078,6 +3089,10 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) goto err_setup; } register_link_notifier(ndev); + + if (ndev->needs_teardown) + teardown_vq_resources(ndev); + if (ndev->setup) { err = resume_vqs(ndev); if (err) { diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.h b/drivers/vdpa/mlx5/net/mlx5_vnet.h index 90b556a57971..00e79a7d0be8 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.h +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.h @@ -56,6 +56,7 @@ struct mlx5_vdpa_net { struct dentry *rx_dent; struct dentry *rx_table_dent; bool setup; + bool needs_teardown; u32 cur_num_vqs; u32 rqt_size; bool nb_registered; -- cgit v1.2.3 From 2638134f710364c9e696a155bf16c6847959b1d9 Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:26:59 +0300 Subject: vdpa/mlx5: Don't reset VQs more than necessary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vdpa device can be reset many times in sequence without any significant state changes in between. Previously this was not a problem: VQs were torn down only on first reset. But after VQ pre-creation was introduced, each reset will delete and re-create the hardware VQs and their associated resources. To solve this problem, avoid resetting hardware VQs if the VQs are still in a blank state. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-23-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index ea4bfd9afce9..573dc01df8c3 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -3134,18 +3134,41 @@ static void init_group_to_asid_map(struct mlx5_vdpa_dev *mvdev) mvdev->group2asid[i] = 0; } +static bool needs_vqs_reset(const struct mlx5_vdpa_dev *mvdev) +{ + struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); + struct mlx5_vdpa_virtqueue *mvq = &ndev->vqs[0]; + + if (mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK) + return true; + + if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT) + return true; + + return mvq->modified_fields & ( + MLX5_VIRTQ_MODIFY_MASK_STATE | + MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_ADDRS | + MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_AVAIL_IDX | + MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_USED_IDX + ); +} + static int mlx5_vdpa_compat_reset(struct vdpa_device *vdev, u32 flags) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); + bool vq_reset; print_status(mvdev, 0, true); mlx5_vdpa_info(mvdev, "performing device reset\n"); down_write(&ndev->reslock); unregister_link_notifier(ndev); - teardown_vq_resources(ndev); - mvqs_set_defaults(ndev); + vq_reset = needs_vqs_reset(mvdev); + if (vq_reset) { + teardown_vq_resources(ndev); + mvqs_set_defaults(ndev); + } if (flags & VDPA_RESET_F_CLEAN_MAP) mlx5_vdpa_destroy_mr_resources(&ndev->mvdev); @@ -3165,7 +3188,8 @@ static int mlx5_vdpa_compat_reset(struct vdpa_device *vdev, u32 flags) if (mlx5_vdpa_create_dma_mr(mvdev)) mlx5_vdpa_warn(mvdev, "create MR failed\n"); } - setup_vq_resources(ndev, false); + if (vq_reset) + setup_vq_resources(ndev, false); up_write(&ndev->reslock); return 0; -- cgit v1.2.3 From 8e0751af1b1162342904dcb0410e8a8ef9cbf70b Mon Sep 17 00:00:00 2001 From: Dragos Tatulea Date: Wed, 26 Jun 2024 13:27:00 +0300 Subject: vdpa/mlx5: Don't enable non-active VQs in .set_vq_ready() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VQ indices in the range [cur_num_qps, max_vqs) represent queues that have not yet been activated. .set_vq_ready should not activate these VQs. Reviewed-by: Cosmin Ratiu Acked-by: Eugenio PĂ©rez Signed-off-by: Dragos Tatulea Message-Id: <20240626-stage-vdpa-vq-precreate-v2-24-560c491078df@nvidia.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 573dc01df8c3..fa78e8288ebb 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1575,6 +1575,9 @@ static int resume_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq if (!mvq->initialized) return 0; + if (mvq->index >= ndev->cur_num_vqs) + return 0; + switch (mvq->fw_state) { case MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT: /* Due to a FW quirk we need to modify the VQ fields first then change state. -- cgit v1.2.3 From 87bb477c39b172071a1cb44aef41e701d5fee90d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:47:56 +0200 Subject: caif_virtio: use virtio_find_single_vq() for single virtqueue finding Since caif uses only one queue, convert to virtio_find_single_vq() helper which is made for this purpose. Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-2-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- drivers/net/caif/caif_virtio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c index 99d984851fef..7fea00c7ca8a 100644 --- a/drivers/net/caif/caif_virtio.c +++ b/drivers/net/caif/caif_virtio.c @@ -646,9 +646,7 @@ static inline void debugfs_init(struct cfv_info *cfv) /* Setup CAIF for the a virtio device */ static int cfv_probe(struct virtio_device *vdev) { - vq_callback_t *vq_cbs = cfv_release_cb; vrh_callback_t *vrh_cbs = cfv_recv; - const char *names = "output"; const char *cfv_netdev_name = "cfvrt"; struct net_device *netdev; struct cfv_info *cfv; @@ -675,9 +673,11 @@ static int cfv_probe(struct virtio_device *vdev) goto err; /* Get the TX virtio ring. This is a "guest side vring". */ - err = virtio_find_vqs(vdev, 1, &cfv->vq_tx, &vq_cbs, &names, NULL); - if (err) + cfv->vq_tx = virtio_find_single_vq(vdev, cfv_release_cb, "output"); + if (IS_ERR(cfv->vq_tx)) { + err = PTR_ERR(cfv->vq_tx); goto err; + } /* Get the CAIF configuration from virtio config space, if available */ if (vdev->config->get) { -- cgit v1.2.3 From de1177e56005dccd9729d4ca331de64f5d463b90 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:47:57 +0200 Subject: virtio: make virtio_find_vqs() call virtio_find_vqs_ctx() In order to prepare for conversion of virtio_find_vqs*() arguments, make virtio_find_vqs() to call virtio_find_vqs_ctx() instead of op directly. Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-3-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- include/linux/virtio_config.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index da9b271b54db..d19eaf6bafbf 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -225,22 +225,23 @@ struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, } static inline -int virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, +int virtio_find_vqs_ctx(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char * const names[], + const char * const names[], const bool *ctx, struct irq_affinity *desc) { - return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, NULL, desc); + return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, ctx, + desc); } static inline -int virtio_find_vqs_ctx(struct virtio_device *vdev, unsigned nvqs, +int virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char * const names[], const bool *ctx, + const char * const names[], struct irq_affinity *desc) { - return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, ctx, - desc); + return virtio_find_vqs_ctx(vdev, nvqs, vqs, callbacks, + names, NULL, desc); } /** -- cgit v1.2.3 From 959538c11a88298672195a0eb3289c0f2f88b02d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:47:58 +0200 Subject: virtio: make virtio_find_single_vq() call virtio_find_vqs() In order to prepare for conversion of virtio_find_vqs*() arguments, make virtio_find_single_vq() to call virtio_find_vqs() instead of op directly. Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-4-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- include/linux/virtio_config.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index d19eaf6bafbf..82a1d798b2f1 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -210,20 +210,6 @@ static inline bool virtio_has_dma_quirk(const struct virtio_device *vdev) return !virtio_has_feature(vdev, VIRTIO_F_ACCESS_PLATFORM); } -static inline -struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, - vq_callback_t *c, const char *n) -{ - vq_callback_t *callbacks[] = { c }; - const char *names[] = { n }; - struct virtqueue *vq; - int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names, NULL, - NULL); - if (err < 0) - return ERR_PTR(err); - return vq; -} - static inline int virtio_find_vqs_ctx(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], @@ -244,6 +230,20 @@ int virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, names, NULL, desc); } +static inline +struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, + vq_callback_t *c, const char *n) +{ + vq_callback_t *callbacks[] = { c }; + const char *names[] = { n }; + struct virtqueue *vq; + int err = virtio_find_vqs(vdev, 1, &vq, callbacks, names, NULL); + + if (err < 0) + return ERR_PTR(err); + return vq; +} + /** * virtio_synchronize_cbs - synchronize with virtqueue callbacks * @dev: the virtio device -- cgit v1.2.3 From c502eb85c34e29bb185e3d15dd9b8fce8a74f303 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:47:59 +0200 Subject: virtio: introduce virtio_queue_info struct and find_vqs_info() config op Introduce a structure virtio_queue_info to carry name, callback and ctx together. In order to allow config implementations to accept config op with array of virtio_queue_info structures, introduce a new find_vqs_info() op. Do the needed conversion in virtio_find_vqs_ctx(). Note that whole virtio_find_vqs_ctx() is going to be eventually removed at the and of this patchset. Suggested-by: Xuan Zhuo Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-5-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- include/linux/virtio_config.h | 55 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 82a1d798b2f1..fb7a1fd00ee5 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -18,6 +18,20 @@ struct virtio_shm_region { typedef void vq_callback_t(struct virtqueue *); +/** + * struct virtqueue_info - Info for a virtqueue passed to find_vqs(). + * @name: virtqueue description. Used mainly for debugging, NULL for + * a virtqueue unused by the driver. + * @callback: A callback to invoke on a used buffer notification. + * NULL for a virtqueue that does not need a callback. + * @ctx: A flag to indicate to maintain an extra context per virtqueue. + */ +struct virtqueue_info { + const char *name; + vq_callback_t *callback; + bool ctx; +}; + /** * struct virtio_config_ops - operations for configuring a virtio device * Note: Do not assume that a transport implements all of the operations @@ -58,6 +72,12 @@ typedef void vq_callback_t(struct virtqueue *); * names: array of virtqueue names (mainly for debugging) * include a NULL entry for vqs unused by driver * Returns 0 on success or error status + * @find_vqs_info: find virtqueues and instantiate them. + * vdev: the virtio_device + * nvqs: the number of virtqueues to find + * vqs: on success, includes new virtqueues + * vqs_info: array of virtqueue info structures + * Returns 0 on success or error status * @del_vqs: free virtqueues found by find_vqs(). * @synchronize_cbs: synchronize with the virtqueue callbacks (optional) * The function guarantees that all memory operations on the @@ -109,6 +129,10 @@ struct virtio_config_ops { struct virtqueue *vqs[], vq_callback_t *callbacks[], const char * const names[], const bool *ctx, struct irq_affinity *desc); + int (*find_vqs_info)(struct virtio_device *vdev, unsigned int nvqs, + struct virtqueue *vqs[], + struct virtqueue_info vqs_info[], + struct irq_affinity *desc); void (*del_vqs)(struct virtio_device *); void (*synchronize_cbs)(struct virtio_device *); u64 (*get_features)(struct virtio_device *vdev); @@ -117,7 +141,7 @@ struct virtio_config_ops { int (*set_vq_affinity)(struct virtqueue *vq, const struct cpumask *cpu_mask); const struct cpumask *(*get_vq_affinity)(struct virtio_device *vdev, - int index); + int index); bool (*get_shm_region)(struct virtio_device *vdev, struct virtio_shm_region *region, u8 id); int (*disable_vq_and_reset)(struct virtqueue *vq); @@ -210,14 +234,39 @@ static inline bool virtio_has_dma_quirk(const struct virtio_device *vdev) return !virtio_has_feature(vdev, VIRTIO_F_ACCESS_PLATFORM); } +static inline +int virtio_find_vqs_info(struct virtio_device *vdev, unsigned int nvqs, + struct virtqueue *vqs[], + struct virtqueue_info vqs_info[], + struct irq_affinity *desc) +{ + return vdev->config->find_vqs_info(vdev, nvqs, vqs, vqs_info, desc); +} + static inline int virtio_find_vqs_ctx(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], const char * const names[], const bool *ctx, struct irq_affinity *desc) { - return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, ctx, - desc); + struct virtqueue_info *vqs_info; + int err, i; + + if (!vdev->config->find_vqs_info) + return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, + names, ctx, desc); + + vqs_info = kmalloc_array(nvqs, sizeof(*vqs_info), GFP_KERNEL); + if (!vqs_info) + return -ENOMEM; + for (i = 0; i < nvqs; i++) { + vqs_info[i].name = names[i]; + vqs_info[i].callback = callbacks[i]; + vqs_info[i].ctx = ctx ? ctx[i] : false; + } + err = virtio_find_vqs_info(vdev, nvqs, vqs, vqs_info, desc); + kfree(vqs_info); + return err; } static inline -- cgit v1.2.3 From ad9a12576bccd4cf1bbef7f8574421804cdff403 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:00 +0200 Subject: virtio_pci: convert vp_*find_vqs() ops to find_vqs_info() Convert existing vp_find_vqs() and vp_modern_find_vqs() implementations to find_vqs_info() config op. Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-6-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_pci_common.c | 48 +++++++++++++++++++++----------------- drivers/virtio/virtio_pci_common.h | 3 +-- drivers/virtio/virtio_pci_legacy.c | 2 +- drivers/virtio/virtio_pci_modern.c | 9 ++++--- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index f6b0b00e4599..7d82facafd75 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -285,12 +285,13 @@ void vp_del_vqs(struct virtio_device *vdev) } static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs, - struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char * const names[], bool per_vq_vectors, - const bool *ctx, - struct irq_affinity *desc) + struct virtqueue *vqs[], + struct virtqueue_info vqs_info[], + bool per_vq_vectors, + struct irq_affinity *desc) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); + struct virtqueue_info *vqi; u16 msix_vec; int i, err, nvectors, allocated_vectors, queue_idx = 0; @@ -301,9 +302,11 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs, if (per_vq_vectors) { /* Best option: one for change interrupt, one per vq. */ nvectors = 1; - for (i = 0; i < nvqs; ++i) - if (names[i] && callbacks[i]) + for (i = 0; i < nvqs; ++i) { + vqi = &vqs_info[i]; + if (vqi->name && vqi->callback) ++nvectors; + } } else { /* Second best: one for change, shared for all vqs. */ nvectors = 2; @@ -317,20 +320,20 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs, vp_dev->per_vq_vectors = per_vq_vectors; allocated_vectors = vp_dev->msix_used_vectors; for (i = 0; i < nvqs; ++i) { - if (!names[i]) { + vqi = &vqs_info[i]; + if (!vqi->name) { vqs[i] = NULL; continue; } - if (!callbacks[i]) + if (!vqi->callback) msix_vec = VIRTIO_MSI_NO_VECTOR; else if (vp_dev->per_vq_vectors) msix_vec = allocated_vectors++; else msix_vec = VP_MSIX_VQ_VECTOR; - vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i], - ctx ? ctx[i] : false, - msix_vec); + vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback, + vqi->name, vqi->ctx, msix_vec); if (IS_ERR(vqs[i])) { err = PTR_ERR(vqs[i]); goto error_find; @@ -343,7 +346,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs, snprintf(vp_dev->msix_names[msix_vec], sizeof *vp_dev->msix_names, "%s-%s", - dev_name(&vp_dev->vdev.dev), names[i]); + dev_name(&vp_dev->vdev.dev), vqi->name); err = request_irq(pci_irq_vector(vp_dev->pci_dev, msix_vec), vring_interrupt, 0, vp_dev->msix_names[msix_vec], @@ -361,8 +364,8 @@ error_find: } static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs, - struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char * const names[], const bool *ctx) + struct virtqueue *vqs[], + struct virtqueue_info vqs_info[]) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); int i, err, queue_idx = 0; @@ -379,12 +382,14 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs, vp_dev->intx_enabled = 1; vp_dev->per_vq_vectors = false; for (i = 0; i < nvqs; ++i) { - if (!names[i]) { + struct virtqueue_info *vqi = &vqs_info[i]; + + if (!vqi->name) { vqs[i] = NULL; continue; } - vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i], - ctx ? ctx[i] : false, + vqs[i] = vp_setup_vq(vdev, queue_idx++, vqi->callback, + vqi->name, vqi->ctx, VIRTIO_MSI_NO_VECTOR); if (IS_ERR(vqs[i])) { err = PTR_ERR(vqs[i]); @@ -400,25 +405,24 @@ out_del_vqs: /* the config->find_vqs() implementation */ int vp_find_vqs(struct virtio_device *vdev, unsigned int nvqs, - struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char * const names[], const bool *ctx, + struct virtqueue *vqs[], struct virtqueue_info vqs_info[], struct irq_affinity *desc) { int err; /* Try MSI-X with one vector per queue. */ - err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, true, ctx, desc); + err = vp_find_vqs_msix(vdev, nvqs, vqs, vqs_info, true, desc); if (!err) return 0; /* Fallback: MSI-X with one vector for config, one shared for queues. */ - err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, ctx, desc); + err = vp_find_vqs_msix(vdev, nvqs, vqs, vqs_info, false, desc); if (!err) return 0; /* Is there an interrupt? If not give up. */ if (!(to_vp_device(vdev)->pci_dev->irq)) return err; /* Finally fall back to regular interrupts. */ - return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names, ctx); + return vp_find_vqs_intx(vdev, nvqs, vqs, vqs_info); } const char *vp_bus_name(struct virtio_device *vdev) diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h index 7fef52bee455..3c4bb2d6163a 100644 --- a/drivers/virtio/virtio_pci_common.h +++ b/drivers/virtio/virtio_pci_common.h @@ -127,8 +127,7 @@ bool vp_notify(struct virtqueue *vq); void vp_del_vqs(struct virtio_device *vdev); /* the config->find_vqs() implementation */ int vp_find_vqs(struct virtio_device *vdev, unsigned int nvqs, - struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char * const names[], const bool *ctx, + struct virtqueue *vqs[], struct virtqueue_info vqs_info[], struct irq_affinity *desc); const char *vp_bus_name(struct virtio_device *vdev); diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c index d9cbb02b35a1..a9786e38d763 100644 --- a/drivers/virtio/virtio_pci_legacy.c +++ b/drivers/virtio/virtio_pci_legacy.c @@ -192,7 +192,7 @@ static const struct virtio_config_ops virtio_pci_config_ops = { .get_status = vp_get_status, .set_status = vp_set_status, .reset = vp_reset, - .find_vqs = vp_find_vqs, + .find_vqs_info = vp_find_vqs, .del_vqs = vp_del_vqs, .synchronize_cbs = vp_synchronize_vectors, .get_features = vp_get_features, diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index f62b530aa3b5..adba4a29fdf4 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -595,13 +595,12 @@ err: static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned int nvqs, struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char * const names[], const bool *ctx, + struct virtqueue_info vqs_info[], struct irq_affinity *desc) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtqueue *vq; - int rc = vp_find_vqs(vdev, nvqs, vqs, callbacks, names, ctx, desc); + int rc = vp_find_vqs(vdev, nvqs, vqs, vqs_info, desc); if (rc) return rc; @@ -782,7 +781,7 @@ static const struct virtio_config_ops virtio_pci_config_nodev_ops = { .get_status = vp_get_status, .set_status = vp_set_status, .reset = vp_reset, - .find_vqs = vp_modern_find_vqs, + .find_vqs_info = vp_modern_find_vqs, .del_vqs = vp_del_vqs, .synchronize_cbs = vp_synchronize_vectors, .get_features = vp_get_features, @@ -804,7 +803,7 @@ static const struct virtio_config_ops virtio_pci_config_ops = { .get_status = vp_get_status, .set_status = vp_set_status, .reset = vp_reset, - .find_vqs = vp_modern_find_vqs, + .find_vqs_info = vp_modern_find_vqs, .del_vqs = vp_del_vqs, .synchronize_cbs = vp_synchronize_vectors, .get_features = vp_get_features, -- cgit v1.2.3 From 3c93b576e038577490e8b906025e38b6fd7241b3 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:01 +0200 Subject: virtio: convert find_vqs() op implementations to find_vqs_info() Convert existing find_vqs() transport implementations to use find_vqs_info() config op. Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-7-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- arch/um/drivers/virtio_uml.c | 14 ++++++++------ drivers/platform/mellanox/mlxbf-tmfifo.c | 12 ++++++------ drivers/remoteproc/remoteproc_virtio.c | 14 +++++++------- drivers/s390/virtio/virtio_ccw.c | 15 +++++++-------- drivers/virtio/virtio_mmio.c | 14 +++++++------- drivers/virtio/virtio_vdpa.c | 15 +++++++-------- 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index 77faa2cf3a13..4cc393e903fc 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -1014,8 +1014,8 @@ error_kzalloc: } static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs, - struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char * const names[], const bool *ctx, + struct virtqueue *vqs[], + struct virtqueue_info vqs_info[], struct irq_affinity *desc) { struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev); @@ -1031,13 +1031,15 @@ static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs, return rc; for (i = 0; i < nvqs; ++i) { - if (!names[i]) { + struct virtqueue_info *vqi = &vqs_info[i]; + + if (!vqi->name) { vqs[i] = NULL; continue; } - vqs[i] = vu_setup_vq(vdev, queue_idx++, callbacks[i], names[i], - ctx ? ctx[i] : false); + vqs[i] = vu_setup_vq(vdev, queue_idx++, vqi->callback, + vqi->name, vqi->ctx); if (IS_ERR(vqs[i])) { rc = PTR_ERR(vqs[i]); goto error_setup; @@ -1097,7 +1099,7 @@ static const struct virtio_config_ops virtio_uml_config_ops = { .get_status = vu_get_status, .set_status = vu_set_status, .reset = vu_reset, - .find_vqs = vu_find_vqs, + .find_vqs_info = vu_find_vqs, .del_vqs = vu_del_vqs, .get_features = vu_get_features, .finalize_features = vu_finalize_features, diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c index b8d1e32e97eb..3dc895cfdc4a 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo.c +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c @@ -1058,9 +1058,7 @@ static void mlxbf_tmfifo_virtio_del_vqs(struct virtio_device *vdev) static int mlxbf_tmfifo_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs, struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char * const names[], - const bool *ctx, + struct virtqueue_info vqs_info[], struct irq_affinity *desc) { struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev); @@ -1072,7 +1070,9 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct virtio_device *vdev, return -EINVAL; for (i = 0; i < nvqs; ++i) { - if (!names[i]) { + struct virtqueue_info *vqi = &vqs_info[i]; + + if (!vqi->name) { ret = -EINVAL; goto error; } @@ -1084,7 +1084,7 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct virtio_device *vdev, vq = vring_new_virtqueue(i, vring->num, vring->align, vdev, false, false, vring->va, mlxbf_tmfifo_virtio_notify, - callbacks[i], names[i]); + vqi->callback, vqi->name); if (!vq) { dev_err(&vdev->dev, "vring_new_virtqueue failed\n"); ret = -ENOMEM; @@ -1175,7 +1175,7 @@ static void tmfifo_virtio_dev_release(struct device *device) static const struct virtio_config_ops mlxbf_tmfifo_virtio_config_ops = { .get_features = mlxbf_tmfifo_virtio_get_features, .finalize_features = mlxbf_tmfifo_virtio_finalize_features, - .find_vqs = mlxbf_tmfifo_virtio_find_vqs, + .find_vqs_info = mlxbf_tmfifo_virtio_find_vqs, .del_vqs = mlxbf_tmfifo_virtio_del_vqs, .reset = mlxbf_tmfifo_virtio_reset, .set_status = mlxbf_tmfifo_virtio_set_status, diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index 25b66b113b69..870764c0ad9f 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -182,21 +182,21 @@ static void rproc_virtio_del_vqs(struct virtio_device *vdev) static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs, struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char * const names[], - const bool * ctx, + struct virtqueue_info vqs_info[], struct irq_affinity *desc) { int i, ret, queue_idx = 0; for (i = 0; i < nvqs; ++i) { - if (!names[i]) { + struct virtqueue_info *vqi = &vqs_info[i]; + + if (!vqi->name) { vqs[i] = NULL; continue; } - vqs[i] = rp_find_vq(vdev, queue_idx++, callbacks[i], names[i], - ctx ? ctx[i] : false); + vqs[i] = rp_find_vq(vdev, queue_idx++, vqi->callback, + vqi->name, vqi->ctx); if (IS_ERR(vqs[i])) { ret = PTR_ERR(vqs[i]); goto error; @@ -327,7 +327,7 @@ static void rproc_virtio_set(struct virtio_device *vdev, unsigned int offset, static const struct virtio_config_ops rproc_virtio_config_ops = { .get_features = rproc_virtio_get_features, .finalize_features = rproc_virtio_finalize_features, - .find_vqs = rproc_virtio_find_vqs, + .find_vqs_info = rproc_virtio_find_vqs, .del_vqs = rproc_virtio_del_vqs, .reset = rproc_virtio_reset, .set_status = rproc_virtio_set_status, diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index d6491fc84e8c..fa884afff777 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -689,9 +689,7 @@ out: static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char * const names[], - const bool *ctx, + struct virtqueue_info vqs_info[], struct irq_affinity *desc) { struct virtio_ccw_device *vcdev = to_vc_device(vdev); @@ -705,14 +703,15 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, return -ENOMEM; for (i = 0; i < nvqs; ++i) { - if (!names[i]) { + struct virtqueue_info *vqi = &vqs_info[i]; + + if (!vqi->name) { vqs[i] = NULL; continue; } - vqs[i] = virtio_ccw_setup_vq(vdev, queue_idx++, callbacks[i], - names[i], ctx ? ctx[i] : false, - ccw); + vqs[i] = virtio_ccw_setup_vq(vdev, queue_idx++, vqi->callback, + vqi->name, vqi->ctx, ccw); if (IS_ERR(vqs[i])) { ret = PTR_ERR(vqs[i]); vqs[i] = NULL; @@ -1079,7 +1078,7 @@ static const struct virtio_config_ops virtio_ccw_config_ops = { .get_status = virtio_ccw_get_status, .set_status = virtio_ccw_set_status, .reset = virtio_ccw_reset, - .find_vqs = virtio_ccw_find_vqs, + .find_vqs_info = virtio_ccw_find_vqs, .del_vqs = virtio_ccw_del_vqs, .bus_name = virtio_ccw_bus_name, .synchronize_cbs = virtio_ccw_synchronize_cbs, diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 173596589c71..57903685d505 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -489,9 +489,7 @@ error_available: static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs, struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char * const names[], - const bool *ctx, + struct virtqueue_info vqs_info[], struct irq_affinity *desc) { struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); @@ -510,13 +508,15 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs, enable_irq_wake(irq); for (i = 0; i < nvqs; ++i) { - if (!names[i]) { + struct virtqueue_info *vqi = &vqs_info[i]; + + if (!vqi->name) { vqs[i] = NULL; continue; } - vqs[i] = vm_setup_vq(vdev, queue_idx++, callbacks[i], names[i], - ctx ? ctx[i] : false); + vqs[i] = vm_setup_vq(vdev, queue_idx++, vqi->callback, + vqi->name, vqi->ctx); if (IS_ERR(vqs[i])) { vm_del_vqs(vdev); return PTR_ERR(vqs[i]); @@ -570,7 +570,7 @@ static const struct virtio_config_ops virtio_mmio_config_ops = { .get_status = vm_get_status, .set_status = vm_set_status, .reset = vm_reset, - .find_vqs = vm_find_vqs, + .find_vqs_info = vm_find_vqs, .del_vqs = vm_del_vqs, .get_features = vm_get_features, .finalize_features = vm_finalize_features, diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index e803db0da307..bc86d81c7cd2 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -358,9 +358,7 @@ create_affinity_masks(unsigned int nvecs, struct irq_affinity *affd) static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs, struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char * const names[], - const bool *ctx, + struct virtqueue_info vqs_info[], struct irq_affinity *desc) { struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vdev); @@ -379,14 +377,15 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs, } for (i = 0; i < nvqs; ++i) { - if (!names[i]) { + struct virtqueue_info *vqi = &vqs_info[i]; + + if (!vqi->name) { vqs[i] = NULL; continue; } - vqs[i] = virtio_vdpa_setup_vq(vdev, queue_idx++, - callbacks[i], names[i], ctx ? - ctx[i] : false); + vqs[i] = virtio_vdpa_setup_vq(vdev, queue_idx++, vqi->callback, + vqi->name, vqi->ctx); if (IS_ERR(vqs[i])) { err = PTR_ERR(vqs[i]); goto err_setup_vq; @@ -470,7 +469,7 @@ static const struct virtio_config_ops virtio_vdpa_config_ops = { .get_status = virtio_vdpa_get_status, .set_status = virtio_vdpa_set_status, .reset = virtio_vdpa_reset, - .find_vqs = virtio_vdpa_find_vqs, + .find_vqs_info = virtio_vdpa_find_vqs, .del_vqs = virtio_vdpa_del_vqs, .get_features = virtio_vdpa_get_features, .finalize_features = virtio_vdpa_finalize_features, -- cgit v1.2.3 From 992648f5a61f1c9fab800fbc42dea31727cd8a55 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:02 +0200 Subject: virtio: call virtio_find_vqs_info() from virtio_find_single_vq() directly Since there are no more implementations of find_vqs() op, call virtio_find_vqs_info() from virtio_find_single_vq() directly. Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-8-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- include/linux/virtio_config.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index fb7a1fd00ee5..23ce1aec54e8 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -283,10 +283,11 @@ static inline struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, vq_callback_t *c, const char *n) { - vq_callback_t *callbacks[] = { c }; - const char *names[] = { n }; + struct virtqueue_info vqs_info[] = { + { n, c }, + }; struct virtqueue *vq; - int err = virtio_find_vqs(vdev, 1, &vq, callbacks, names, NULL); + int err = virtio_find_vqs_info(vdev, 1, &vq, vqs_info, NULL); if (err < 0) return ERR_PTR(err); -- cgit v1.2.3 From 18cd029fd7f7a85d522973f34c413a2b009255ac Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:03 +0200 Subject: virtio: remove the original find_vqs() op As it is no longer used, remove it. Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-9-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- include/linux/virtio_config.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 23ce1aec54e8..1ae346bd2dbd 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -63,15 +63,6 @@ struct virtqueue_info { * After this, status and feature negotiation must be done again * Device must not be reset from its vq/config callbacks, or in * parallel with being added/removed. - * @find_vqs: find virtqueues and instantiate them. - * vdev: the virtio_device - * nvqs: the number of virtqueues to find - * vqs: on success, includes new virtqueues - * callbacks: array of callbacks, for each virtqueue - * include a NULL entry for vqs that do not need a callback - * names: array of virtqueue names (mainly for debugging) - * include a NULL entry for vqs unused by driver - * Returns 0 on success or error status * @find_vqs_info: find virtqueues and instantiate them. * vdev: the virtio_device * nvqs: the number of virtqueues to find @@ -125,10 +116,6 @@ struct virtio_config_ops { u8 (*get_status)(struct virtio_device *vdev); void (*set_status)(struct virtio_device *vdev, u8 status); void (*reset)(struct virtio_device *vdev); - int (*find_vqs)(struct virtio_device *, unsigned nvqs, - struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char * const names[], const bool *ctx, - struct irq_affinity *desc); int (*find_vqs_info)(struct virtio_device *vdev, unsigned int nvqs, struct virtqueue *vqs[], struct virtqueue_info vqs_info[], @@ -252,10 +239,6 @@ int virtio_find_vqs_ctx(struct virtio_device *vdev, unsigned nvqs, struct virtqueue_info *vqs_info; int err, i; - if (!vdev->config->find_vqs_info) - return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, - names, ctx, desc); - vqs_info = kmalloc_array(nvqs, sizeof(*vqs_info), GFP_KERNEL); if (!vqs_info) return -ENOMEM; -- cgit v1.2.3 From b49503eaf9c74c3d0efd1e8331aba37ce3c1fd68 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:04 +0200 Subject: virtio: rename find_vqs_info() op to find_vqs() Since the original find_vqs() is no longer present, rename find_vqs_info() back to find_vqs(). Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-10-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- arch/um/drivers/virtio_uml.c | 2 +- drivers/platform/mellanox/mlxbf-tmfifo.c | 2 +- drivers/remoteproc/remoteproc_virtio.c | 2 +- drivers/s390/virtio/virtio_ccw.c | 2 +- drivers/virtio/virtio_mmio.c | 2 +- drivers/virtio/virtio_pci_legacy.c | 2 +- drivers/virtio/virtio_pci_modern.c | 4 ++-- drivers/virtio/virtio_vdpa.c | 2 +- include/linux/virtio_config.h | 12 ++++++------ 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index 4cc393e903fc..2b6e701776b6 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -1099,7 +1099,7 @@ static const struct virtio_config_ops virtio_uml_config_ops = { .get_status = vu_get_status, .set_status = vu_set_status, .reset = vu_reset, - .find_vqs_info = vu_find_vqs, + .find_vqs = vu_find_vqs, .del_vqs = vu_del_vqs, .get_features = vu_get_features, .finalize_features = vu_finalize_features, diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c index 3dc895cfdc4a..6c834e39352d 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo.c +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c @@ -1175,7 +1175,7 @@ static void tmfifo_virtio_dev_release(struct device *device) static const struct virtio_config_ops mlxbf_tmfifo_virtio_config_ops = { .get_features = mlxbf_tmfifo_virtio_get_features, .finalize_features = mlxbf_tmfifo_virtio_finalize_features, - .find_vqs_info = mlxbf_tmfifo_virtio_find_vqs, + .find_vqs = mlxbf_tmfifo_virtio_find_vqs, .del_vqs = mlxbf_tmfifo_virtio_del_vqs, .reset = mlxbf_tmfifo_virtio_reset, .set_status = mlxbf_tmfifo_virtio_set_status, diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index 870764c0ad9f..d3f39009b28e 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -327,7 +327,7 @@ static void rproc_virtio_set(struct virtio_device *vdev, unsigned int offset, static const struct virtio_config_ops rproc_virtio_config_ops = { .get_features = rproc_virtio_get_features, .finalize_features = rproc_virtio_finalize_features, - .find_vqs_info = rproc_virtio_find_vqs, + .find_vqs = rproc_virtio_find_vqs, .del_vqs = rproc_virtio_del_vqs, .reset = rproc_virtio_reset, .set_status = rproc_virtio_set_status, diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index fa884afff777..62eca9419ad7 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -1078,7 +1078,7 @@ static const struct virtio_config_ops virtio_ccw_config_ops = { .get_status = virtio_ccw_get_status, .set_status = virtio_ccw_set_status, .reset = virtio_ccw_reset, - .find_vqs_info = virtio_ccw_find_vqs, + .find_vqs = virtio_ccw_find_vqs, .del_vqs = virtio_ccw_del_vqs, .bus_name = virtio_ccw_bus_name, .synchronize_cbs = virtio_ccw_synchronize_cbs, diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 57903685d505..90e784e7b721 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -570,7 +570,7 @@ static const struct virtio_config_ops virtio_mmio_config_ops = { .get_status = vm_get_status, .set_status = vm_set_status, .reset = vm_reset, - .find_vqs_info = vm_find_vqs, + .find_vqs = vm_find_vqs, .del_vqs = vm_del_vqs, .get_features = vm_get_features, .finalize_features = vm_finalize_features, diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c index a9786e38d763..d9cbb02b35a1 100644 --- a/drivers/virtio/virtio_pci_legacy.c +++ b/drivers/virtio/virtio_pci_legacy.c @@ -192,7 +192,7 @@ static const struct virtio_config_ops virtio_pci_config_ops = { .get_status = vp_get_status, .set_status = vp_set_status, .reset = vp_reset, - .find_vqs_info = vp_find_vqs, + .find_vqs = vp_find_vqs, .del_vqs = vp_del_vqs, .synchronize_cbs = vp_synchronize_vectors, .get_features = vp_get_features, diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index adba4a29fdf4..3b5b9499a53a 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -781,7 +781,7 @@ static const struct virtio_config_ops virtio_pci_config_nodev_ops = { .get_status = vp_get_status, .set_status = vp_set_status, .reset = vp_reset, - .find_vqs_info = vp_modern_find_vqs, + .find_vqs = vp_modern_find_vqs, .del_vqs = vp_del_vqs, .synchronize_cbs = vp_synchronize_vectors, .get_features = vp_get_features, @@ -803,7 +803,7 @@ static const struct virtio_config_ops virtio_pci_config_ops = { .get_status = vp_get_status, .set_status = vp_set_status, .reset = vp_reset, - .find_vqs_info = vp_modern_find_vqs, + .find_vqs = vp_modern_find_vqs, .del_vqs = vp_del_vqs, .synchronize_cbs = vp_synchronize_vectors, .get_features = vp_get_features, diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index bc86d81c7cd2..7364bd53e38d 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -469,7 +469,7 @@ static const struct virtio_config_ops virtio_vdpa_config_ops = { .get_status = virtio_vdpa_get_status, .set_status = virtio_vdpa_set_status, .reset = virtio_vdpa_reset, - .find_vqs_info = virtio_vdpa_find_vqs, + .find_vqs = virtio_vdpa_find_vqs, .del_vqs = virtio_vdpa_del_vqs, .get_features = virtio_vdpa_get_features, .finalize_features = virtio_vdpa_finalize_features, diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 1ae346bd2dbd..7848fba7f48a 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -63,7 +63,7 @@ struct virtqueue_info { * After this, status and feature negotiation must be done again * Device must not be reset from its vq/config callbacks, or in * parallel with being added/removed. - * @find_vqs_info: find virtqueues and instantiate them. + * @find_vqs: find virtqueues and instantiate them. * vdev: the virtio_device * nvqs: the number of virtqueues to find * vqs: on success, includes new virtqueues @@ -116,10 +116,10 @@ struct virtio_config_ops { u8 (*get_status)(struct virtio_device *vdev); void (*set_status)(struct virtio_device *vdev, u8 status); void (*reset)(struct virtio_device *vdev); - int (*find_vqs_info)(struct virtio_device *vdev, unsigned int nvqs, - struct virtqueue *vqs[], - struct virtqueue_info vqs_info[], - struct irq_affinity *desc); + int (*find_vqs)(struct virtio_device *vdev, unsigned int nvqs, + struct virtqueue *vqs[], + struct virtqueue_info vqs_info[], + struct irq_affinity *desc); void (*del_vqs)(struct virtio_device *); void (*synchronize_cbs)(struct virtio_device *); u64 (*get_features)(struct virtio_device *vdev); @@ -227,7 +227,7 @@ int virtio_find_vqs_info(struct virtio_device *vdev, unsigned int nvqs, struct virtqueue_info vqs_info[], struct irq_affinity *desc) { - return vdev->config->find_vqs_info(vdev, nvqs, vqs, vqs_info, desc); + return vdev->config->find_vqs(vdev, nvqs, vqs, vqs_info, desc); } static inline -- cgit v1.2.3 From 0c60458b1827adbd1ddf7c7dcd2c5b82a449f6df Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:05 +0200 Subject: virtio_blk: convert to use virtio_find_vqs_info() Instead of passing separate names and callbacks arrays to virtio_find_vqs(), allocate one of virtual_queue_info structs and pass it to virtio_find_vqs_info(). Suggested-by: Xuan Zhuo Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-11-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- drivers/block/virtio_blk.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 2351f411fa46..ca3446503e82 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -964,8 +964,7 @@ static int init_vq(struct virtio_blk *vblk) { int err; unsigned short i; - vq_callback_t **callbacks; - const char **names; + struct virtqueue_info *vqs_info; struct virtqueue **vqs; unsigned short num_vqs; unsigned short num_poll_vqs; @@ -1002,28 +1001,26 @@ static int init_vq(struct virtio_blk *vblk) if (!vblk->vqs) return -ENOMEM; - names = kmalloc_array(num_vqs, sizeof(*names), GFP_KERNEL); - callbacks = kmalloc_array(num_vqs, sizeof(*callbacks), GFP_KERNEL); + vqs_info = kcalloc(num_vqs, sizeof(*vqs_info), GFP_KERNEL); vqs = kmalloc_array(num_vqs, sizeof(*vqs), GFP_KERNEL); - if (!names || !callbacks || !vqs) { + if (!vqs_info || !vqs) { err = -ENOMEM; goto out; } for (i = 0; i < num_vqs - num_poll_vqs; i++) { - callbacks[i] = virtblk_done; + vqs_info[i].callback = virtblk_done; snprintf(vblk->vqs[i].name, VQ_NAME_LEN, "req.%u", i); - names[i] = vblk->vqs[i].name; + vqs_info[i].name = vblk->vqs[i].name; } for (; i < num_vqs; i++) { - callbacks[i] = NULL; snprintf(vblk->vqs[i].name, VQ_NAME_LEN, "req_poll.%u", i); - names[i] = vblk->vqs[i].name; + vqs_info[i].name = vblk->vqs[i].name; } /* Discover virtqueues and write information to configuration. */ - err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc); + err = virtio_find_vqs_info(vdev, num_vqs, vqs, vqs_info, &desc); if (err) goto out; @@ -1035,8 +1032,7 @@ static int init_vq(struct virtio_blk *vblk) out: kfree(vqs); - kfree(callbacks); - kfree(names); + kfree(vqs_info); if (err) kfree(vblk->vqs); return err; -- cgit v1.2.3 From cd54c623a80bf818c72eb09051e462157d04cad4 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:06 +0200 Subject: virtio_console: convert to use virtio_find_vqs_info() Instead of passing separate names and callbacks arrays to virtio_find_vqs(), allocate one of virtual_queue_info structs and pass it to virtio_find_vqs_info(). Suggested-by: Xuan Zhuo Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-12-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- drivers/char/virtio_console.c | 44 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index d9ee2dbc7eab..903d83a1ffe8 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1804,8 +1804,7 @@ static void config_work_handler(struct work_struct *work) static int init_vqs(struct ports_device *portdev) { - vq_callback_t **io_callbacks; - char **io_names; + struct virtqueue_info *vqs_info; struct virtqueue **vqs; u32 i, j, nr_ports, nr_queues; int err; @@ -1814,15 +1813,12 @@ static int init_vqs(struct ports_device *portdev) nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; vqs = kmalloc_array(nr_queues, sizeof(struct virtqueue *), GFP_KERNEL); - io_callbacks = kmalloc_array(nr_queues, sizeof(vq_callback_t *), - GFP_KERNEL); - io_names = kmalloc_array(nr_queues, sizeof(char *), GFP_KERNEL); + vqs_info = kcalloc(nr_queues, sizeof(*vqs_info), GFP_KERNEL); portdev->in_vqs = kmalloc_array(nr_ports, sizeof(struct virtqueue *), GFP_KERNEL); portdev->out_vqs = kmalloc_array(nr_ports, sizeof(struct virtqueue *), GFP_KERNEL); - if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs || - !portdev->out_vqs) { + if (!vqs || !vqs_info || !portdev->in_vqs || !portdev->out_vqs) { err = -ENOMEM; goto free; } @@ -1833,30 +1829,28 @@ static int init_vqs(struct ports_device *portdev) * 0 before others. */ j = 0; - io_callbacks[j] = in_intr; - io_callbacks[j + 1] = out_intr; - io_names[j] = "input"; - io_names[j + 1] = "output"; + vqs_info[j].callback = in_intr; + vqs_info[j + 1].callback = out_intr; + vqs_info[j].name = "input"; + vqs_info[j + 1].name = "output"; j += 2; if (use_multiport(portdev)) { - io_callbacks[j] = control_intr; - io_callbacks[j + 1] = NULL; - io_names[j] = "control-i"; - io_names[j + 1] = "control-o"; + vqs_info[j].callback = control_intr; + vqs_info[j].name = "control-i"; + vqs_info[j + 1].name = "control-o"; for (i = 1; i < nr_ports; i++) { j += 2; - io_callbacks[j] = in_intr; - io_callbacks[j + 1] = out_intr; - io_names[j] = "input"; - io_names[j + 1] = "output"; + vqs_info[j].callback = in_intr; + vqs_info[j + 1].callback = out_intr; + vqs_info[j].name = "input"; + vqs_info[j + 1].name = "output"; } } /* Find the queues. */ - err = virtio_find_vqs(portdev->vdev, nr_queues, vqs, - io_callbacks, - (const char **)io_names, NULL); + err = virtio_find_vqs_info(portdev->vdev, nr_queues, vqs, + vqs_info, NULL); if (err) goto free; @@ -1874,8 +1868,7 @@ static int init_vqs(struct ports_device *portdev) portdev->out_vqs[i] = vqs[j + 1]; } } - kfree(io_names); - kfree(io_callbacks); + kfree(vqs_info); kfree(vqs); return 0; @@ -1883,8 +1876,7 @@ static int init_vqs(struct ports_device *portdev) free: kfree(portdev->out_vqs); kfree(portdev->in_vqs); - kfree(io_names); - kfree(io_callbacks); + kfree(vqs_info); kfree(vqs); return err; -- cgit v1.2.3 From 210a70f22dd09559c2fdc0135aecdd6fe01d724e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:07 +0200 Subject: virtio_crypto: convert to use virtio_find_vqs_info() Instead of passing separate names and callbacks arrays to virtio_find_vqs(), allocate one of virtual_queue_info structs and pass it to virtio_find_vqs_info(). Suggested-by: Xuan Zhuo Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-13-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- drivers/crypto/virtio/virtio_crypto_core.c | 31 ++++++++++++------------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/crypto/virtio/virtio_crypto_core.c b/drivers/crypto/virtio/virtio_crypto_core.c index 30cd040aa03b..b8119d1f9931 100644 --- a/drivers/crypto/virtio/virtio_crypto_core.c +++ b/drivers/crypto/virtio/virtio_crypto_core.c @@ -96,11 +96,10 @@ static void virtcrypto_dataq_callback(struct virtqueue *vq) static int virtcrypto_find_vqs(struct virtio_crypto *vi) { - vq_callback_t **callbacks; + struct virtqueue_info *vqs_info; struct virtqueue **vqs; int ret = -ENOMEM; int i, total_vqs; - const char **names; struct device *dev = &vi->vdev->dev; /* @@ -114,26 +113,23 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi) vqs = kcalloc(total_vqs, sizeof(*vqs), GFP_KERNEL); if (!vqs) goto err_vq; - callbacks = kcalloc(total_vqs, sizeof(*callbacks), GFP_KERNEL); - if (!callbacks) - goto err_callback; - names = kcalloc(total_vqs, sizeof(*names), GFP_KERNEL); - if (!names) - goto err_names; + vqs_info = kcalloc(total_vqs, sizeof(*vqs_info), GFP_KERNEL); + if (!vqs_info) + goto err_vqs_info; /* Parameters for control virtqueue */ - callbacks[total_vqs - 1] = virtcrypto_ctrlq_callback; - names[total_vqs - 1] = "controlq"; + vqs_info[total_vqs - 1].callback = virtcrypto_ctrlq_callback; + vqs_info[total_vqs - 1].name = "controlq"; /* Allocate/initialize parameters for data virtqueues */ for (i = 0; i < vi->max_data_queues; i++) { - callbacks[i] = virtcrypto_dataq_callback; + vqs_info[i].callback = virtcrypto_dataq_callback; snprintf(vi->data_vq[i].name, sizeof(vi->data_vq[i].name), "dataq.%d", i); - names[i] = vi->data_vq[i].name; + vqs_info[i].name = vi->data_vq[i].name; } - ret = virtio_find_vqs(vi->vdev, total_vqs, vqs, callbacks, names, NULL); + ret = virtio_find_vqs_info(vi->vdev, total_vqs, vqs, vqs_info, NULL); if (ret) goto err_find; @@ -153,18 +149,15 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi) (unsigned long)&vi->data_vq[i]); } - kfree(names); - kfree(callbacks); + kfree(vqs_info); kfree(vqs); return 0; err_engine: err_find: - kfree(names); -err_names: - kfree(callbacks); -err_callback: + kfree(vqs_info); +err_vqs_info: kfree(vqs); err_vq: return ret; -- cgit v1.2.3 From c2c6325e1645b56cc5784c288686e11d649c453e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:08 +0200 Subject: virtio_net: convert to use virtio_find_vqs_info() Instead of passing separate names and callbacks arrays to virtio_find_vqs_ctx(), allocate one of virtual_queue_info structs and pass it to virtio_find_vqs_info(). Suggested-by: Xuan Zhuo Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-14-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- drivers/net/virtio_net.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index ea10db9a09fa..7a0a44216bec 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -5293,9 +5293,8 @@ static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqu static int virtnet_find_vqs(struct virtnet_info *vi) { - vq_callback_t **callbacks; + struct virtqueue_info *vqs_info; struct virtqueue **vqs; - const char **names; int ret = -ENOMEM; int total_vqs; bool *ctx; @@ -5312,12 +5311,9 @@ static int virtnet_find_vqs(struct virtnet_info *vi) vqs = kcalloc(total_vqs, sizeof(*vqs), GFP_KERNEL); if (!vqs) goto err_vq; - callbacks = kmalloc_array(total_vqs, sizeof(*callbacks), GFP_KERNEL); - if (!callbacks) - goto err_callback; - names = kmalloc_array(total_vqs, sizeof(*names), GFP_KERNEL); - if (!names) - goto err_names; + vqs_info = kcalloc(total_vqs, sizeof(*vqs_info), GFP_KERNEL); + if (!vqs_info) + goto err_vqs_info; if (!vi->big_packets || vi->mergeable_rx_bufs) { ctx = kcalloc(total_vqs, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -5328,24 +5324,22 @@ static int virtnet_find_vqs(struct virtnet_info *vi) /* Parameters for control virtqueue, if any */ if (vi->has_cvq) { - callbacks[total_vqs - 1] = NULL; - names[total_vqs - 1] = "control"; + vqs_info[total_vqs - 1].name = "control"; } /* Allocate/initialize parameters for send/receive virtqueues */ for (i = 0; i < vi->max_queue_pairs; i++) { - callbacks[rxq2vq(i)] = skb_recv_done; - callbacks[txq2vq(i)] = skb_xmit_done; + vqs_info[rxq2vq(i)].callback = skb_recv_done; + vqs_info[txq2vq(i)].callback = skb_xmit_done; sprintf(vi->rq[i].name, "input.%u", i); sprintf(vi->sq[i].name, "output.%u", i); - names[rxq2vq(i)] = vi->rq[i].name; - names[txq2vq(i)] = vi->sq[i].name; + vqs_info[rxq2vq(i)].name = vi->rq[i].name; + vqs_info[txq2vq(i)].name = vi->sq[i].name; if (ctx) - ctx[rxq2vq(i)] = true; + vqs_info[rxq2vq(i)].ctx = true; } - ret = virtio_find_vqs_ctx(vi->vdev, total_vqs, vqs, callbacks, - names, ctx, NULL); + ret = virtio_find_vqs_info(vi->vdev, total_vqs, vqs, vqs_info, NULL); if (ret) goto err_find; @@ -5367,10 +5361,8 @@ static int virtnet_find_vqs(struct virtnet_info *vi) err_find: kfree(ctx); err_ctx: - kfree(names); -err_names: - kfree(callbacks); -err_callback: + kfree(vqs_info); +err_vqs_info: kfree(vqs); err_vq: return ret; -- cgit v1.2.3 From a6da214b7c9d8f1c32e1d1844c78f764db63cd48 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:09 +0200 Subject: scsi: virtio_scsi: convert to use virtio_find_vqs_info() Instead of passing separate names and callbacks arrays to virtio_find_vqs(), allocate one of virtual_queue_info structs and pass it to virtio_find_vqs_info(). Suggested-by: Xuan Zhuo Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-15-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- drivers/scsi/virtio_scsi.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 89ca26945721..bf9346a66df2 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -841,19 +841,16 @@ static int virtscsi_init(struct virtio_device *vdev, int err; u32 i; u32 num_vqs, num_poll_vqs, num_req_vqs; - vq_callback_t **callbacks; - const char **names; + struct virtqueue_info *vqs_info; struct virtqueue **vqs; struct irq_affinity desc = { .pre_vectors = 2 }; num_req_vqs = vscsi->num_queues; num_vqs = num_req_vqs + VIRTIO_SCSI_VQ_BASE; vqs = kmalloc_array(num_vqs, sizeof(struct virtqueue *), GFP_KERNEL); - callbacks = kmalloc_array(num_vqs, sizeof(vq_callback_t *), - GFP_KERNEL); - names = kmalloc_array(num_vqs, sizeof(char *), GFP_KERNEL); + vqs_info = kcalloc(num_vqs, sizeof(*vqs_info), GFP_KERNEL); - if (!callbacks || !vqs || !names) { + if (!vqs || !vqs_info) { err = -ENOMEM; goto out; } @@ -869,22 +866,20 @@ static int virtscsi_init(struct virtio_device *vdev, vscsi->io_queues[HCTX_TYPE_READ], vscsi->io_queues[HCTX_TYPE_POLL]); - callbacks[0] = virtscsi_ctrl_done; - callbacks[1] = virtscsi_event_done; - names[0] = "control"; - names[1] = "event"; + vqs_info[0].callback = virtscsi_ctrl_done; + vqs_info[0].name = "control"; + vqs_info[1].callback = virtscsi_event_done; + vqs_info[1].name = "event"; for (i = VIRTIO_SCSI_VQ_BASE; i < num_vqs - num_poll_vqs; i++) { - callbacks[i] = virtscsi_req_done; - names[i] = "request"; + vqs_info[i].callback = virtscsi_req_done; + vqs_info[i].name = "request"; } - for (; i < num_vqs; i++) { - callbacks[i] = NULL; - names[i] = "request_poll"; - } + for (; i < num_vqs; i++) + vqs_info[i].name = "request_poll"; /* Discover virtqueues and write information to configuration. */ - err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc); + err = virtio_find_vqs_info(vdev, num_vqs, vqs, vqs_info, &desc); if (err) goto out; @@ -900,8 +895,7 @@ static int virtscsi_init(struct virtio_device *vdev, err = 0; out: - kfree(names); - kfree(callbacks); + kfree(vqs_info); kfree(vqs); if (err) virtscsi_remove_vqs(vdev); -- cgit v1.2.3 From fc496dcd935c23a0b4425e34f82c2ec33c2893f6 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:10 +0200 Subject: virtiofs: convert to use virtio_find_vqs_info() Instead of passing separate names and callbacks arrays to virtio_find_vqs(), allocate one of virtual_queue_info structs and pass it to virtio_find_vqs_info(). Suggested-by: Xuan Zhuo Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-16-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- fs/fuse/virtio_fs.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 728f14e077bd..a335b421f196 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -789,14 +789,13 @@ static void virtio_fs_init_vq(struct virtio_fs_vq *fsvq, char *name, static int virtio_fs_setup_vqs(struct virtio_device *vdev, struct virtio_fs *fs) { + struct virtqueue_info *vqs_info; struct virtqueue **vqs; - vq_callback_t **callbacks; /* Specify pre_vectors to ensure that the queues before the * request queues (e.g. hiprio) don't claim any of the CPUs in * the multi-queue mapping and interrupt affinities */ struct irq_affinity desc = { .pre_vectors = VQ_REQUEST }; - const char **names; unsigned int i; int ret = 0; @@ -814,20 +813,18 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev, return -ENOMEM; vqs = kmalloc_array(fs->nvqs, sizeof(vqs[VQ_HIPRIO]), GFP_KERNEL); - callbacks = kmalloc_array(fs->nvqs, sizeof(callbacks[VQ_HIPRIO]), - GFP_KERNEL); - names = kmalloc_array(fs->nvqs, sizeof(names[VQ_HIPRIO]), GFP_KERNEL); fs->mq_map = kcalloc_node(nr_cpu_ids, sizeof(*fs->mq_map), GFP_KERNEL, dev_to_node(&vdev->dev)); - if (!vqs || !callbacks || !names || !fs->mq_map) { + vqs_info = kcalloc(fs->nvqs, sizeof(*vqs_info), GFP_KERNEL); + if (!vqs || !vqs_info || !fs->mq_map) { ret = -ENOMEM; goto out; } /* Initialize the hiprio/forget request virtqueue */ - callbacks[VQ_HIPRIO] = virtio_fs_vq_done; + vqs_info[VQ_HIPRIO].callback = virtio_fs_vq_done; virtio_fs_init_vq(&fs->vqs[VQ_HIPRIO], "hiprio", VQ_HIPRIO); - names[VQ_HIPRIO] = fs->vqs[VQ_HIPRIO].name; + vqs_info[VQ_HIPRIO].name = fs->vqs[VQ_HIPRIO].name; /* Initialize the requests virtqueues */ for (i = VQ_REQUEST; i < fs->nvqs; i++) { @@ -835,11 +832,11 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev, snprintf(vq_name, VQ_NAME_LEN, "requests.%u", i - VQ_REQUEST); virtio_fs_init_vq(&fs->vqs[i], vq_name, VQ_REQUEST); - callbacks[i] = virtio_fs_vq_done; - names[i] = fs->vqs[i].name; + vqs_info[i].callback = virtio_fs_vq_done; + vqs_info[i].name = fs->vqs[i].name; } - ret = virtio_find_vqs(vdev, fs->nvqs, vqs, callbacks, names, &desc); + ret = virtio_find_vqs_info(vdev, fs->nvqs, vqs, vqs_info, &desc); if (ret < 0) goto out; @@ -848,8 +845,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev, virtio_fs_start_all_queues(fs); out: - kfree(names); - kfree(callbacks); + kfree(vqs_info); kfree(vqs); if (ret) { kfree(fs->vqs); -- cgit v1.2.3 From 7221922da2a1eb8bbc8d6570cec1197c8f484517 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:11 +0200 Subject: virtio_balloon: convert to use virtio_find_vqs_info() Instead of passing separate names and callbacks arrays to virtio_find_vqs(), have one of virtual_queue_info structs and pass it to virtio_find_vqs_info(). Suggested-by: Xuan Zhuo Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-17-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_balloon.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 9a61febbd2f7..cfa710abf441 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -560,9 +560,8 @@ static void update_balloon_size_func(struct work_struct *work) static int init_vqs(struct virtio_balloon *vb) { + struct virtqueue_info vqs_info[VIRTIO_BALLOON_VQ_MAX] = {}; struct virtqueue *vqs[VIRTIO_BALLOON_VQ_MAX]; - vq_callback_t *callbacks[VIRTIO_BALLOON_VQ_MAX]; - const char *names[VIRTIO_BALLOON_VQ_MAX]; int err; /* @@ -570,33 +569,26 @@ static int init_vqs(struct virtio_balloon *vb) * will be NULL if the related feature is not enabled, which will * cause no allocation for the corresponding virtqueue in find_vqs. */ - callbacks[VIRTIO_BALLOON_VQ_INFLATE] = balloon_ack; - names[VIRTIO_BALLOON_VQ_INFLATE] = "inflate"; - callbacks[VIRTIO_BALLOON_VQ_DEFLATE] = balloon_ack; - names[VIRTIO_BALLOON_VQ_DEFLATE] = "deflate"; - callbacks[VIRTIO_BALLOON_VQ_STATS] = NULL; - names[VIRTIO_BALLOON_VQ_STATS] = NULL; - callbacks[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL; - names[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL; - names[VIRTIO_BALLOON_VQ_REPORTING] = NULL; + vqs_info[VIRTIO_BALLOON_VQ_INFLATE].callback = balloon_ack; + vqs_info[VIRTIO_BALLOON_VQ_INFLATE].name = "inflate"; + vqs_info[VIRTIO_BALLOON_VQ_DEFLATE].callback = balloon_ack; + vqs_info[VIRTIO_BALLOON_VQ_DEFLATE].name = "deflate"; if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) { - names[VIRTIO_BALLOON_VQ_STATS] = "stats"; - callbacks[VIRTIO_BALLOON_VQ_STATS] = stats_request; + vqs_info[VIRTIO_BALLOON_VQ_STATS].name = "stats"; + vqs_info[VIRTIO_BALLOON_VQ_STATS].callback = stats_request; } - if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) { - names[VIRTIO_BALLOON_VQ_FREE_PAGE] = "free_page_vq"; - callbacks[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL; - } + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) + vqs_info[VIRTIO_BALLOON_VQ_FREE_PAGE].name = "free_page_vq"; if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_REPORTING)) { - names[VIRTIO_BALLOON_VQ_REPORTING] = "reporting_vq"; - callbacks[VIRTIO_BALLOON_VQ_REPORTING] = balloon_ack; + vqs_info[VIRTIO_BALLOON_VQ_REPORTING].name = "reporting_vq"; + vqs_info[VIRTIO_BALLOON_VQ_REPORTING].callback = balloon_ack; } - err = virtio_find_vqs(vb->vdev, VIRTIO_BALLOON_VQ_MAX, vqs, - callbacks, names, NULL); + err = virtio_find_vqs_info(vb->vdev, VIRTIO_BALLOON_VQ_MAX, vqs, + vqs_info, NULL); if (err) return err; -- cgit v1.2.3 From c95e67bac42d7e671e6a2c14548b6a7f76e71235 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:12 +0200 Subject: virtio: convert the rest virtio_find_vqs() users to virtio_find_vqs_info() Instead of passing separate names and callbacks arrays to virtio_find_vqs(), have one of virtual_queue_info structs and pass it to virtio_find_vqs_info(). Suggested-by: Xuan Zhuo Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-18-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- arch/um/drivers/virt-pci.c | 8 +++++--- drivers/bluetooth/virtio_bt.c | 14 +++++--------- drivers/firmware/arm_scmi/virtio.c | 11 ++++------- drivers/gpio/gpio-virtio.c | 10 +++++----- drivers/gpu/drm/virtio/virtgpu_kms.c | 9 ++++----- drivers/iommu/virtio-iommu.c | 11 +++++------ drivers/net/wireless/virtual/mac80211_hwsim.c | 14 +++++--------- drivers/rpmsg/virtio_rpmsg_bus.c | 8 +++++--- drivers/virtio/virtio_input.c | 9 +++++---- net/vmw_vsock/virtio_transport.c | 17 ++++++----------- sound/virtio/virtio_card.c | 23 ++++++++++------------- 11 files changed, 59 insertions(+), 75 deletions(-) diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c index 7cb503469bbd..3a668241c0aa 100644 --- a/arch/um/drivers/virt-pci.c +++ b/arch/um/drivers/virt-pci.c @@ -567,12 +567,14 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) static int um_pci_init_vqs(struct um_pci_device *dev) { + struct virtqueue_info vqs_info[] = { + { "cmd", um_pci_cmd_vq_cb }, + { "irq", um_pci_irq_vq_cb }, + }; struct virtqueue *vqs[2]; - static const char *const names[2] = { "cmd", "irq" }; - vq_callback_t *cbs[2] = { um_pci_cmd_vq_cb, um_pci_irq_vq_cb }; int err, i; - err = virtio_find_vqs(dev->vdev, 2, vqs, cbs, names, NULL); + err = virtio_find_vqs_info(dev->vdev, 2, vqs, vqs_info, NULL); if (err) return err; diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c index 40bd83825c29..79574855ed54 100644 --- a/drivers/bluetooth/virtio_bt.c +++ b/drivers/bluetooth/virtio_bt.c @@ -254,13 +254,9 @@ static void virtbt_rx_done(struct virtqueue *vq) static int virtbt_probe(struct virtio_device *vdev) { - vq_callback_t *callbacks[VIRTBT_NUM_VQS] = { - [VIRTBT_VQ_TX] = virtbt_tx_done, - [VIRTBT_VQ_RX] = virtbt_rx_done, - }; - const char *names[VIRTBT_NUM_VQS] = { - [VIRTBT_VQ_TX] = "tx", - [VIRTBT_VQ_RX] = "rx", + struct virtqueue_info vqs_info[VIRTBT_NUM_VQS] = { + [VIRTBT_VQ_TX] = { "tx", virtbt_tx_done }, + [VIRTBT_VQ_RX] = { "rx", virtbt_rx_done }, }; struct virtio_bluetooth *vbt; struct hci_dev *hdev; @@ -288,8 +284,8 @@ static int virtbt_probe(struct virtio_device *vdev) INIT_WORK(&vbt->rx, virtbt_rx_work); - err = virtio_find_vqs(vdev, VIRTBT_NUM_VQS, vbt->vqs, callbacks, - names, NULL); + err = virtio_find_vqs_info(vdev, VIRTBT_NUM_VQS, vbt->vqs, + vqs_info, NULL); if (err) return err; diff --git a/drivers/firmware/arm_scmi/virtio.c b/drivers/firmware/arm_scmi/virtio.c index 4892058445ce..d7cdefb6bd54 100644 --- a/drivers/firmware/arm_scmi/virtio.c +++ b/drivers/firmware/arm_scmi/virtio.c @@ -354,11 +354,9 @@ static void scmi_vio_deferred_tx_worker(struct work_struct *work) scmi_vio_channel_release(vioch); } -static const char *const scmi_vio_vqueue_names[] = { "tx", "rx" }; - -static vq_callback_t *scmi_vio_complete_callbacks[] = { - scmi_vio_complete_cb, - scmi_vio_complete_cb +static struct virtqueue_info scmi_vio_vqs_info[] = { + { "tx", scmi_vio_complete_cb }, + { "rx", scmi_vio_complete_cb }, }; static unsigned int virtio_get_max_msg(struct scmi_chan_info *base_cinfo) @@ -831,8 +829,7 @@ static int scmi_vio_probe(struct virtio_device *vdev) if (have_vq_rx) channels[VIRTIO_SCMI_VQ_RX].is_rx = true; - ret = virtio_find_vqs(vdev, vq_cnt, vqs, scmi_vio_complete_callbacks, - scmi_vio_vqueue_names, NULL); + ret = virtio_find_vqs_info(vdev, vq_cnt, vqs, scmi_vio_vqs_info, NULL); if (ret) { dev_err(dev, "Failed to get %d virtqueue(s)\n", vq_cnt); return ret; diff --git a/drivers/gpio/gpio-virtio.c b/drivers/gpio/gpio-virtio.c index 9fae8e396c58..d11464420797 100644 --- a/drivers/gpio/gpio-virtio.c +++ b/drivers/gpio/gpio-virtio.c @@ -457,15 +457,15 @@ static void virtio_gpio_free_vqs(struct virtio_device *vdev) static int virtio_gpio_alloc_vqs(struct virtio_gpio *vgpio, struct virtio_device *vdev) { - const char * const names[] = { "requestq", "eventq" }; - vq_callback_t *cbs[] = { - virtio_gpio_request_vq, - virtio_gpio_event_vq, + struct virtqueue_info vqs_info[] = { + { "requestq", virtio_gpio_request_vq }, + { "eventq", virtio_gpio_event_vq }, }; struct virtqueue *vqs[2] = { NULL, NULL }; int ret; - ret = virtio_find_vqs(vdev, vgpio->irq_lines ? 2 : 1, vqs, cbs, names, NULL); + ret = virtio_find_vqs_info(vdev, vgpio->irq_lines ? 2 : 1, vqs, + vqs_info, NULL); if (ret) { dev_err(&vdev->dev, "failed to find vqs: %d\n", ret); return ret; diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 5a3b5aaed1f3..1590fc180c66 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -116,11 +116,10 @@ static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev, int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev) { - static vq_callback_t *callbacks[] = { - virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack + struct virtqueue_info vqs_info[] = { + { "control", virtio_gpu_ctrl_ack }, + { "cursor", virtio_gpu_cursor_ack }, }; - static const char * const names[] = { "control", "cursor" }; - struct virtio_gpu_device *vgdev; /* this will expand later */ struct virtqueue *vqs[2]; @@ -207,7 +206,7 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev) DRM_INFO("features: %ccontext_init\n", vgdev->has_context_init ? '+' : '-'); - ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL); + ret = virtio_find_vqs_info(vgdev->vdev, 2, vqs, vqs_info, NULL); if (ret) { DRM_ERROR("failed to find virt queues\n"); goto err_vqs; diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c index 36d680826b57..d3c7877a3806 100644 --- a/drivers/iommu/virtio-iommu.c +++ b/drivers/iommu/virtio-iommu.c @@ -1084,14 +1084,13 @@ static struct iommu_ops viommu_ops = { static int viommu_init_vqs(struct viommu_dev *viommu) { struct virtio_device *vdev = dev_to_virtio(viommu->dev); - const char *names[] = { "request", "event" }; - vq_callback_t *callbacks[] = { - NULL, /* No async requests */ - viommu_event_handler, + struct virtqueue_info vqs_info[] = { + { "request" }, + { "event", viommu_event_handler }, }; - return virtio_find_vqs(vdev, VIOMMU_NR_VQS, viommu->vqs, callbacks, - names, NULL); + return virtio_find_vqs_info(vdev, VIOMMU_NR_VQS, viommu->vqs, + vqs_info, NULL); } static int viommu_fill_evtq(struct viommu_dev *viommu) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index c5d896994e70..7bda786631ba 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -6574,17 +6574,13 @@ static void hwsim_virtio_rx_done(struct virtqueue *vq) static int init_vqs(struct virtio_device *vdev) { - vq_callback_t *callbacks[HWSIM_NUM_VQS] = { - [HWSIM_VQ_TX] = hwsim_virtio_tx_done, - [HWSIM_VQ_RX] = hwsim_virtio_rx_done, - }; - const char *names[HWSIM_NUM_VQS] = { - [HWSIM_VQ_TX] = "tx", - [HWSIM_VQ_RX] = "rx", + struct virtqueue_info vqs_info[HWSIM_NUM_VQS] = { + [HWSIM_VQ_TX] = { "tx", hwsim_virtio_tx_done }, + [HWSIM_VQ_RX] = { "rx", hwsim_virtio_rx_done }, }; - return virtio_find_vqs(vdev, HWSIM_NUM_VQS, - hwsim_vqs, callbacks, names, NULL); + return virtio_find_vqs_info(vdev, HWSIM_NUM_VQS, + hwsim_vqs, vqs_info, NULL); } static int fill_vq(struct virtqueue *vq) diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index e9e8c1f7829f..fb466ef20f07 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -868,8 +868,10 @@ static void rpmsg_virtio_del_ctrl_dev(struct rpmsg_device *rpdev_ctrl) static int rpmsg_probe(struct virtio_device *vdev) { - vq_callback_t *vq_cbs[] = { rpmsg_recv_done, rpmsg_xmit_done }; - static const char * const names[] = { "input", "output" }; + struct virtqueue_info vqs_info[] = { + { "input", rpmsg_recv_done }, + { "output", rpmsg_xmit_done }, + }; struct virtqueue *vqs[2]; struct virtproc_info *vrp; struct virtio_rpmsg_channel *vch = NULL; @@ -891,7 +893,7 @@ static int rpmsg_probe(struct virtio_device *vdev) init_waitqueue_head(&vrp->sendq); /* We expect two virtqueues, rx and tx (and in this order) */ - err = virtio_find_vqs(vdev, 2, vqs, vq_cbs, names, NULL); + err = virtio_find_vqs_info(vdev, 2, vqs, vqs_info, NULL); if (err) goto free_vrp; diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c index 1a730d6c0b55..6f803dc3d0f9 100644 --- a/drivers/virtio/virtio_input.c +++ b/drivers/virtio/virtio_input.c @@ -185,13 +185,14 @@ static void virtinput_cfg_abs(struct virtio_input *vi, int abs) static int virtinput_init_vqs(struct virtio_input *vi) { + struct virtqueue_info vqs_info[] = { + { "events", virtinput_recv_events }, + { "status", virtinput_recv_status }, + }; struct virtqueue *vqs[2]; - vq_callback_t *cbs[] = { virtinput_recv_events, - virtinput_recv_status }; - static const char * const names[] = { "events", "status" }; int err; - err = virtio_find_vqs(vi->vdev, 2, vqs, cbs, names, NULL); + err = virtio_find_vqs_info(vi->vdev, 2, vqs, vqs_info, NULL); if (err) return err; vi->evt = vqs[0]; diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c index 43d405298857..3033680fcc98 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -617,20 +617,15 @@ out: static int virtio_vsock_vqs_init(struct virtio_vsock *vsock) { struct virtio_device *vdev = vsock->vdev; - static const char * const names[] = { - "rx", - "tx", - "event", - }; - vq_callback_t *callbacks[] = { - virtio_vsock_rx_done, - virtio_vsock_tx_done, - virtio_vsock_event_done, + struct virtqueue_info vqs_info[] = { + { "rx", virtio_vsock_rx_done }, + { "tx", virtio_vsock_tx_done }, + { "event", virtio_vsock_event_done }, }; int ret; - ret = virtio_find_vqs(vdev, VSOCK_VQ_MAX, vsock->vqs, callbacks, names, - NULL); + ret = virtio_find_vqs_info(vdev, VSOCK_VQ_MAX, vsock->vqs, vqs_info, + NULL); if (ret < 0) return ret; diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 7805daea0102..109a0008b69e 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -110,25 +110,22 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue) static int virtsnd_find_vqs(struct virtio_snd *snd) { struct virtio_device *vdev = snd->vdev; - static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = { - [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb, - [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb, - [VIRTIO_SND_VQ_TX] = virtsnd_pcm_tx_notify_cb, - [VIRTIO_SND_VQ_RX] = virtsnd_pcm_rx_notify_cb - }; - static const char *names[VIRTIO_SND_VQ_MAX] = { - [VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl", - [VIRTIO_SND_VQ_EVENT] = "virtsnd-event", - [VIRTIO_SND_VQ_TX] = "virtsnd-tx", - [VIRTIO_SND_VQ_RX] = "virtsnd-rx" + struct virtqueue_info vqs_info[VIRTIO_SND_VQ_MAX] = { + [VIRTIO_SND_VQ_CONTROL] = { "virtsnd-ctl", + virtsnd_ctl_notify_cb }, + [VIRTIO_SND_VQ_EVENT] = { "virtsnd-event", + virtsnd_event_notify_cb }, + [VIRTIO_SND_VQ_TX] = { "virtsnd-tx", + virtsnd_pcm_tx_notify_cb }, + [VIRTIO_SND_VQ_RX] = { "virtsnd-rx", + virtsnd_pcm_rx_notify_cb }, }; struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 }; unsigned int i; unsigned int n; int rc; - rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names, - NULL); + rc = virtio_find_vqs_info(vdev, VIRTIO_SND_VQ_MAX, vqs, vqs_info, NULL); if (rc) { dev_err(&vdev->dev, "failed to initialize virtqueues\n"); return rc; -- cgit v1.2.3 From 3e8d51c7765dac2a70fe2ad222a8ad244c9f29a4 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:13 +0200 Subject: virtio: remove unused virtio_find_vqs() and virtio_find_vqs_ctx() helpers All callers of virtio_find_vqs() and virtio_find_vqs_ctx() were converted to use virtio_find_vqs_info(). Remove no longer used helpers. Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-19-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- include/linux/virtio_config.h | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 7848fba7f48a..b6b615c3e21d 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -230,38 +230,6 @@ int virtio_find_vqs_info(struct virtio_device *vdev, unsigned int nvqs, return vdev->config->find_vqs(vdev, nvqs, vqs, vqs_info, desc); } -static inline -int virtio_find_vqs_ctx(struct virtio_device *vdev, unsigned nvqs, - struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char * const names[], const bool *ctx, - struct irq_affinity *desc) -{ - struct virtqueue_info *vqs_info; - int err, i; - - vqs_info = kmalloc_array(nvqs, sizeof(*vqs_info), GFP_KERNEL); - if (!vqs_info) - return -ENOMEM; - for (i = 0; i < nvqs; i++) { - vqs_info[i].name = names[i]; - vqs_info[i].callback = callbacks[i]; - vqs_info[i].ctx = ctx ? ctx[i] : false; - } - err = virtio_find_vqs_info(vdev, nvqs, vqs, vqs_info, desc); - kfree(vqs_info); - return err; -} - -static inline -int virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, - struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char * const names[], - struct irq_affinity *desc) -{ - return virtio_find_vqs_ctx(vdev, nvqs, vqs, callbacks, - names, NULL, desc); -} - static inline struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, vq_callback_t *c, const char *n) -- cgit v1.2.3 From 6c85d6b653caeba2ef982925703cbb4f2b3b3163 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 8 Jul 2024 09:48:14 +0200 Subject: virtio: rename virtio_find_vqs_info() to virtio_find_vqs() Since the original virtio_find_vqs() is no longer present, rename virtio_find_vqs_info() back to virtio_find_vqs(). Signed-off-by: Jiri Pirko Message-Id: <20240708074814.1739223-20-jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin --- arch/um/drivers/virt-pci.c | 2 +- drivers/block/virtio_blk.c | 2 +- drivers/bluetooth/virtio_bt.c | 3 +-- drivers/char/virtio_console.c | 3 +-- drivers/crypto/virtio/virtio_crypto_core.c | 2 +- drivers/firmware/arm_scmi/virtio.c | 2 +- drivers/gpio/gpio-virtio.c | 4 ++-- drivers/gpu/drm/virtio/virtgpu_kms.c | 2 +- drivers/iommu/virtio-iommu.c | 4 ++-- drivers/net/virtio_net.c | 2 +- drivers/net/wireless/virtual/mac80211_hwsim.c | 4 ++-- drivers/rpmsg/virtio_rpmsg_bus.c | 2 +- drivers/scsi/virtio_scsi.c | 2 +- drivers/virtio/virtio_balloon.c | 4 ++-- drivers/virtio/virtio_input.c | 2 +- fs/fuse/virtio_fs.c | 2 +- include/linux/virtio_config.h | 10 +++++----- net/vmw_vsock/virtio_transport.c | 3 +-- sound/virtio/virtio_card.c | 2 +- 19 files changed, 27 insertions(+), 30 deletions(-) diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c index 3a668241c0aa..b16a75c94b8b 100644 --- a/arch/um/drivers/virt-pci.c +++ b/arch/um/drivers/virt-pci.c @@ -574,7 +574,7 @@ static int um_pci_init_vqs(struct um_pci_device *dev) struct virtqueue *vqs[2]; int err, i; - err = virtio_find_vqs_info(dev->vdev, 2, vqs, vqs_info, NULL); + err = virtio_find_vqs(dev->vdev, 2, vqs, vqs_info, NULL); if (err) return err; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index ca3446503e82..112a9e629ab5 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -1020,7 +1020,7 @@ static int init_vq(struct virtio_blk *vblk) } /* Discover virtqueues and write information to configuration. */ - err = virtio_find_vqs_info(vdev, num_vqs, vqs, vqs_info, &desc); + err = virtio_find_vqs(vdev, num_vqs, vqs, vqs_info, &desc); if (err) goto out; diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c index 79574855ed54..756f292df9e8 100644 --- a/drivers/bluetooth/virtio_bt.c +++ b/drivers/bluetooth/virtio_bt.c @@ -284,8 +284,7 @@ static int virtbt_probe(struct virtio_device *vdev) INIT_WORK(&vbt->rx, virtbt_rx_work); - err = virtio_find_vqs_info(vdev, VIRTBT_NUM_VQS, vbt->vqs, - vqs_info, NULL); + err = virtio_find_vqs(vdev, VIRTBT_NUM_VQS, vbt->vqs, vqs_info, NULL); if (err) return err; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 903d83a1ffe8..de7d720d99fa 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1849,8 +1849,7 @@ static int init_vqs(struct ports_device *portdev) } } /* Find the queues. */ - err = virtio_find_vqs_info(portdev->vdev, nr_queues, vqs, - vqs_info, NULL); + err = virtio_find_vqs(portdev->vdev, nr_queues, vqs, vqs_info, NULL); if (err) goto free; diff --git a/drivers/crypto/virtio/virtio_crypto_core.c b/drivers/crypto/virtio/virtio_crypto_core.c index b8119d1f9931..d0278eb568b9 100644 --- a/drivers/crypto/virtio/virtio_crypto_core.c +++ b/drivers/crypto/virtio/virtio_crypto_core.c @@ -129,7 +129,7 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi) vqs_info[i].name = vi->data_vq[i].name; } - ret = virtio_find_vqs_info(vi->vdev, total_vqs, vqs, vqs_info, NULL); + ret = virtio_find_vqs(vi->vdev, total_vqs, vqs, vqs_info, NULL); if (ret) goto err_find; diff --git a/drivers/firmware/arm_scmi/virtio.c b/drivers/firmware/arm_scmi/virtio.c index d7cdefb6bd54..dd3459bdb9cb 100644 --- a/drivers/firmware/arm_scmi/virtio.c +++ b/drivers/firmware/arm_scmi/virtio.c @@ -829,7 +829,7 @@ static int scmi_vio_probe(struct virtio_device *vdev) if (have_vq_rx) channels[VIRTIO_SCMI_VQ_RX].is_rx = true; - ret = virtio_find_vqs_info(vdev, vq_cnt, vqs, scmi_vio_vqs_info, NULL); + ret = virtio_find_vqs(vdev, vq_cnt, vqs, scmi_vio_vqs_info, NULL); if (ret) { dev_err(dev, "Failed to get %d virtqueue(s)\n", vq_cnt); return ret; diff --git a/drivers/gpio/gpio-virtio.c b/drivers/gpio/gpio-virtio.c index d11464420797..93544ff62513 100644 --- a/drivers/gpio/gpio-virtio.c +++ b/drivers/gpio/gpio-virtio.c @@ -464,8 +464,8 @@ static int virtio_gpio_alloc_vqs(struct virtio_gpio *vgpio, struct virtqueue *vqs[2] = { NULL, NULL }; int ret; - ret = virtio_find_vqs_info(vdev, vgpio->irq_lines ? 2 : 1, vqs, - vqs_info, NULL); + ret = virtio_find_vqs(vdev, vgpio->irq_lines ? 2 : 1, vqs, + vqs_info, NULL); if (ret) { dev_err(&vdev->dev, "failed to find vqs: %d\n", ret); return ret; diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 1590fc180c66..7dfb2006c561 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -206,7 +206,7 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev) DRM_INFO("features: %ccontext_init\n", vgdev->has_context_init ? '+' : '-'); - ret = virtio_find_vqs_info(vgdev->vdev, 2, vqs, vqs_info, NULL); + ret = virtio_find_vqs(vgdev->vdev, 2, vqs, vqs_info, NULL); if (ret) { DRM_ERROR("failed to find virt queues\n"); goto err_vqs; diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c index d3c7877a3806..b85ce6310ddb 100644 --- a/drivers/iommu/virtio-iommu.c +++ b/drivers/iommu/virtio-iommu.c @@ -1089,8 +1089,8 @@ static int viommu_init_vqs(struct viommu_dev *viommu) { "event", viommu_event_handler }, }; - return virtio_find_vqs_info(vdev, VIOMMU_NR_VQS, viommu->vqs, - vqs_info, NULL); + return virtio_find_vqs(vdev, VIOMMU_NR_VQS, viommu->vqs, + vqs_info, NULL); } static int viommu_fill_evtq(struct viommu_dev *viommu) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 7a0a44216bec..3797427d0a03 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -5339,7 +5339,7 @@ static int virtnet_find_vqs(struct virtnet_info *vi) vqs_info[rxq2vq(i)].ctx = true; } - ret = virtio_find_vqs_info(vi->vdev, total_vqs, vqs, vqs_info, NULL); + ret = virtio_find_vqs(vi->vdev, total_vqs, vqs, vqs_info, NULL); if (ret) goto err_find; diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 7bda786631ba..f2e58d246284 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -6579,8 +6579,8 @@ static int init_vqs(struct virtio_device *vdev) [HWSIM_VQ_RX] = { "rx", hwsim_virtio_rx_done }, }; - return virtio_find_vqs_info(vdev, HWSIM_NUM_VQS, - hwsim_vqs, vqs_info, NULL); + return virtio_find_vqs(vdev, HWSIM_NUM_VQS, + hwsim_vqs, vqs_info, NULL); } static int fill_vq(struct virtqueue *vq) diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index fb466ef20f07..89d7a3b8c48b 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -893,7 +893,7 @@ static int rpmsg_probe(struct virtio_device *vdev) init_waitqueue_head(&vrp->sendq); /* We expect two virtqueues, rx and tx (and in this order) */ - err = virtio_find_vqs_info(vdev, 2, vqs, vqs_info, NULL); + err = virtio_find_vqs(vdev, 2, vqs, vqs_info, NULL); if (err) goto free_vrp; diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index bf9346a66df2..8471f38b730e 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -879,7 +879,7 @@ static int virtscsi_init(struct virtio_device *vdev, vqs_info[i].name = "request_poll"; /* Discover virtqueues and write information to configuration. */ - err = virtio_find_vqs_info(vdev, num_vqs, vqs, vqs_info, &desc); + err = virtio_find_vqs(vdev, num_vqs, vqs, vqs_info, &desc); if (err) goto out; diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index cfa710abf441..54469277ca30 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -587,8 +587,8 @@ static int init_vqs(struct virtio_balloon *vb) vqs_info[VIRTIO_BALLOON_VQ_REPORTING].callback = balloon_ack; } - err = virtio_find_vqs_info(vb->vdev, VIRTIO_BALLOON_VQ_MAX, vqs, - vqs_info, NULL); + err = virtio_find_vqs(vb->vdev, VIRTIO_BALLOON_VQ_MAX, vqs, + vqs_info, NULL); if (err) return err; diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c index 6f803dc3d0f9..a5d63269f20b 100644 --- a/drivers/virtio/virtio_input.c +++ b/drivers/virtio/virtio_input.c @@ -192,7 +192,7 @@ static int virtinput_init_vqs(struct virtio_input *vi) struct virtqueue *vqs[2]; int err; - err = virtio_find_vqs_info(vi->vdev, 2, vqs, vqs_info, NULL); + err = virtio_find_vqs(vi->vdev, 2, vqs, vqs_info, NULL); if (err) return err; vi->evt = vqs[0]; diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index a335b421f196..dd5260141615 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -836,7 +836,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev, vqs_info[i].name = fs->vqs[i].name; } - ret = virtio_find_vqs_info(vdev, fs->nvqs, vqs, vqs_info, &desc); + ret = virtio_find_vqs(vdev, fs->nvqs, vqs, vqs_info, &desc); if (ret < 0) goto out; diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index b6b615c3e21d..ab4b9a3fef6b 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -222,10 +222,10 @@ static inline bool virtio_has_dma_quirk(const struct virtio_device *vdev) } static inline -int virtio_find_vqs_info(struct virtio_device *vdev, unsigned int nvqs, - struct virtqueue *vqs[], - struct virtqueue_info vqs_info[], - struct irq_affinity *desc) +int virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs, + struct virtqueue *vqs[], + struct virtqueue_info vqs_info[], + struct irq_affinity *desc) { return vdev->config->find_vqs(vdev, nvqs, vqs, vqs_info, desc); } @@ -238,7 +238,7 @@ struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, { n, c }, }; struct virtqueue *vq; - int err = virtio_find_vqs_info(vdev, 1, &vq, vqs_info, NULL); + int err = virtio_find_vqs(vdev, 1, &vq, vqs_info, NULL); if (err < 0) return ERR_PTR(err); diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c index 3033680fcc98..64a07acfef12 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -624,8 +624,7 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock) }; int ret; - ret = virtio_find_vqs_info(vdev, VSOCK_VQ_MAX, vsock->vqs, vqs_info, - NULL); + ret = virtio_find_vqs(vdev, VSOCK_VQ_MAX, vsock->vqs, vqs_info, NULL); if (ret < 0) return ret; diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 109a0008b69e..965209e1d872 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -125,7 +125,7 @@ static int virtsnd_find_vqs(struct virtio_snd *snd) unsigned int n; int rc; - rc = virtio_find_vqs_info(vdev, VIRTIO_SND_VQ_MAX, vqs, vqs_info, NULL); + rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, vqs_info, NULL); if (rc) { dev_err(&vdev->dev, "failed to initialize virtqueues\n"); return rc; -- cgit v1.2.3