Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Aug 2022 16:50:34 +0000 (09:50 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Aug 2022 16:50:34 +0000 (09:50 -0700)
Pull virtio updates from Michael Tsirkin:

 - A huge patchset supporting vq resize using the new vq reset
   capability

 - Features, fixes, and cleanups all over the place

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost: (88 commits)
  vdpa/mlx5: Fix possible uninitialized return value
  vdpa_sim_blk: add support for discard and write-zeroes
  vdpa_sim_blk: add support for VIRTIO_BLK_T_FLUSH
  vdpa_sim_blk: make vdpasim_blk_check_range usable by other requests
  vdpa_sim_blk: check if sector is 0 for commands other than read or write
  vdpa_sim: Implement suspend vdpa op
  vhost-vdpa: uAPI to suspend the device
  vhost-vdpa: introduce SUSPEND backend feature bit
  vdpa: Add suspend operation
  virtio-blk: Avoid use-after-free on suspend/resume
  virtio_vdpa: support the arg sizes of find_vqs()
  vhost-vdpa: Call ida_simple_remove() when failed
  vDPA: fix 'cast to restricted le16' warnings in vdpa.c
  vDPA: !FEATURES_OK should not block querying device config space
  vDPA/ifcvf: support userspace to query features and MQ of a management device
  vDPA/ifcvf: get_config_size should return a value no greater than dev implementation
  vhost scsi: Allow user to control num virtqueues
  vhost-scsi: Fix max number of virtqueues
  vdpa/mlx5: Support different address spaces for control and data
  vdpa/mlx5: Implement susupend virtqueue callback
  ...

1  2 
drivers/block/virtio_blk.c
drivers/net/virtio_net.c
drivers/remoteproc/remoteproc_core.c
drivers/s390/virtio/virtio_ccw.c
drivers/vhost/scsi.c
drivers/virtio/Kconfig
drivers/virtio/virtio.c
include/uapi/linux/vhost_types.h

index d7d72e8f6e551297ddd7c0e5aa7e654ec8e7c727,d756423e0059a5499beb368998805a769ab16bf7..30255fcaf18121c5051ba156e821ee0fd33ba4aa
@@@ -101,6 -101,14 +101,14 @@@ static inline blk_status_t virtblk_resu
        }
  }
  
+ static inline struct virtio_blk_vq *get_virtio_blk_vq(struct blk_mq_hw_ctx *hctx)
+ {
+       struct virtio_blk *vblk = hctx->queue->queuedata;
+       struct virtio_blk_vq *vq = &vblk->vqs[hctx->queue_num];
+       return vq;
+ }
  static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
  {
        struct scatterlist hdr, status, *sgs[3];
@@@ -416,7 -424,7 +424,7 @@@ static void virtio_queue_rqs(struct req
        struct request *requeue_list = NULL;
  
        rq_list_for_each_safe(rqlist, req, next) {
-               struct virtio_blk_vq *vq = req->mq_hctx->driver_data;
+               struct virtio_blk_vq *vq = get_virtio_blk_vq(req->mq_hctx);
                bool kick;
  
                if (!virtblk_prep_rq_batch(req)) {
@@@ -837,7 -845,7 +845,7 @@@ static void virtblk_complete_batch(stru
  static int virtblk_poll(struct blk_mq_hw_ctx *hctx, struct io_comp_batch *iob)
  {
        struct virtio_blk *vblk = hctx->queue->queuedata;
-       struct virtio_blk_vq *vq = hctx->driver_data;
+       struct virtio_blk_vq *vq = get_virtio_blk_vq(hctx);
        struct virtblk_req *vbr;
        unsigned long flags;
        unsigned int len;
        return found;
  }
  
- static int virtblk_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
-                         unsigned int hctx_idx)
- {
-       struct virtio_blk *vblk = data;
-       struct virtio_blk_vq *vq = &vblk->vqs[hctx_idx];
-       WARN_ON(vblk->tag_set.tags[hctx_idx] != hctx->tags);
-       hctx->driver_data = vq;
-       return 0;
- }
  static const struct blk_mq_ops virtio_mq_ops = {
        .queue_rq       = virtio_queue_rq,
        .queue_rqs      = virtio_queue_rqs,
        .commit_rqs     = virtio_commit_rqs,
-       .init_hctx      = virtblk_init_hctx,
        .complete       = virtblk_request_done,
        .map_queues     = virtblk_map_queues,
        .poll           = virtblk_poll,
@@@ -1089,7 -1085,7 +1085,7 @@@ static int virtblk_probe(struct virtio_
        return 0;
  
  out_cleanup_disk:
 -      blk_cleanup_disk(vblk->disk);
 +      put_disk(vblk->disk);
  out_free_tags:
        blk_mq_free_tag_set(&vblk->tag_set);
  out_free_vq:
@@@ -1111,6 -1107,7 +1107,6 @@@ static void virtblk_remove(struct virti
        flush_work(&vblk->config_work);
  
        del_gendisk(vblk->disk);
 -      blk_cleanup_queue(vblk->disk->queue);
        blk_mq_free_tag_set(&vblk->tag_set);
  
        mutex_lock(&vblk->vdev_mutex);
diff --combined drivers/net/virtio_net.c
index 3b3eebad39772c9160098f20e32b278dd6e7127b,d9c434b00e9ba17b2c9bdd4ff88dd9836cbafa67..d934774e9733bc1077c05f026127ea143fdc9f8f
@@@ -135,6 -135,9 +135,9 @@@ struct send_queue 
        struct virtnet_sq_stats stats;
  
        struct napi_struct napi;
+       /* Record whether sq is in reset state. */
+       bool reset;
  };
  
  /* Internal representation of a receive virtqueue */
@@@ -267,6 -270,12 +270,12 @@@ struct virtnet_info 
        u8 duplex;
        u32 speed;
  
+       /* Interrupt coalescing settings */
+       u32 tx_usecs;
+       u32 rx_usecs;
+       u32 tx_max_packets;
+       u32 rx_max_packets;
        unsigned long guest_offloads;
        unsigned long guest_offloads_capable;
  
@@@ -284,6 -293,9 +293,9 @@@ struct padded_vnet_hdr 
        char padding[12];
  };
  
+ static void virtnet_rq_free_unused_buf(struct virtqueue *vq, void *buf);
+ static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
  static bool is_xdp_frame(void *ptr)
  {
        return (unsigned long)ptr & VIRTIO_XDP_FLAG;
@@@ -1057,11 -1069,8 +1069,11 @@@ static struct sk_buff *receive_mergeabl
                case XDP_TX:
                        stats->xdp_tx++;
                        xdpf = xdp_convert_buff_to_frame(&xdp);
 -                      if (unlikely(!xdpf))
 +                      if (unlikely(!xdpf)) {
 +                              if (unlikely(xdp_page != page))
 +                                      put_page(xdp_page);
                                goto err_xdp;
 +                      }
                        err = virtnet_xdp_xmit(dev, 1, &xdpf, 0);
                        if (unlikely(!err)) {
                                xdp_return_frame_rx_napi(xdpf);
@@@ -1628,6 -1637,11 +1640,11 @@@ static void virtnet_poll_cleantx(struc
                return;
  
        if (__netif_tx_trylock(txq)) {
+               if (sq->reset) {
+                       __netif_tx_unlock(txq);
+                       return;
+               }
                do {
                        virtqueue_disable_cb(sq->vq);
                        free_old_xmit_skbs(sq, true);
@@@ -1875,6 -1889,70 +1892,70 @@@ static netdev_tx_t start_xmit(struct sk
        return NETDEV_TX_OK;
  }
  
+ static int virtnet_rx_resize(struct virtnet_info *vi,
+                            struct receive_queue *rq, u32 ring_num)
+ {
+       bool running = netif_running(vi->dev);
+       int err, qindex;
+       qindex = rq - vi->rq;
+       if (running)
+               napi_disable(&rq->napi);
+       err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_free_unused_buf);
+       if (err)
+               netdev_err(vi->dev, "resize rx fail: rx queue index: %d err: %d\n", qindex, err);
+       if (!try_fill_recv(vi, rq, GFP_KERNEL))
+               schedule_delayed_work(&vi->refill, 0);
+       if (running)
+               virtnet_napi_enable(rq->vq, &rq->napi);
+       return err;
+ }
+ static int virtnet_tx_resize(struct virtnet_info *vi,
+                            struct send_queue *sq, u32 ring_num)
+ {
+       bool running = netif_running(vi->dev);
+       struct netdev_queue *txq;
+       int err, qindex;
+       qindex = sq - vi->sq;
+       if (running)
+               virtnet_napi_tx_disable(&sq->napi);
+       txq = netdev_get_tx_queue(vi->dev, qindex);
+       /* 1. wait all ximt complete
+        * 2. fix the race of netif_stop_subqueue() vs netif_start_subqueue()
+        */
+       __netif_tx_lock_bh(txq);
+       /* Prevent rx poll from accessing sq. */
+       sq->reset = true;
+       /* Prevent the upper layer from trying to send packets. */
+       netif_stop_subqueue(vi->dev, qindex);
+       __netif_tx_unlock_bh(txq);
+       err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf);
+       if (err)
+               netdev_err(vi->dev, "resize tx fail: tx queue index: %d err: %d\n", qindex, err);
+       __netif_tx_lock_bh(txq);
+       sq->reset = false;
+       netif_tx_wake_queue(txq);
+       __netif_tx_unlock_bh(txq);
+       if (running)
+               virtnet_napi_tx_enable(vi, sq->vq, &sq->napi);
+       return err;
+ }
  /*
   * Send command via the control virtqueue and check status.  Commands
   * supported by the hypervisor, as indicated by feature bits, should
@@@ -2285,10 -2363,57 +2366,57 @@@ static void virtnet_get_ringparam(struc
  {
        struct virtnet_info *vi = netdev_priv(dev);
  
-       ring->rx_max_pending = virtqueue_get_vring_size(vi->rq[0].vq);
-       ring->tx_max_pending = virtqueue_get_vring_size(vi->sq[0].vq);
-       ring->rx_pending = ring->rx_max_pending;
-       ring->tx_pending = ring->tx_max_pending;
+       ring->rx_max_pending = vi->rq[0].vq->num_max;
+       ring->tx_max_pending = vi->sq[0].vq->num_max;
+       ring->rx_pending = virtqueue_get_vring_size(vi->rq[0].vq);
+       ring->tx_pending = virtqueue_get_vring_size(vi->sq[0].vq);
+ }
+ static int virtnet_set_ringparam(struct net_device *dev,
+                                struct ethtool_ringparam *ring,
+                                struct kernel_ethtool_ringparam *kernel_ring,
+                                struct netlink_ext_ack *extack)
+ {
+       struct virtnet_info *vi = netdev_priv(dev);
+       u32 rx_pending, tx_pending;
+       struct receive_queue *rq;
+       struct send_queue *sq;
+       int i, err;
+       if (ring->rx_mini_pending || ring->rx_jumbo_pending)
+               return -EINVAL;
+       rx_pending = virtqueue_get_vring_size(vi->rq[0].vq);
+       tx_pending = virtqueue_get_vring_size(vi->sq[0].vq);
+       if (ring->rx_pending == rx_pending &&
+           ring->tx_pending == tx_pending)
+               return 0;
+       if (ring->rx_pending > vi->rq[0].vq->num_max)
+               return -EINVAL;
+       if (ring->tx_pending > vi->sq[0].vq->num_max)
+               return -EINVAL;
+       for (i = 0; i < vi->max_queue_pairs; i++) {
+               rq = vi->rq + i;
+               sq = vi->sq + i;
+               if (ring->tx_pending != tx_pending) {
+                       err = virtnet_tx_resize(vi, sq, ring->tx_pending);
+                       if (err)
+                               return err;
+               }
+               if (ring->rx_pending != rx_pending) {
+                       err = virtnet_rx_resize(vi, rq, ring->rx_pending);
+                       if (err)
+                               return err;
+               }
+       }
+       return 0;
  }
  
  static bool virtnet_commit_rss_command(struct virtnet_info *vi)
@@@ -2618,27 -2743,89 +2746,89 @@@ static int virtnet_get_link_ksettings(s
        return 0;
  }
  
+ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
+                                      struct ethtool_coalesce *ec)
+ {
+       struct scatterlist sgs_tx, sgs_rx;
+       struct virtio_net_ctrl_coal_tx coal_tx;
+       struct virtio_net_ctrl_coal_rx coal_rx;
+       coal_tx.tx_usecs = cpu_to_le32(ec->tx_coalesce_usecs);
+       coal_tx.tx_max_packets = cpu_to_le32(ec->tx_max_coalesced_frames);
+       sg_init_one(&sgs_tx, &coal_tx, sizeof(coal_tx));
+       if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
+                                 VIRTIO_NET_CTRL_NOTF_COAL_TX_SET,
+                                 &sgs_tx))
+               return -EINVAL;
+       /* Save parameters */
+       vi->tx_usecs = ec->tx_coalesce_usecs;
+       vi->tx_max_packets = ec->tx_max_coalesced_frames;
+       coal_rx.rx_usecs = cpu_to_le32(ec->rx_coalesce_usecs);
+       coal_rx.rx_max_packets = cpu_to_le32(ec->rx_max_coalesced_frames);
+       sg_init_one(&sgs_rx, &coal_rx, sizeof(coal_rx));
+       if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
+                                 VIRTIO_NET_CTRL_NOTF_COAL_RX_SET,
+                                 &sgs_rx))
+               return -EINVAL;
+       /* Save parameters */
+       vi->rx_usecs = ec->rx_coalesce_usecs;
+       vi->rx_max_packets = ec->rx_max_coalesced_frames;
+       return 0;
+ }
+ static int virtnet_coal_params_supported(struct ethtool_coalesce *ec)
+ {
+       /* usecs coalescing is supported only if VIRTIO_NET_F_NOTF_COAL
+        * feature is negotiated.
+        */
+       if (ec->rx_coalesce_usecs || ec->tx_coalesce_usecs)
+               return -EOPNOTSUPP;
+       if (ec->tx_max_coalesced_frames > 1 ||
+           ec->rx_max_coalesced_frames != 1)
+               return -EINVAL;
+       return 0;
+ }
  static int virtnet_set_coalesce(struct net_device *dev,
                                struct ethtool_coalesce *ec,
                                struct kernel_ethtool_coalesce *kernel_coal,
                                struct netlink_ext_ack *extack)
  {
        struct virtnet_info *vi = netdev_priv(dev);
-       int i, napi_weight;
-       if (ec->tx_max_coalesced_frames > 1 ||
-           ec->rx_max_coalesced_frames != 1)
-               return -EINVAL;
+       int ret, i, napi_weight;
+       bool update_napi = false;
  
+       /* Can't change NAPI weight if the link is up */
        napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0;
        if (napi_weight ^ vi->sq[0].napi.weight) {
                if (dev->flags & IFF_UP)
                        return -EBUSY;
+               else
+                       update_napi = true;
+       }
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL))
+               ret = virtnet_send_notf_coal_cmds(vi, ec);
+       else
+               ret = virtnet_coal_params_supported(ec);
+       if (ret)
+               return ret;
+       if (update_napi) {
                for (i = 0; i < vi->max_queue_pairs; i++)
                        vi->sq[i].napi.weight = napi_weight;
        }
  
-       return 0;
+       return ret;
  }
  
  static int virtnet_get_coalesce(struct net_device *dev,
                                struct kernel_ethtool_coalesce *kernel_coal,
                                struct netlink_ext_ack *extack)
  {
-       struct ethtool_coalesce ec_default = {
-               .cmd = ETHTOOL_GCOALESCE,
-               .rx_max_coalesced_frames = 1,
-       };
        struct virtnet_info *vi = netdev_priv(dev);
  
-       memcpy(ec, &ec_default, sizeof(ec_default));
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL)) {
+               ec->rx_coalesce_usecs = vi->rx_usecs;
+               ec->tx_coalesce_usecs = vi->tx_usecs;
+               ec->tx_max_coalesced_frames = vi->tx_max_packets;
+               ec->rx_max_coalesced_frames = vi->rx_max_packets;
+       } else {
+               ec->rx_max_coalesced_frames = 1;
  
-       if (vi->sq[0].napi.weight)
-               ec->tx_max_coalesced_frames = 1;
+               if (vi->sq[0].napi.weight)
+                       ec->tx_max_coalesced_frames = 1;
+       }
  
        return 0;
  }
@@@ -2774,10 -2964,12 +2967,12 @@@ static int virtnet_set_rxnfc(struct net
  }
  
  static const struct ethtool_ops virtnet_ethtool_ops = {
-       .supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
+       .supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES |
+               ETHTOOL_COALESCE_USECS,
        .get_drvinfo = virtnet_get_drvinfo,
        .get_link = ethtool_op_get_link,
        .get_ringparam = virtnet_get_ringparam,
+       .set_ringparam = virtnet_set_ringparam,
        .get_strings = virtnet_get_strings,
        .get_sset_count = virtnet_get_sset_count,
        .get_ethtool_stats = virtnet_get_ethtool_stats,
@@@ -3171,6 -3363,27 +3366,27 @@@ static void free_receive_page_frags(str
                        put_page(vi->rq[i].alloc_frag.page);
  }
  
+ static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf)
+ {
+       if (!is_xdp_frame(buf))
+               dev_kfree_skb(buf);
+       else
+               xdp_return_frame(ptr_to_xdp(buf));
+ }
+ static void virtnet_rq_free_unused_buf(struct virtqueue *vq, void *buf)
+ {
+       struct virtnet_info *vi = vq->vdev->priv;
+       int i = vq2rxq(vq);
+       if (vi->mergeable_rx_bufs)
+               put_page(virt_to_head_page(buf));
+       else if (vi->big_packets)
+               give_pages(&vi->rq[i], buf);
+       else
+               put_page(virt_to_head_page(buf));
+ }
  static void free_unused_bufs(struct virtnet_info *vi)
  {
        void *buf;
  
        for (i = 0; i < vi->max_queue_pairs; i++) {
                struct virtqueue *vq = vi->sq[i].vq;
-               while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
-                       if (!is_xdp_frame(buf))
-                               dev_kfree_skb(buf);
-                       else
-                               xdp_return_frame(ptr_to_xdp(buf));
-               }
+               while ((buf = virtqueue_detach_unused_buf(vq)) != NULL)
+                       virtnet_sq_free_unused_buf(vq, buf);
        }
  
        for (i = 0; i < vi->max_queue_pairs; i++) {
                struct virtqueue *vq = vi->rq[i].vq;
-               while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
-                       if (vi->mergeable_rx_bufs) {
-                               put_page(virt_to_head_page(buf));
-                       } else if (vi->big_packets) {
-                               give_pages(&vi->rq[i], buf);
-                       } else {
-                               put_page(virt_to_head_page(buf));
-                       }
-               }
+               while ((buf = virtqueue_detach_unused_buf(vq)) != NULL)
+                       virtnet_rq_free_unused_buf(vq, buf);
        }
  }
  
@@@ -3228,6 -3429,29 +3432,29 @@@ static unsigned int mergeable_min_buf_l
                   (unsigned int)GOOD_PACKET_LEN);
  }
  
+ static void virtnet_config_sizes(struct virtnet_info *vi, u32 *sizes)
+ {
+       u32 i, rx_size, tx_size;
+       if (vi->speed == SPEED_UNKNOWN || vi->speed < SPEED_10000) {
+               rx_size = 1024;
+               tx_size = 1024;
+       } else if (vi->speed < SPEED_40000) {
+               rx_size = 1024 * 4;
+               tx_size = 1024 * 4;
+       } else {
+               rx_size = 1024 * 8;
+               tx_size = 1024 * 8;
+       }
+       for (i = 0; i < vi->max_queue_pairs; i++) {
+               sizes[rxq2vq(i)] = rx_size;
+               sizes[txq2vq(i)] = tx_size;
+       }
+ }
  static int virtnet_find_vqs(struct virtnet_info *vi)
  {
        vq_callback_t **callbacks;
        int ret = -ENOMEM;
        int i, total_vqs;
        const char **names;
+       u32 *sizes;
        bool *ctx;
  
        /* We expect 1 RX virtqueue followed by 1 TX virtqueue, followed by
                ctx = NULL;
        }
  
+       sizes = kmalloc_array(total_vqs, sizeof(*sizes), GFP_KERNEL);
+       if (!sizes)
+               goto err_sizes;
        /* Parameters for control virtqueue, if any */
        if (vi->has_cvq) {
                callbacks[total_vqs - 1] = NULL;
                names[total_vqs - 1] = "control";
+               sizes[total_vqs - 1] = 64;
        }
  
        /* Allocate/initialize parameters for send/receive virtqueues */
                        ctx[rxq2vq(i)] = true;
        }
  
-       ret = virtio_find_vqs_ctx(vi->vdev, total_vqs, vqs, callbacks,
-                                 names, ctx, NULL);
+       virtnet_config_sizes(vi, sizes);
+       ret = virtio_find_vqs_ctx_size(vi->vdev, total_vqs, vqs, callbacks,
+                                      names, sizes, ctx, NULL);
        if (ret)
                goto err_find;
  
  
  
  err_find:
+       kfree(sizes);
+ err_sizes:
        kfree(ctx);
  err_ctx:
        kfree(names);
@@@ -3444,6 -3678,8 +3681,8 @@@ static bool virtnet_validate_features(s
             VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS,
                             "VIRTIO_NET_F_CTRL_VQ") ||
             VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
+                            "VIRTIO_NET_F_CTRL_VQ") ||
+            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_NOTF_COAL,
                             "VIRTIO_NET_F_CTRL_VQ"))) {
                return false;
        }
@@@ -3580,6 -3816,13 +3819,13 @@@ static int virtnet_probe(struct virtio_
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
                vi->mergeable_rx_bufs = true;
  
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL)) {
+               vi->rx_usecs = 0;
+               vi->tx_usecs = 0;
+               vi->tx_max_packets = 0;
+               vi->rx_max_packets = 0;
+       }
        if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT))
                vi->has_rss_hash_report = true;
  
                vi->curr_queue_pairs = num_online_cpus();
        vi->max_queue_pairs = max_queue_pairs;
  
+       virtnet_init_settings(dev);
+       virtnet_update_settings(vi);
        /* Allocate/initialize the rx/tx queues, and invoke find_vqs */
        err = init_vqs(vi);
        if (err)
        netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
        netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-       virtnet_init_settings(dev);
        if (virtio_has_feature(vdev, VIRTIO_NET_F_STANDBY)) {
                vi->failover = net_failover_create(vi->dev);
                if (IS_ERR(vi->failover)) {
@@@ -3814,7 -4058,7 +4061,7 @@@ static struct virtio_device_id id_table
        VIRTIO_NET_F_CTRL_MAC_ADDR, \
        VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
        VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY, \
-       VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT
+       VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT, VIRTIO_NET_F_NOTF_COAL
  
  static unsigned int features[] = {
        VIRTNET_FEATURES,
index 89832399e0280636dd334008552cd21972d4ceed,2d2f3bab588852c37a19a895578146db88fa6511..e5279ed9a8d7c7ace6f396795833a0379762177a
@@@ -59,7 -59,6 +59,7 @@@ static int rproc_release_carveout(struc
  
  /* Unique indices for remoteproc devices */
  static DEFINE_IDA(rproc_dev_index);
 +static struct workqueue_struct *rproc_recovery_wq;
  
  static const char * const rproc_crash_names[] = {
        [RPROC_MMUFAULT]        = "mmufault",
@@@ -335,7 -334,7 +335,7 @@@ int rproc_alloc_vring(struct rproc_vde
        size_t size;
  
        /* actual size of vring (in bytes) */
-       size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
+       size = PAGE_ALIGN(vring_size(rvring->num, rvring->align));
  
        rsc = (void *)rproc->table_ptr + rvdev->rsc_offset;
  
@@@ -402,7 -401,7 +402,7 @@@ rproc_parse_vring(struct rproc_vdev *rv
                return -EINVAL;
        }
  
-       rvring->len = vring->num;
+       rvring->num = vring->num;
        rvring->align = vring->align;
        rvring->rvdev = rvdev;
  
@@@ -462,7 -461,6 +462,7 @@@ static void rproc_rvdev_release(struct 
        struct rproc_vdev *rvdev = container_of(dev, struct rproc_vdev, dev);
  
        of_reserved_mem_device_release(dev);
 +      dma_release_coherent_memory(dev);
  
        kfree(rvdev);
  }
@@@ -972,7 -970,7 +972,7 @@@ static int rproc_handle_carveout(struc
                return 0;
        }
  
 -      /* Register carveout in in list */
 +      /* Register carveout in list */
        carveout = rproc_mem_entry_init(dev, NULL, 0, rsc->len, rsc->da,
                                        rproc_alloc_carveout,
                                        rproc_release_carveout, rsc->name);
@@@ -2436,7 -2434,7 +2436,7 @@@ static void rproc_type_release(struct d
        idr_destroy(&rproc->notifyids);
  
        if (rproc->index >= 0)
 -              ida_simple_remove(&rproc_dev_index, rproc->index);
 +              ida_free(&rproc_dev_index, rproc->index);
  
        kfree_const(rproc->firmware);
        kfree_const(rproc->name);
@@@ -2553,9 -2551,9 +2553,9 @@@ struct rproc *rproc_alloc(struct devic
                goto put_device;
  
        /* Assign a unique device index and name */
 -      rproc->index = ida_simple_get(&rproc_dev_index, 0, 0, GFP_KERNEL);
 +      rproc->index = ida_alloc(&rproc_dev_index, GFP_KERNEL);
        if (rproc->index < 0) {
 -              dev_err(dev, "ida_simple_get failed: %d\n", rproc->index);
 +              dev_err(dev, "ida_alloc failed: %d\n", rproc->index);
                goto put_device;
        }
  
@@@ -2764,7 -2762,8 +2764,7 @@@ void rproc_report_crash(struct rproc *r
        dev_err(&rproc->dev, "crash detected in %s: type %s\n",
                rproc->name, rproc_crash_to_string(type));
  
 -      /* Have a worker handle the error; ensure system is not suspended */
 -      queue_work(system_freezable_wq, &rproc->crash_handler);
 +      queue_work(rproc_recovery_wq, &rproc->crash_handler);
  }
  EXPORT_SYMBOL(rproc_report_crash);
  
@@@ -2813,13 -2812,6 +2813,13 @@@ static void __exit rproc_exit_panic(voi
  
  static int __init remoteproc_init(void)
  {
 +      rproc_recovery_wq = alloc_workqueue("rproc_recovery_wq",
 +                                              WQ_UNBOUND | WQ_FREEZABLE, 0);
 +      if (!rproc_recovery_wq) {
 +              pr_err("remoteproc: creation of rproc_recovery_wq failed\n");
 +              return -ENOMEM;
 +      }
 +
        rproc_init_sysfs();
        rproc_init_debugfs();
        rproc_init_cdev();
@@@ -2833,13 -2825,9 +2833,13 @@@ static void __exit remoteproc_exit(void
  {
        ida_destroy(&rproc_dev_index);
  
 +      if (!rproc_recovery_wq)
 +              return;
 +
        rproc_exit_panic();
        rproc_exit_debugfs();
        rproc_exit_sysfs();
 +      destroy_workqueue(rproc_recovery_wq);
  }
  module_exit(remoteproc_exit);
  
index aa96f67dd0b1635b4181e88c302e9375e933beb6,72500cd2dbf51702f971059a7fa6a56f89409633..896896e326645ef615cdba25bf399eeb3d75dced
@@@ -33,7 -33,6 +33,7 @@@
  #include <asm/virtio-ccw.h>
  #include <asm/isc.h>
  #include <asm/airq.h>
 +#include <asm/tpi.h>
  
  /*
   * virtio related functions
@@@ -205,8 -204,7 +205,8 @@@ static void drop_airq_indicator(struct 
        write_unlock_irqrestore(&info->lock, flags);
  }
  
 -static void virtio_airq_handler(struct airq_struct *airq, bool floating)
 +static void virtio_airq_handler(struct airq_struct *airq,
 +                              struct tpi_info *tpi_info)
  {
        struct airq_info *info = container_of(airq, struct airq_info, airq);
        unsigned long ai;
@@@ -242,7 -240,7 +242,7 @@@ static struct airq_info *new_airq_info(
                return NULL;
        rwlock_init(&info->lock);
        info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR
 -                                 | AIRQ_IV_CACHELINE);
 +                                 | AIRQ_IV_CACHELINE, NULL);
        if (!info->aiv) {
                kfree(info);
                return NULL;
@@@ -532,6 -530,9 +532,9 @@@ static struct virtqueue *virtio_ccw_set
                err = -ENOMEM;
                goto out_err;
        }
+       vq->num_max = info->num;
        /* it may have been reduced */
        info->num = virtqueue_get_vring_size(vq);
  
@@@ -634,6 -635,7 +637,7 @@@ static int virtio_ccw_find_vqs(struct v
                               struct virtqueue *vqs[],
                               vq_callback_t *callbacks[],
                               const char * const names[],
+                              u32 sizes[],
                               const bool *ctx,
                               struct irq_affinity *desc)
  {
diff --combined drivers/vhost/scsi.c
index 9b65509424dc6baf31ebe89bceb7d9ffaf96f5d1,d9861ab2c300dc9730acb550ebb93753d388f678..7ebf106d50c15ecaffcecdd8ca5d58e6e0d08fa1
@@@ -159,9 -159,13 +159,13 @@@ enum 
  };
  
  #define VHOST_SCSI_MAX_TARGET 256
- #define VHOST_SCSI_MAX_VQ     128
+ #define VHOST_SCSI_MAX_IO_VQ  1024
  #define VHOST_SCSI_MAX_EVENT  128
  
+ static unsigned vhost_scsi_max_io_vqs = 128;
+ module_param_named(max_io_vqs, vhost_scsi_max_io_vqs, uint, 0644);
+ MODULE_PARM_DESC(max_io_vqs, "Set the max number of IO virtqueues a vhost scsi device can support. The default is 128. The max is 1024.");
  struct vhost_scsi_virtqueue {
        struct vhost_virtqueue vq;
        /*
@@@ -186,7 -190,9 +190,9 @@@ struct vhost_scsi 
        char vs_vhost_wwpn[TRANSPORT_IQN_LEN];
  
        struct vhost_dev dev;
-       struct vhost_scsi_virtqueue vqs[VHOST_SCSI_MAX_VQ];
+       struct vhost_scsi_virtqueue *vqs;
+       unsigned long *compl_bitmap;
+       struct vhost_scsi_inflight **old_inflight;
  
        struct vhost_work vs_completion_work; /* cmd completion work item */
        struct llist_head vs_completion_list; /* cmd completion queue */
@@@ -245,7 -251,7 +251,7 @@@ static void vhost_scsi_init_inflight(st
        struct vhost_virtqueue *vq;
        int idx, i;
  
-       for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
+       for (i = 0; i < vs->dev.nvqs;  i++) {
                vq = &vs->vqs[i].vq;
  
                mutex_lock(&vq->mutex);
@@@ -533,7 -539,6 +539,6 @@@ static void vhost_scsi_complete_cmd_wor
  {
        struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
                                        vs_completion_work);
-       DECLARE_BITMAP(signal, VHOST_SCSI_MAX_VQ);
        struct virtio_scsi_cmd_resp v_rsp;
        struct vhost_scsi_cmd *cmd, *t;
        struct llist_node *llnode;
        struct iov_iter iov_iter;
        int ret, vq;
  
-       bitmap_zero(signal, VHOST_SCSI_MAX_VQ);
+       bitmap_zero(vs->compl_bitmap, vs->dev.nvqs);
        llnode = llist_del_all(&vs->vs_completion_list);
        llist_for_each_entry_safe(cmd, t, llnode, tvc_completion_list) {
                se_cmd = &cmd->tvc_se_cmd;
                        vhost_add_used(cmd->tvc_vq, cmd->tvc_vq_desc, 0);
                        q = container_of(cmd->tvc_vq, struct vhost_scsi_virtqueue, vq);
                        vq = q - vs->vqs;
-                       __set_bit(vq, signal);
+                       __set_bit(vq, vs->compl_bitmap);
                } else
                        pr_err("Faulted on virtio_scsi_cmd_resp\n");
  
        }
  
        vq = -1;
-       while ((vq = find_next_bit(signal, VHOST_SCSI_MAX_VQ, vq + 1))
-               < VHOST_SCSI_MAX_VQ)
+       while ((vq = find_next_bit(vs->compl_bitmap, vs->dev.nvqs, vq + 1))
+               < vs->dev.nvqs)
                vhost_signal(&vs->dev, &vs->vqs[vq].vq);
  }
  
@@@ -643,12 -648,14 +648,12 @@@ vhost_scsi_map_to_sgl(struct vhost_scsi
        size_t offset;
        unsigned int npages = 0;
  
 -      bytes = iov_iter_get_pages(iter, pages, LONG_MAX,
 +      bytes = iov_iter_get_pages2(iter, pages, LONG_MAX,
                                VHOST_SCSI_PREALLOC_UPAGES, &offset);
        /* No pages were pinned */
        if (bytes <= 0)
                return bytes < 0 ? bytes : -EFAULT;
  
 -      iov_iter_advance(iter, bytes);
 -
        while (bytes) {
                unsigned n = min_t(unsigned, PAGE_SIZE - offset, bytes);
                sg_set_page(sg++, pages[npages++], n, offset);
@@@ -1419,26 -1426,25 +1424,25 @@@ static void vhost_scsi_handle_kick(stru
  /* Callers must hold dev mutex */
  static void vhost_scsi_flush(struct vhost_scsi *vs)
  {
-       struct vhost_scsi_inflight *old_inflight[VHOST_SCSI_MAX_VQ];
        int i;
  
        /* Init new inflight and remember the old inflight */
-       vhost_scsi_init_inflight(vs, old_inflight);
+       vhost_scsi_init_inflight(vs, vs->old_inflight);
  
        /*
         * The inflight->kref was initialized to 1. We decrement it here to
         * indicate the start of the flush operation so that it will reach 0
         * when all the reqs are finished.
         */
-       for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
-               kref_put(&old_inflight[i]->kref, vhost_scsi_done_inflight);
+       for (i = 0; i < vs->dev.nvqs; i++)
+               kref_put(&vs->old_inflight[i]->kref, vhost_scsi_done_inflight);
  
        /* Flush both the vhost poll and vhost work */
        vhost_dev_flush(&vs->dev);
  
        /* Wait for all reqs issued before the flush to be finished */
-       for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
-               wait_for_completion(&old_inflight[i]->comp);
+       for (i = 0; i < vs->dev.nvqs; i++)
+               wait_for_completion(&vs->old_inflight[i]->comp);
  }
  
  static void vhost_scsi_destroy_vq_cmds(struct vhost_virtqueue *vq)
@@@ -1601,7 -1607,7 +1605,7 @@@ vhost_scsi_set_endpoint(struct vhost_sc
                memcpy(vs->vs_vhost_wwpn, t->vhost_wwpn,
                       sizeof(vs->vs_vhost_wwpn));
  
-               for (i = VHOST_SCSI_VQ_IO; i < VHOST_SCSI_MAX_VQ; i++) {
+               for (i = VHOST_SCSI_VQ_IO; i < vs->dev.nvqs; i++) {
                        vq = &vs->vqs[i].vq;
                        if (!vhost_vq_is_setup(vq))
                                continue;
                                goto destroy_vq_cmds;
                }
  
-               for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
+               for (i = 0; i < vs->dev.nvqs; i++) {
                        vq = &vs->vqs[i].vq;
                        mutex_lock(&vq->mutex);
                        vhost_vq_set_backend(vq, vs_tpg);
@@@ -1713,7 -1719,7 +1717,7 @@@ vhost_scsi_clear_endpoint(struct vhost_
                target_undepend_item(&se_tpg->tpg_group.cg_item);
        }
        if (match) {
-               for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
+               for (i = 0; i < vs->dev.nvqs; i++) {
                        vq = &vs->vqs[i].vq;
                        mutex_lock(&vq->mutex);
                        vhost_vq_set_backend(vq, NULL);
                /* Make sure cmds are not running before tearing them down. */
                vhost_scsi_flush(vs);
  
-               for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
+               for (i = 0; i < vs->dev.nvqs; i++) {
                        vq = &vs->vqs[i].vq;
                        vhost_scsi_destroy_vq_cmds(vq);
                }
@@@ -1762,7 -1768,7 +1766,7 @@@ static int vhost_scsi_set_features(stru
                return -EFAULT;
        }
  
-       for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
+       for (i = 0; i < vs->dev.nvqs; i++) {
                vq = &vs->vqs[i].vq;
                mutex_lock(&vq->mutex);
                vq->acked_features = features;
@@@ -1776,16 -1782,40 +1780,40 @@@ static int vhost_scsi_open(struct inod
  {
        struct vhost_scsi *vs;
        struct vhost_virtqueue **vqs;
-       int r = -ENOMEM, i;
+       int r = -ENOMEM, i, nvqs = vhost_scsi_max_io_vqs;
  
        vs = kvzalloc(sizeof(*vs), GFP_KERNEL);
        if (!vs)
                goto err_vs;
  
-       vqs = kmalloc_array(VHOST_SCSI_MAX_VQ, sizeof(*vqs), GFP_KERNEL);
-       if (!vqs)
+       if (nvqs > VHOST_SCSI_MAX_IO_VQ) {
+               pr_err("Invalid max_io_vqs of %d. Using %d.\n", nvqs,
+                      VHOST_SCSI_MAX_IO_VQ);
+               nvqs = VHOST_SCSI_MAX_IO_VQ;
+       } else if (nvqs == 0) {
+               pr_err("Invalid max_io_vqs of %d. Using 1.\n", nvqs);
+               nvqs = 1;
+       }
+       nvqs += VHOST_SCSI_VQ_IO;
+       vs->compl_bitmap = bitmap_alloc(nvqs, GFP_KERNEL);
+       if (!vs->compl_bitmap)
+               goto err_compl_bitmap;
+       vs->old_inflight = kmalloc_array(nvqs, sizeof(*vs->old_inflight),
+                                        GFP_KERNEL | __GFP_ZERO);
+       if (!vs->old_inflight)
+               goto err_inflight;
+       vs->vqs = kmalloc_array(nvqs, sizeof(*vs->vqs),
+                               GFP_KERNEL | __GFP_ZERO);
+       if (!vs->vqs)
                goto err_vqs;
  
+       vqs = kmalloc_array(nvqs, sizeof(*vqs), GFP_KERNEL);
+       if (!vqs)
+               goto err_local_vqs;
        vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work);
        vhost_work_init(&vs->vs_event_work, vhost_scsi_evt_work);
  
        vqs[VHOST_SCSI_VQ_EVT] = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
        vs->vqs[VHOST_SCSI_VQ_CTL].vq.handle_kick = vhost_scsi_ctl_handle_kick;
        vs->vqs[VHOST_SCSI_VQ_EVT].vq.handle_kick = vhost_scsi_evt_handle_kick;
-       for (i = VHOST_SCSI_VQ_IO; i < VHOST_SCSI_MAX_VQ; i++) {
+       for (i = VHOST_SCSI_VQ_IO; i < nvqs; i++) {
                vqs[i] = &vs->vqs[i].vq;
                vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
        }
-       vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ, UIO_MAXIOV,
+       vhost_dev_init(&vs->dev, vqs, nvqs, UIO_MAXIOV,
                       VHOST_SCSI_WEIGHT, 0, true, NULL);
  
        vhost_scsi_init_inflight(vs, NULL);
        f->private_data = vs;
        return 0;
  
+ err_local_vqs:
+       kfree(vs->vqs);
  err_vqs:
+       kfree(vs->old_inflight);
+ err_inflight:
+       bitmap_free(vs->compl_bitmap);
+ err_compl_bitmap:
        kvfree(vs);
  err_vs:
        return r;
@@@ -1826,6 -1862,9 +1860,9 @@@ static int vhost_scsi_release(struct in
        vhost_dev_stop(&vs->dev);
        vhost_dev_cleanup(&vs->dev);
        kfree(vs->dev.vqs);
+       kfree(vs->vqs);
+       kfree(vs->old_inflight);
+       bitmap_free(vs->compl_bitmap);
        kvfree(vs);
        return 0;
  }
diff --combined drivers/virtio/Kconfig
index 56c77f63cd224f7b97b37eaaa7efba3b66aa5b97,02bbccd602c008136e7dd9f06ecb85b7a253dbcc..0a53a61231c2944092d3ecac74d5caf40aaca2d3
@@@ -1,10 -1,6 +1,10 @@@
  # SPDX-License-Identifier: GPL-2.0-only
 +config VIRTIO_ANCHOR
 +      bool
 +
  config VIRTIO
        tristate
 +      select VIRTIO_ANCHOR
        help
          This option is selected by any driver which implements the virtio
          bus, such as CONFIG_VIRTIO_PCI, CONFIG_VIRTIO_MMIO, CONFIG_RPMSG
@@@ -35,11 -31,12 +35,12 @@@ if VIRTIO_MEN
  
  config VIRTIO_HARDEN_NOTIFICATION
          bool "Harden virtio notification"
+         depends on BROKEN
          help
            Enable this to harden the device notifications and suppress
            those that happen at a time where notifications are illegal.
  
-           Experimental: Note that several drivers still have bugs that
+           Experimental: Note that several drivers still have issues that
            may cause crashes or hangs when correct handling of
            notifications is enforced; depending on the subset of
            drivers and devices you use, this may or may not work.
@@@ -126,9 -123,11 +127,11 @@@ config VIRTIO_ME
         This driver provides access to virtio-mem paravirtualized memory
         devices, allowing to hotplug and hotunplug memory.
  
-        This driver was only tested under x86-64 and arm64, but should
-        theoretically work on all architectures that support memory hotplug
-        and hotremove.
+        This driver currently only supports x86-64 and arm64. Although it
+        should compile on other architectures that implement memory
+        hot(un)plug, architecture-specific and/or common
+        code changes may be required for virtio-mem, kdump and kexec to work as
+        expected.
  
         If unsure, say M.
  
diff --combined drivers/virtio/virtio.c
index 14c142d77fba1b6d73b85251580bed803622f6f0,ddd4466da83bb1835bbe9015d6377a662399e654..828ced060742358069ae33e46dd62899d5400760
@@@ -2,10 -2,10 +2,10 @@@
  #include <linux/virtio.h>
  #include <linux/spinlock.h>
  #include <linux/virtio_config.h>
 +#include <linux/virtio_anchor.h>
  #include <linux/module.h>
  #include <linux/idr.h>
  #include <linux/of.h>
 -#include <linux/platform-feature.h>
  #include <uapi/linux/virtio_ids.h>
  
  /* Unique numbering for virtio devices. */
@@@ -174,7 -174,7 +174,7 @@@ static int virtio_features_ok(struct vi
  
        might_sleep();
  
 -      if (platform_has(PLATFORM_VIRTIO_RESTRICTED_MEM_ACCESS)) {
 +      if (virtio_check_mem_acc_cb(dev)) {
                if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) {
                        dev_warn(&dev->dev,
                                 "device must provide VIRTIO_F_VERSION_1\n");
@@@ -428,7 -428,9 +428,9 @@@ int register_virtio_device(struct virti
                goto out;
  
        dev->index = err;
-       dev_set_name(&dev->dev, "virtio%u", dev->index);
+       err = dev_set_name(&dev->dev, "virtio%u", dev->index);
+       if (err)
+               goto out_ida_remove;
  
        err = virtio_device_of_init(dev);
        if (err)
index 391331a10879a93395a37a5cd0a4fac6d9aa6843,1bdd6e363f4c9f1557608bf2218363e7024b1489..53601ce2c20a42b1fac94d712b39c75cca071ec6
@@@ -107,7 -107,7 +107,7 @@@ struct vhost_memory_region 
  struct vhost_memory {
        __u32 nregions;
        __u32 padding;
 -      struct vhost_memory_region regions[0];
 +      struct vhost_memory_region regions[];
  };
  
  /* VHOST_SCSI specific definitions */
@@@ -135,7 -135,7 +135,7 @@@ struct vhost_scsi_target 
  struct vhost_vdpa_config {
        __u32 off;
        __u32 len;
 -      __u8 buf[0];
 +      __u8 buf[];
  };
  
  /* vhost vdpa IOVA range
@@@ -161,5 -161,7 +161,7 @@@ struct vhost_vdpa_iova_range 
   * message
   */
  #define VHOST_BACKEND_F_IOTLB_ASID  0x3
+ /* Device can be suspended */
+ #define VHOST_BACKEND_F_SUSPEND  0x4
  
  #endif