Commit 8aeab132 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost

Pull virtio updates from Michael Tsirkin:

 - 9k mtu perf improvements

 - vdpa feature provisioning

 - virtio blk SECURE ERASE support

 - fixes and cleanups all over the place

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost:
  virtio_pci: don't try to use intxif pin is zero
  vDPA: conditionally read MTU and MAC in dev cfg space
  vDPA: fix spars cast warning in vdpa_dev_net_mq_config_fill
  vDPA: check virtio device features to detect MQ
  vDPA: check VIRTIO_NET_F_RSS for max_virtqueue_paris's presence
  vDPA: only report driver features if FEATURES_OK is set
  vDPA: allow userspace to query features of a vDPA device
  virtio_blk: add SECURE ERASE command support
  vp_vdpa: support feature provisioning
  vdpa_sim_net: support feature provisioning
  vdpa: device feature provisioning
  virtio-net: use mtu size as buffer length for big packets
  virtio-net: introduce and use helper function for guest gso support checks
  virtio: drop vp_legacy_set_queue_size
  virtio_ring: make vring_alloc_queue_packed prettier
  virtio_ring: split: Operators use unified style
  vhost: add __init/__exit annotations to module init/exit funcs
parents 0e0073eb 71491c54
...@@ -130,7 +130,7 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr) ...@@ -130,7 +130,7 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
} }
static int virtblk_setup_discard_write_zeroes(struct request *req, bool unmap) static int virtblk_setup_discard_write_zeroes_erase(struct request *req, bool unmap)
{ {
unsigned short segments = blk_rq_nr_discard_segments(req); unsigned short segments = blk_rq_nr_discard_segments(req);
unsigned short n = 0; unsigned short n = 0;
...@@ -240,6 +240,9 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, ...@@ -240,6 +240,9 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
type = VIRTIO_BLK_T_WRITE_ZEROES; type = VIRTIO_BLK_T_WRITE_ZEROES;
unmap = !(req->cmd_flags & REQ_NOUNMAP); unmap = !(req->cmd_flags & REQ_NOUNMAP);
break; break;
case REQ_OP_SECURE_ERASE:
type = VIRTIO_BLK_T_SECURE_ERASE;
break;
case REQ_OP_DRV_IN: case REQ_OP_DRV_IN:
type = VIRTIO_BLK_T_GET_ID; type = VIRTIO_BLK_T_GET_ID;
break; break;
...@@ -251,8 +254,9 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, ...@@ -251,8 +254,9 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
vbr->out_hdr.type = cpu_to_virtio32(vdev, type); vbr->out_hdr.type = cpu_to_virtio32(vdev, type);
vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req)); vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) { if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES ||
if (virtblk_setup_discard_write_zeroes(req, unmap)) type == VIRTIO_BLK_T_SECURE_ERASE) {
if (virtblk_setup_discard_write_zeroes_erase(req, unmap))
return BLK_STS_RESOURCE; return BLK_STS_RESOURCE;
} }
...@@ -886,6 +890,8 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -886,6 +890,8 @@ static int virtblk_probe(struct virtio_device *vdev)
int err, index; int err, index;
u32 v, blk_size, max_size, sg_elems, opt_io_size; u32 v, blk_size, max_size, sg_elems, opt_io_size;
u32 max_discard_segs = 0;
u32 discard_granularity = 0;
u16 min_io_size; u16 min_io_size;
u8 physical_block_exp, alignment_offset; u8 physical_block_exp, alignment_offset;
unsigned int queue_depth; unsigned int queue_depth;
...@@ -1043,27 +1049,14 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -1043,27 +1049,14 @@ static int virtblk_probe(struct virtio_device *vdev)
if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) { if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
virtio_cread(vdev, struct virtio_blk_config, virtio_cread(vdev, struct virtio_blk_config,
discard_sector_alignment, &v); discard_sector_alignment, &discard_granularity);
if (v)
q->limits.discard_granularity = v << SECTOR_SHIFT;
else
q->limits.discard_granularity = blk_size;
virtio_cread(vdev, struct virtio_blk_config, virtio_cread(vdev, struct virtio_blk_config,
max_discard_sectors, &v); max_discard_sectors, &v);
blk_queue_max_discard_sectors(q, v ? v : UINT_MAX); blk_queue_max_discard_sectors(q, v ? v : UINT_MAX);
virtio_cread(vdev, struct virtio_blk_config, max_discard_seg, virtio_cread(vdev, struct virtio_blk_config, max_discard_seg,
&v); &max_discard_segs);
/*
* max_discard_seg == 0 is out of spec but we always
* handled it.
*/
if (!v)
v = sg_elems;
blk_queue_max_discard_segments(q,
min(v, MAX_DISCARD_SEGMENTS));
} }
if (virtio_has_feature(vdev, VIRTIO_BLK_F_WRITE_ZEROES)) { if (virtio_has_feature(vdev, VIRTIO_BLK_F_WRITE_ZEROES)) {
...@@ -1072,6 +1065,85 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -1072,6 +1065,85 @@ static int virtblk_probe(struct virtio_device *vdev)
blk_queue_max_write_zeroes_sectors(q, v ? v : UINT_MAX); blk_queue_max_write_zeroes_sectors(q, v ? v : UINT_MAX);
} }
/* The discard and secure erase limits are combined since the Linux
* block layer uses the same limit for both commands.
*
* If both VIRTIO_BLK_F_SECURE_ERASE and VIRTIO_BLK_F_DISCARD features
* are negotiated, we will use the minimum between the limits.
*
* discard sector alignment is set to the minimum between discard_sector_alignment
* and secure_erase_sector_alignment.
*
* max discard sectors is set to the minimum between max_discard_seg and
* max_secure_erase_seg.
*/
if (virtio_has_feature(vdev, VIRTIO_BLK_F_SECURE_ERASE)) {
virtio_cread(vdev, struct virtio_blk_config,
secure_erase_sector_alignment, &v);
/* secure_erase_sector_alignment should not be zero, the device should set a
* valid number of sectors.
*/
if (!v) {
dev_err(&vdev->dev,
"virtio_blk: secure_erase_sector_alignment can't be 0\n");
err = -EINVAL;
goto out_cleanup_disk;
}
discard_granularity = min_not_zero(discard_granularity, v);
virtio_cread(vdev, struct virtio_blk_config,
max_secure_erase_sectors, &v);
/* max_secure_erase_sectors should not be zero, the device should set a
* valid number of sectors.
*/
if (!v) {
dev_err(&vdev->dev,
"virtio_blk: max_secure_erase_sectors can't be 0\n");
err = -EINVAL;
goto out_cleanup_disk;
}
blk_queue_max_secure_erase_sectors(q, v);
virtio_cread(vdev, struct virtio_blk_config,
max_secure_erase_seg, &v);
/* max_secure_erase_seg should not be zero, the device should set a
* valid number of segments
*/
if (!v) {
dev_err(&vdev->dev,
"virtio_blk: max_secure_erase_seg can't be 0\n");
err = -EINVAL;
goto out_cleanup_disk;
}
max_discard_segs = min_not_zero(max_discard_segs, v);
}
if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD) ||
virtio_has_feature(vdev, VIRTIO_BLK_F_SECURE_ERASE)) {
/* max_discard_seg and discard_granularity will be 0 only
* if max_discard_seg and discard_sector_alignment fields in the virtio
* config are 0 and VIRTIO_BLK_F_SECURE_ERASE feature is not negotiated.
* In this case, we use default values.
*/
if (!max_discard_segs)
max_discard_segs = sg_elems;
blk_queue_max_discard_segments(q,
min(max_discard_segs, MAX_DISCARD_SEGMENTS));
if (discard_granularity)
q->limits.discard_granularity = discard_granularity << SECTOR_SHIFT;
else
q->limits.discard_granularity = blk_size;
}
virtblk_update_capacity(vblk, false); virtblk_update_capacity(vblk, false);
virtio_device_ready(vdev); virtio_device_ready(vdev);
...@@ -1167,6 +1239,7 @@ static unsigned int features_legacy[] = { ...@@ -1167,6 +1239,7 @@ static unsigned int features_legacy[] = {
VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
VIRTIO_BLK_F_SECURE_ERASE,
} }
; ;
static unsigned int features[] = { static unsigned int features[] = {
...@@ -1174,6 +1247,7 @@ static unsigned int features[] = { ...@@ -1174,6 +1247,7 @@ static unsigned int features[] = {
VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
VIRTIO_BLK_F_SECURE_ERASE,
}; };
static struct virtio_driver virtio_blk = { static struct virtio_driver virtio_blk = {
......
...@@ -225,6 +225,9 @@ struct virtnet_info { ...@@ -225,6 +225,9 @@ struct virtnet_info {
/* I like... big packets and I cannot lie! */ /* I like... big packets and I cannot lie! */
bool big_packets; bool big_packets;
/* number of sg entries allocated for big packets */
unsigned int big_packets_num_skbfrags;
/* Host will merge rx buffers for big packets (shake it! shake it!) */ /* Host will merge rx buffers for big packets (shake it! shake it!) */
bool mergeable_rx_bufs; bool mergeable_rx_bufs;
...@@ -1331,10 +1334,10 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq, ...@@ -1331,10 +1334,10 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
char *p; char *p;
int i, err, offset; int i, err, offset;
sg_init_table(rq->sg, MAX_SKB_FRAGS + 2); sg_init_table(rq->sg, vi->big_packets_num_skbfrags + 2);
/* page in rq->sg[MAX_SKB_FRAGS + 1] is list tail */ /* page in rq->sg[vi->big_packets_num_skbfrags + 1] is list tail */
for (i = MAX_SKB_FRAGS + 1; i > 1; --i) { for (i = vi->big_packets_num_skbfrags + 1; i > 1; --i) {
first = get_a_page(rq, gfp); first = get_a_page(rq, gfp);
if (!first) { if (!first) {
if (list) if (list)
...@@ -1365,7 +1368,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq, ...@@ -1365,7 +1368,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
/* chain first in list head */ /* chain first in list head */
first->private = (unsigned long)list; first->private = (unsigned long)list;
err = virtqueue_add_inbuf(rq->vq, rq->sg, MAX_SKB_FRAGS + 2, err = virtqueue_add_inbuf(rq->vq, rq->sg, vi->big_packets_num_skbfrags + 2,
first, gfp); first, gfp);
if (err < 0) if (err < 0)
give_pages(rq, first); give_pages(rq, first);
...@@ -3682,13 +3685,35 @@ static int virtnet_validate(struct virtio_device *vdev) ...@@ -3682,13 +3685,35 @@ static int virtnet_validate(struct virtio_device *vdev)
return 0; return 0;
} }
static bool virtnet_check_guest_gso(const struct virtnet_info *vi)
{
return virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) ||
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6) ||
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) ||
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO);
}
static void virtnet_set_big_packets(struct virtnet_info *vi, const int mtu)
{
bool guest_gso = virtnet_check_guest_gso(vi);
/* If device can receive ANY guest GSO packets, regardless of mtu,
* allocate packets of maximum size, otherwise limit it to only
* mtu size worth only.
*/
if (mtu > ETH_DATA_LEN || guest_gso) {
vi->big_packets = true;
vi->big_packets_num_skbfrags = guest_gso ? MAX_SKB_FRAGS : DIV_ROUND_UP(mtu, PAGE_SIZE);
}
}
static int virtnet_probe(struct virtio_device *vdev) static int virtnet_probe(struct virtio_device *vdev)
{ {
int i, err = -ENOMEM; int i, err = -ENOMEM;
struct net_device *dev; struct net_device *dev;
struct virtnet_info *vi; struct virtnet_info *vi;
u16 max_queue_pairs; u16 max_queue_pairs;
int mtu; int mtu = 0;
/* Find if host supports multiqueue/rss virtio_net device */ /* Find if host supports multiqueue/rss virtio_net device */
max_queue_pairs = 1; max_queue_pairs = 1;
...@@ -3776,13 +3801,6 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -3776,13 +3801,6 @@ static int virtnet_probe(struct virtio_device *vdev)
INIT_WORK(&vi->config_work, virtnet_config_changed_work); INIT_WORK(&vi->config_work, virtnet_config_changed_work);
spin_lock_init(&vi->refill_lock); spin_lock_init(&vi->refill_lock);
/* If we can receive ANY GSO packets, we must allocate large ones. */
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
vi->big_packets = true;
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
vi->mergeable_rx_bufs = true; vi->mergeable_rx_bufs = true;
...@@ -3848,12 +3866,10 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -3848,12 +3866,10 @@ static int virtnet_probe(struct virtio_device *vdev)
dev->mtu = mtu; dev->mtu = mtu;
dev->max_mtu = mtu; dev->max_mtu = mtu;
/* TODO: size buffers correctly in this case. */
if (dev->mtu > ETH_DATA_LEN)
vi->big_packets = true;
} }
virtnet_set_big_packets(vi, mtu);
if (vi->any_header_sg) if (vi->any_header_sg)
dev->needed_headroom = vi->hdr_len; dev->needed_headroom = vi->hdr_len;
......
...@@ -600,6 +600,11 @@ static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *i ...@@ -600,6 +600,11 @@ static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *i
} }
config.mask |= BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP); config.mask |= BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP);
} }
if (nl_attrs[VDPA_ATTR_DEV_FEATURES]) {
config.device_features =
nla_get_u64(nl_attrs[VDPA_ATTR_DEV_FEATURES]);
config.mask |= BIT_ULL(VDPA_ATTR_DEV_FEATURES);
}
/* Skip checking capability if user didn't prefer to configure any /* Skip checking capability if user didn't prefer to configure any
* device networking attributes. It is likely that user might have used * device networking attributes. It is likely that user might have used
...@@ -799,51 +804,76 @@ static int vdpa_nl_cmd_dev_get_dumpit(struct sk_buff *msg, struct netlink_callba ...@@ -799,51 +804,76 @@ static int vdpa_nl_cmd_dev_get_dumpit(struct sk_buff *msg, struct netlink_callba
return msg->len; return msg->len;
} }
static int vdpa_dev_net_mq_config_fill(struct vdpa_device *vdev, static int vdpa_dev_net_mq_config_fill(struct sk_buff *msg, u64 features,
struct sk_buff *msg, u64 features,
const struct virtio_net_config *config) const struct virtio_net_config *config)
{ {
u16 val_u16; u16 val_u16;
if ((features & BIT_ULL(VIRTIO_NET_F_MQ)) == 0) if ((features & BIT_ULL(VIRTIO_NET_F_MQ)) == 0 &&
(features & BIT_ULL(VIRTIO_NET_F_RSS)) == 0)
return 0; return 0;
val_u16 = le16_to_cpu(config->max_virtqueue_pairs); val_u16 = __virtio16_to_cpu(true, config->max_virtqueue_pairs);
return nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_MAX_VQP, val_u16); return nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_MAX_VQP, val_u16);
} }
static int vdpa_dev_net_mtu_config_fill(struct sk_buff *msg, u64 features,
const struct virtio_net_config *config)
{
u16 val_u16;
if ((features & BIT_ULL(VIRTIO_NET_F_MTU)) == 0)
return 0;
val_u16 = __virtio16_to_cpu(true, config->mtu);
return nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_MTU, val_u16);
}
static int vdpa_dev_net_mac_config_fill(struct sk_buff *msg, u64 features,
const struct virtio_net_config *config)
{
if ((features & BIT_ULL(VIRTIO_NET_F_MAC)) == 0)
return 0;
return nla_put(msg, VDPA_ATTR_DEV_NET_CFG_MACADDR,
sizeof(config->mac), config->mac);
}
static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *msg) static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *msg)
{ {
struct virtio_net_config config = {}; struct virtio_net_config config = {};
u64 features; u64 features_device;
u16 val_u16; u16 val_u16;
vdpa_get_config_unlocked(vdev, 0, &config, sizeof(config)); vdev->config->get_config(vdev, 0, &config, sizeof(config));
if (nla_put(msg, VDPA_ATTR_DEV_NET_CFG_MACADDR, sizeof(config.mac),
config.mac))
return -EMSGSIZE;
val_u16 = __virtio16_to_cpu(true, config.status); val_u16 = __virtio16_to_cpu(true, config.status);
if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_STATUS, val_u16)) if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_STATUS, val_u16))
return -EMSGSIZE; return -EMSGSIZE;
val_u16 = __virtio16_to_cpu(true, config.mtu); features_device = vdev->config->get_device_features(vdev);
if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_MTU, val_u16))
return -EMSGSIZE;
features = vdev->config->get_driver_features(vdev); if (nla_put_u64_64bit(msg, VDPA_ATTR_VDPA_DEV_SUPPORTED_FEATURES, features_device,
if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_NEGOTIATED_FEATURES, features,
VDPA_ATTR_PAD)) VDPA_ATTR_PAD))
return -EMSGSIZE; return -EMSGSIZE;
return vdpa_dev_net_mq_config_fill(vdev, msg, features, &config); if (vdpa_dev_net_mtu_config_fill(msg, features_device, &config))
return -EMSGSIZE;
if (vdpa_dev_net_mac_config_fill(msg, features_device, &config))
return -EMSGSIZE;
return vdpa_dev_net_mq_config_fill(msg, features_device, &config);
} }
static int static int
vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid, u32 seq, vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid, u32 seq,
int flags, struct netlink_ext_ack *extack) int flags, struct netlink_ext_ack *extack)
{ {
u64 features_driver;
u8 status = 0;
u32 device_id; u32 device_id;
void *hdr; void *hdr;
int err; int err;
...@@ -867,6 +897,17 @@ vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid, ...@@ -867,6 +897,17 @@ vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid,
goto msg_err; goto msg_err;
} }
/* only read driver features after the feature negotiation is done */
status = vdev->config->get_status(vdev);
if (status & VIRTIO_CONFIG_S_FEATURES_OK) {
features_driver = vdev->config->get_driver_features(vdev);
if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_NEGOTIATED_FEATURES, features_driver,
VDPA_ATTR_PAD)) {
err = -EMSGSIZE;
goto msg_err;
}
}
switch (device_id) { switch (device_id) {
case VIRTIO_ID_NET: case VIRTIO_ID_NET:
err = vdpa_dev_net_config_fill(vdev, msg); err = vdpa_dev_net_config_fill(vdev, msg);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/vdpa.h> #include <linux/vdpa.h>
#include <linux/vhost_iotlb.h> #include <linux/vhost_iotlb.h>
#include <linux/iova.h> #include <linux/iova.h>
#include <uapi/linux/vdpa.h>
#include "vdpa_sim.h" #include "vdpa_sim.h"
...@@ -245,13 +246,22 @@ static const struct dma_map_ops vdpasim_dma_ops = { ...@@ -245,13 +246,22 @@ static const struct dma_map_ops vdpasim_dma_ops = {
static const struct vdpa_config_ops vdpasim_config_ops; static const struct vdpa_config_ops vdpasim_config_ops;
static const struct vdpa_config_ops vdpasim_batch_config_ops; static const struct vdpa_config_ops vdpasim_batch_config_ops;
struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr) struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
const struct vdpa_dev_set_config *config)
{ {
const struct vdpa_config_ops *ops; const struct vdpa_config_ops *ops;
struct vdpasim *vdpasim; struct vdpasim *vdpasim;
struct device *dev; struct device *dev;
int i, ret = -ENOMEM; int i, ret = -ENOMEM;
if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) {
if (config->device_features &
~dev_attr->supported_features)
return ERR_PTR(-EINVAL);
dev_attr->supported_features =
config->device_features;
}
if (batch_mapping) if (batch_mapping)
ops = &vdpasim_batch_config_ops; ops = &vdpasim_batch_config_ops;
else else
......
...@@ -71,7 +71,8 @@ struct vdpasim { ...@@ -71,7 +71,8 @@ struct vdpasim {
spinlock_t iommu_lock; spinlock_t iommu_lock;
}; };
struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *attr); struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *attr,
const struct vdpa_dev_set_config *config);
/* TODO: cross-endian support */ /* TODO: cross-endian support */
static inline bool vdpasim_is_little_endian(struct vdpasim *vdpasim) static inline bool vdpasim_is_little_endian(struct vdpasim *vdpasim)
......
...@@ -383,7 +383,7 @@ static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, ...@@ -383,7 +383,7 @@ static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
dev_attr.work_fn = vdpasim_blk_work; dev_attr.work_fn = vdpasim_blk_work;
dev_attr.buffer_size = VDPASIM_BLK_CAPACITY << SECTOR_SHIFT; dev_attr.buffer_size = VDPASIM_BLK_CAPACITY << SECTOR_SHIFT;
simdev = vdpasim_create(&dev_attr); simdev = vdpasim_create(&dev_attr, config);
if (IS_ERR(simdev)) if (IS_ERR(simdev))
return PTR_ERR(simdev); return PTR_ERR(simdev);
......
...@@ -254,7 +254,7 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, ...@@ -254,7 +254,7 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
dev_attr.work_fn = vdpasim_net_work; dev_attr.work_fn = vdpasim_net_work;
dev_attr.buffer_size = PAGE_SIZE; dev_attr.buffer_size = PAGE_SIZE;
simdev = vdpasim_create(&dev_attr); simdev = vdpasim_create(&dev_attr, config);
if (IS_ERR(simdev)) if (IS_ERR(simdev))
return PTR_ERR(simdev); return PTR_ERR(simdev);
...@@ -294,7 +294,8 @@ static struct vdpa_mgmt_dev mgmt_dev = { ...@@ -294,7 +294,8 @@ static struct vdpa_mgmt_dev mgmt_dev = {
.id_table = id_table, .id_table = id_table,
.ops = &vdpasim_net_mgmtdev_ops, .ops = &vdpasim_net_mgmtdev_ops,
.config_attr_mask = (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR | .config_attr_mask = (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR |
1 << VDPA_ATTR_DEV_NET_CFG_MTU), 1 << VDPA_ATTR_DEV_NET_CFG_MTU |
1 << VDPA_ATTR_DEV_FEATURES),
.max_supported_vqs = VDPASIM_NET_VQ_NUM, .max_supported_vqs = VDPASIM_NET_VQ_NUM,
.supported_features = VDPASIM_NET_FEATURES, .supported_features = VDPASIM_NET_FEATURES,
}; };
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/virtio_ring.h> #include <linux/virtio_ring.h>
#include <linux/virtio_pci.h> #include <linux/virtio_pci.h>
#include <linux/virtio_pci_modern.h> #include <linux/virtio_pci_modern.h>
#include <uapi/linux/vdpa.h>
#define VP_VDPA_QUEUE_MAX 256 #define VP_VDPA_QUEUE_MAX 256
#define VP_VDPA_DRIVER_NAME "vp_vdpa" #define VP_VDPA_DRIVER_NAME "vp_vdpa"
...@@ -35,6 +36,7 @@ struct vp_vdpa { ...@@ -35,6 +36,7 @@ struct vp_vdpa {
struct virtio_pci_modern_device *mdev; struct virtio_pci_modern_device *mdev;
struct vp_vring *vring; struct vp_vring *vring;
struct vdpa_callback config_cb; struct vdpa_callback config_cb;
u64 device_features;
char msix_name[VP_VDPA_NAME_SIZE]; char msix_name[VP_VDPA_NAME_SIZE];
int config_irq; int config_irq;
int queues; int queues;
...@@ -66,9 +68,9 @@ static struct virtio_pci_modern_device *vp_vdpa_to_mdev(struct vp_vdpa *vp_vdpa) ...@@ -66,9 +68,9 @@ static struct virtio_pci_modern_device *vp_vdpa_to_mdev(struct vp_vdpa *vp_vdpa)
static u64 vp_vdpa_get_device_features(struct vdpa_device *vdpa) static u64 vp_vdpa_get_device_features(struct vdpa_device *vdpa)
{ {
struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa); struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa);
return vp_modern_get_features(mdev); return vp_vdpa->device_features;
} }
static int vp_vdpa_set_driver_features(struct vdpa_device *vdpa, u64 features) static int vp_vdpa_set_driver_features(struct vdpa_device *vdpa, u64 features)
...@@ -475,6 +477,7 @@ static int vp_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, ...@@ -475,6 +477,7 @@ static int vp_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
struct pci_dev *pdev = mdev->pci_dev; struct pci_dev *pdev = mdev->pci_dev;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct vp_vdpa *vp_vdpa = NULL; struct vp_vdpa *vp_vdpa = NULL;
u64 device_features;
int ret, i; int ret, i;
vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa, vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa,
...@@ -491,6 +494,20 @@ static int vp_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, ...@@ -491,6 +494,20 @@ static int vp_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
vp_vdpa->queues = vp_modern_get_num_queues(mdev); vp_vdpa->queues = vp_modern_get_num_queues(mdev);
vp_vdpa->mdev = mdev; vp_vdpa->mdev = mdev;
device_features = vp_modern_get_features(mdev);
if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) {
if (add_config->device_features & ~device_features) {
ret = -EINVAL;
dev_err(&pdev->dev, "Try to provision features "
"that are not supported by the device: "
"device_features 0x%llx provisioned 0x%llx\n",
device_features, add_config->device_features);
goto err;
}
device_features = add_config->device_features;
}
vp_vdpa->device_features = device_features;
ret = devm_add_action_or_reset(dev, vp_vdpa_free_irq_vectors, pdev); ret = devm_add_action_or_reset(dev, vp_vdpa_free_irq_vectors, pdev);
if (ret) { if (ret) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
...@@ -599,6 +616,7 @@ static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -599,6 +616,7 @@ static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mgtdev->id_table = mdev_id; mgtdev->id_table = mdev_id;
mgtdev->max_supported_vqs = vp_modern_get_num_queues(mdev); mgtdev->max_supported_vqs = vp_modern_get_num_queues(mdev);
mgtdev->supported_features = vp_modern_get_features(mdev); mgtdev->supported_features = vp_modern_get_features(mdev);
mgtdev->config_attr_mask = (1 << VDPA_ATTR_DEV_FEATURES);
pci_set_master(pdev); pci_set_master(pdev);
pci_set_drvdata(pdev, vp_vdpa_mgtdev); pci_set_drvdata(pdev, vp_vdpa_mgtdev);
......
...@@ -1782,7 +1782,7 @@ static struct miscdevice vhost_net_misc = { ...@@ -1782,7 +1782,7 @@ static struct miscdevice vhost_net_misc = {
.fops = &vhost_net_fops, .fops = &vhost_net_fops,
}; };
static int vhost_net_init(void) static int __init vhost_net_init(void)
{ {
if (experimental_zcopytx) if (experimental_zcopytx)
vhost_net_enable_zcopy(VHOST_NET_VQ_TX); vhost_net_enable_zcopy(VHOST_NET_VQ_TX);
...@@ -1790,7 +1790,7 @@ static int vhost_net_init(void) ...@@ -1790,7 +1790,7 @@ static int vhost_net_init(void)
} }
module_init(vhost_net_init); module_init(vhost_net_init);
static void vhost_net_exit(void) static void __exit vhost_net_exit(void)
{ {
misc_deregister(&vhost_net_misc); misc_deregister(&vhost_net_misc);
} }
......
...@@ -409,6 +409,9 @@ int vp_find_vqs(struct virtio_device *vdev, unsigned int nvqs, ...@@ -409,6 +409,9 @@ int vp_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, ctx, desc); err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, ctx, desc);
if (!err) if (!err)
return 0; return 0;
/* Is there an interrupt pin? If not give up. */
if (!(to_vp_device(vdev)->pci_dev->pin))
return err;
/* Finally fall back to regular interrupts. */ /* 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, callbacks, names, ctx);
} }
......
...@@ -1066,7 +1066,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split, ...@@ -1066,7 +1066,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
if (!queue) { if (!queue) {
/* Try to get a single page. You are my only hope! */ /* Try to get a single page. You are my only hope! */
queue = vring_alloc_queue(vdev, vring_size(num, vring_align), queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
&dma_addr, GFP_KERNEL|__GFP_ZERO); &dma_addr, GFP_KERNEL | __GFP_ZERO);
} }
if (!queue) if (!queue)
return -ENOMEM; return -ENOMEM;
...@@ -1867,7 +1867,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed, ...@@ -1867,7 +1867,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
ring = vring_alloc_queue(vdev, ring_size_in_bytes, ring = vring_alloc_queue(vdev, ring_size_in_bytes,
&ring_dma_addr, &ring_dma_addr,
GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO); GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
if (!ring) if (!ring)
goto err; goto err;
...@@ -1879,7 +1879,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed, ...@@ -1879,7 +1879,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
driver = vring_alloc_queue(vdev, event_size_in_bytes, driver = vring_alloc_queue(vdev, event_size_in_bytes,
&driver_event_dma_addr, &driver_event_dma_addr,
GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO); GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
if (!driver) if (!driver)
goto err; goto err;
...@@ -1889,7 +1889,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed, ...@@ -1889,7 +1889,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
device = vring_alloc_queue(vdev, event_size_in_bytes, device = vring_alloc_queue(vdev, event_size_in_bytes,
&device_event_dma_addr, &device_event_dma_addr,
GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO); GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
if (!device) if (!device)
goto err; goto err;
......
...@@ -104,6 +104,7 @@ struct vdpa_iova_range { ...@@ -104,6 +104,7 @@ struct vdpa_iova_range {
}; };
struct vdpa_dev_set_config { struct vdpa_dev_set_config {
u64 device_features;
struct { struct {
u8 mac[ETH_ALEN]; u8 mac[ETH_ALEN];
u16 mtu; u16 mtu;
......
...@@ -32,8 +32,6 @@ void vp_legacy_set_queue_address(struct virtio_pci_legacy_device *ldev, ...@@ -32,8 +32,6 @@ void vp_legacy_set_queue_address(struct virtio_pci_legacy_device *ldev,
u16 index, u32 queue_pfn); u16 index, u32 queue_pfn);
bool vp_legacy_get_queue_enable(struct virtio_pci_legacy_device *ldev, bool vp_legacy_get_queue_enable(struct virtio_pci_legacy_device *ldev,
u16 idx); u16 idx);
void vp_legacy_set_queue_size(struct virtio_pci_legacy_device *ldev,
u16 idx, u16 size);
u16 vp_legacy_get_queue_size(struct virtio_pci_legacy_device *ldev, u16 vp_legacy_get_queue_size(struct virtio_pci_legacy_device *ldev,
u16 idx); u16 idx);
int vp_legacy_probe(struct virtio_pci_legacy_device *ldev); int vp_legacy_probe(struct virtio_pci_legacy_device *ldev);
......
...@@ -46,12 +46,18 @@ enum vdpa_attr { ...@@ -46,12 +46,18 @@ enum vdpa_attr {
VDPA_ATTR_DEV_NEGOTIATED_FEATURES, /* u64 */ VDPA_ATTR_DEV_NEGOTIATED_FEATURES, /* u64 */
VDPA_ATTR_DEV_MGMTDEV_MAX_VQS, /* u32 */ VDPA_ATTR_DEV_MGMTDEV_MAX_VQS, /* u32 */
/* virtio features that are supported by the vDPA management device */
VDPA_ATTR_DEV_SUPPORTED_FEATURES, /* u64 */ VDPA_ATTR_DEV_SUPPORTED_FEATURES, /* u64 */
VDPA_ATTR_DEV_QUEUE_INDEX, /* u32 */ VDPA_ATTR_DEV_QUEUE_INDEX, /* u32 */
VDPA_ATTR_DEV_VENDOR_ATTR_NAME, /* string */ VDPA_ATTR_DEV_VENDOR_ATTR_NAME, /* string */
VDPA_ATTR_DEV_VENDOR_ATTR_VALUE, /* u64 */ VDPA_ATTR_DEV_VENDOR_ATTR_VALUE, /* u64 */
VDPA_ATTR_DEV_FEATURES, /* u64 */
/* virtio features that are supported by the vDPA device */
VDPA_ATTR_VDPA_DEV_SUPPORTED_FEATURES, /* u64 */
/* new attributes must be added above here */ /* new attributes must be added above here */
VDPA_ATTR_MAX, VDPA_ATTR_MAX,
}; };
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */ #define VIRTIO_BLK_F_MQ 12 /* support more than one vq */
#define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */ #define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */
#define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */ #define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */
#define VIRTIO_BLK_F_SECURE_ERASE 16 /* Secure Erase is supported */
/* Legacy feature bits */ /* Legacy feature bits */
#ifndef VIRTIO_BLK_NO_LEGACY #ifndef VIRTIO_BLK_NO_LEGACY
...@@ -121,6 +122,21 @@ struct virtio_blk_config { ...@@ -121,6 +122,21 @@ struct virtio_blk_config {
__u8 write_zeroes_may_unmap; __u8 write_zeroes_may_unmap;
__u8 unused1[3]; __u8 unused1[3];
/* the next 3 entries are guarded by VIRTIO_BLK_F_SECURE_ERASE */
/*
* The maximum secure erase sectors (in 512-byte sectors) for
* one segment.
*/
__virtio32 max_secure_erase_sectors;
/*
* The maximum number of secure erase segments in a
* secure erase command.
*/
__virtio32 max_secure_erase_seg;
/* Secure erase commands must be aligned to this number of sectors. */
__virtio32 secure_erase_sector_alignment;
} __attribute__((packed)); } __attribute__((packed));
/* /*
...@@ -155,6 +171,9 @@ struct virtio_blk_config { ...@@ -155,6 +171,9 @@ struct virtio_blk_config {
/* Write zeroes command */ /* Write zeroes command */
#define VIRTIO_BLK_T_WRITE_ZEROES 13 #define VIRTIO_BLK_T_WRITE_ZEROES 13
/* Secure erase command */
#define VIRTIO_BLK_T_SECURE_ERASE 14
#ifndef VIRTIO_BLK_NO_LEGACY #ifndef VIRTIO_BLK_NO_LEGACY
/* Barrier before this op. */ /* Barrier before this op. */
#define VIRTIO_BLK_T_BARRIER 0x80000000 #define VIRTIO_BLK_T_BARRIER 0x80000000
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment