mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-27 22:24:11 +08:00
virtio: fixes, features
9k mtu perf improvements vdpa feature provisioning virtio blk SECURE ERASE support Fixes, cleanups all over the place. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmNAvcMPHG1zdEByZWRo YXQuY29tAAoJECgfDbjSjVRpYaMH/0hv6q1D35lLinVn4DSz8ru754picK9Pg8Vv dJG8w0v3VN1lHLBQ63Gj9/M47odCq8JeeDwmkzVs3C2I3pwLdcO1Yd+fkqGVP7gd Fc7cyi87sk4heHEm6K5jC17gf3k39rS9BkFbYFyPQzr/+6HXx6O/6x7StxvY9EB0 nst7yjPxKXptF5Sf3uUFk4YIFxSvkmvV292sLrWvkaMjn71oJXqsr8yNCFcqv/jk KM7C8ZCRuydatM+PEuJPcveJd04jYuoNS3OZDCCWD6XuzLROQ10PbLBBqoHLEWu7 wZbY4WndJSqnRE3dx0Xm8LgKNPOBxVfDoD3RVejxW6JF9hmGcG8= =PIpt -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
8aeab132e0
@ -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);
|
||||
}
|
||||
|
||||
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 n = 0;
|
||||
@ -240,6 +240,9 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
|
||||
type = VIRTIO_BLK_T_WRITE_ZEROES;
|
||||
unmap = !(req->cmd_flags & REQ_NOUNMAP);
|
||||
break;
|
||||
case REQ_OP_SECURE_ERASE:
|
||||
type = VIRTIO_BLK_T_SECURE_ERASE;
|
||||
break;
|
||||
case REQ_OP_DRV_IN:
|
||||
type = VIRTIO_BLK_T_GET_ID;
|
||||
break;
|
||||
@ -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.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
|
||||
|
||||
if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) {
|
||||
if (virtblk_setup_discard_write_zeroes(req, unmap))
|
||||
if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES ||
|
||||
type == VIRTIO_BLK_T_SECURE_ERASE) {
|
||||
if (virtblk_setup_discard_write_zeroes_erase(req, unmap))
|
||||
return BLK_STS_RESOURCE;
|
||||
}
|
||||
|
||||
@ -886,6 +890,8 @@ static int virtblk_probe(struct virtio_device *vdev)
|
||||
int err, index;
|
||||
|
||||
u32 v, blk_size, max_size, sg_elems, opt_io_size;
|
||||
u32 max_discard_segs = 0;
|
||||
u32 discard_granularity = 0;
|
||||
u16 min_io_size;
|
||||
u8 physical_block_exp, alignment_offset;
|
||||
unsigned int queue_depth;
|
||||
@ -1043,27 +1049,14 @@ static int virtblk_probe(struct virtio_device *vdev)
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
|
||||
virtio_cread(vdev, struct virtio_blk_config,
|
||||
discard_sector_alignment, &v);
|
||||
if (v)
|
||||
q->limits.discard_granularity = v << SECTOR_SHIFT;
|
||||
else
|
||||
q->limits.discard_granularity = blk_size;
|
||||
discard_sector_alignment, &discard_granularity);
|
||||
|
||||
virtio_cread(vdev, struct virtio_blk_config,
|
||||
max_discard_sectors, &v);
|
||||
blk_queue_max_discard_sectors(q, v ? v : UINT_MAX);
|
||||
|
||||
virtio_cread(vdev, struct virtio_blk_config, max_discard_seg,
|
||||
&v);
|
||||
|
||||
/*
|
||||
* 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));
|
||||
&max_discard_segs);
|
||||
}
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_BLK_F_WRITE_ZEROES)) {
|
||||
@ -1072,6 +1065,85 @@ static int virtblk_probe(struct virtio_device *vdev)
|
||||
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);
|
||||
virtio_device_ready(vdev);
|
||||
|
||||
@ -1167,6 +1239,7 @@ static unsigned int features_legacy[] = {
|
||||
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_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
|
||||
VIRTIO_BLK_F_SECURE_ERASE,
|
||||
}
|
||||
;
|
||||
static unsigned int features[] = {
|
||||
@ -1174,6 +1247,7 @@ static unsigned int features[] = {
|
||||
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_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
|
||||
VIRTIO_BLK_F_SECURE_ERASE,
|
||||
};
|
||||
|
||||
static struct virtio_driver virtio_blk = {
|
||||
|
@ -225,6 +225,9 @@ struct virtnet_info {
|
||||
/* I like... big packets and I cannot lie! */
|
||||
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!) */
|
||||
bool mergeable_rx_bufs;
|
||||
|
||||
@ -1331,10 +1334,10 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
|
||||
char *p;
|
||||
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 */
|
||||
for (i = MAX_SKB_FRAGS + 1; i > 1; --i) {
|
||||
/* page in rq->sg[vi->big_packets_num_skbfrags + 1] is list tail */
|
||||
for (i = vi->big_packets_num_skbfrags + 1; i > 1; --i) {
|
||||
first = get_a_page(rq, gfp);
|
||||
if (!first) {
|
||||
if (list)
|
||||
@ -1365,7 +1368,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
|
||||
|
||||
/* chain first in list head */
|
||||
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);
|
||||
if (err < 0)
|
||||
give_pages(rq, first);
|
||||
@ -3682,13 +3685,35 @@ static int virtnet_validate(struct virtio_device *vdev)
|
||||
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)
|
||||
{
|
||||
int i, err = -ENOMEM;
|
||||
struct net_device *dev;
|
||||
struct virtnet_info *vi;
|
||||
u16 max_queue_pairs;
|
||||
int mtu;
|
||||
int mtu = 0;
|
||||
|
||||
/* Find if host supports multiqueue/rss virtio_net device */
|
||||
max_queue_pairs = 1;
|
||||
@ -3776,13 +3801,6 @@ static int virtnet_probe(struct virtio_device *vdev)
|
||||
INIT_WORK(&vi->config_work, virtnet_config_changed_work);
|
||||
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))
|
||||
vi->mergeable_rx_bufs = true;
|
||||
|
||||
@ -3848,12 +3866,10 @@ static int virtnet_probe(struct virtio_device *vdev)
|
||||
|
||||
dev->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)
|
||||
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
|
||||
}
|
||||
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
|
||||
* 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
|
||||
return msg->len;
|
||||
}
|
||||
|
||||
static int vdpa_dev_net_mq_config_fill(struct vdpa_device *vdev,
|
||||
struct sk_buff *msg, u64 features,
|
||||
static int vdpa_dev_net_mq_config_fill(struct sk_buff *msg, u64 features,
|
||||
const struct virtio_net_config *config)
|
||||
{
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct virtio_net_config config = {};
|
||||
u64 features;
|
||||
u64 features_device;
|
||||
u16 val_u16;
|
||||
|
||||
vdpa_get_config_unlocked(vdev, 0, &config, sizeof(config));
|
||||
|
||||
if (nla_put(msg, VDPA_ATTR_DEV_NET_CFG_MACADDR, sizeof(config.mac),
|
||||
config.mac))
|
||||
return -EMSGSIZE;
|
||||
vdev->config->get_config(vdev, 0, &config, sizeof(config));
|
||||
|
||||
val_u16 = __virtio16_to_cpu(true, config.status);
|
||||
if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_STATUS, val_u16))
|
||||
return -EMSGSIZE;
|
||||
|
||||
val_u16 = __virtio16_to_cpu(true, config.mtu);
|
||||
if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_MTU, val_u16))
|
||||
return -EMSGSIZE;
|
||||
features_device = vdev->config->get_device_features(vdev);
|
||||
|
||||
features = vdev->config->get_driver_features(vdev);
|
||||
if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_NEGOTIATED_FEATURES, features,
|
||||
if (nla_put_u64_64bit(msg, VDPA_ATTR_VDPA_DEV_SUPPORTED_FEATURES, features_device,
|
||||
VDPA_ATTR_PAD))
|
||||
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
|
||||
vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid, u32 seq,
|
||||
int flags, struct netlink_ext_ack *extack)
|
||||
{
|
||||
u64 features_driver;
|
||||
u8 status = 0;
|
||||
u32 device_id;
|
||||
void *hdr;
|
||||
int err;
|
||||
@ -867,6 +897,17 @@ vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid,
|
||||
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) {
|
||||
case VIRTIO_ID_NET:
|
||||
err = vdpa_dev_net_config_fill(vdev, msg);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/vdpa.h>
|
||||
#include <linux/vhost_iotlb.h>
|
||||
#include <linux/iova.h>
|
||||
#include <uapi/linux/vdpa.h>
|
||||
|
||||
#include "vdpa_sim.h"
|
||||
|
||||
@ -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_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;
|
||||
struct vdpasim *vdpasim;
|
||||
struct device *dev;
|
||||
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)
|
||||
ops = &vdpasim_batch_config_ops;
|
||||
else
|
||||
|
@ -71,7 +71,8 @@ struct vdpasim {
|
||||
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 */
|
||||
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,
|
||||
dev_attr.work_fn = vdpasim_blk_work;
|
||||
dev_attr.buffer_size = VDPASIM_BLK_CAPACITY << SECTOR_SHIFT;
|
||||
|
||||
simdev = vdpasim_create(&dev_attr);
|
||||
simdev = vdpasim_create(&dev_attr, config);
|
||||
if (IS_ERR(simdev))
|
||||
return PTR_ERR(simdev);
|
||||
|
||||
|
@ -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.buffer_size = PAGE_SIZE;
|
||||
|
||||
simdev = vdpasim_create(&dev_attr);
|
||||
simdev = vdpasim_create(&dev_attr, config);
|
||||
if (IS_ERR(simdev))
|
||||
return PTR_ERR(simdev);
|
||||
|
||||
@ -294,7 +294,8 @@ static struct vdpa_mgmt_dev mgmt_dev = {
|
||||
.id_table = id_table,
|
||||
.ops = &vdpasim_net_mgmtdev_ops,
|
||||
.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,
|
||||
.supported_features = VDPASIM_NET_FEATURES,
|
||||
};
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/virtio_ring.h>
|
||||
#include <linux/virtio_pci.h>
|
||||
#include <linux/virtio_pci_modern.h>
|
||||
#include <uapi/linux/vdpa.h>
|
||||
|
||||
#define VP_VDPA_QUEUE_MAX 256
|
||||
#define VP_VDPA_DRIVER_NAME "vp_vdpa"
|
||||
@ -35,6 +36,7 @@ struct vp_vdpa {
|
||||
struct virtio_pci_modern_device *mdev;
|
||||
struct vp_vring *vring;
|
||||
struct vdpa_callback config_cb;
|
||||
u64 device_features;
|
||||
char msix_name[VP_VDPA_NAME_SIZE];
|
||||
int config_irq;
|
||||
int queues;
|
||||
@ -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)
|
||||
{
|
||||
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)
|
||||
@ -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 device *dev = &pdev->dev;
|
||||
struct vp_vdpa *vp_vdpa = NULL;
|
||||
u64 device_features;
|
||||
int ret, i;
|
||||
|
||||
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,
|
||||
vp_vdpa->queues = vp_modern_get_num_queues(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);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
@ -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->max_supported_vqs = vp_modern_get_num_queues(mdev);
|
||||
mgtdev->supported_features = vp_modern_get_features(mdev);
|
||||
mgtdev->config_attr_mask = (1 << VDPA_ATTR_DEV_FEATURES);
|
||||
pci_set_master(pdev);
|
||||
pci_set_drvdata(pdev, vp_vdpa_mgtdev);
|
||||
|
||||
|
@ -1782,7 +1782,7 @@ static struct miscdevice vhost_net_misc = {
|
||||
.fops = &vhost_net_fops,
|
||||
};
|
||||
|
||||
static int vhost_net_init(void)
|
||||
static int __init vhost_net_init(void)
|
||||
{
|
||||
if (experimental_zcopytx)
|
||||
vhost_net_enable_zcopy(VHOST_NET_VQ_TX);
|
||||
@ -1790,7 +1790,7 @@ static int vhost_net_init(void)
|
||||
}
|
||||
module_init(vhost_net_init);
|
||||
|
||||
static void vhost_net_exit(void)
|
||||
static void __exit vhost_net_exit(void)
|
||||
{
|
||||
misc_deregister(&vhost_net_misc);
|
||||
}
|
||||
|
@ -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);
|
||||
if (!err)
|
||||
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. */
|
||||
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,
|
||||
if (!queue) {
|
||||
/* Try to get a single page. You are my only hope! */
|
||||
queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
|
||||
&dma_addr, GFP_KERNEL|__GFP_ZERO);
|
||||
&dma_addr, GFP_KERNEL | __GFP_ZERO);
|
||||
}
|
||||
if (!queue)
|
||||
return -ENOMEM;
|
||||
@ -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_dma_addr,
|
||||
GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO);
|
||||
GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
|
||||
if (!ring)
|
||||
goto err;
|
||||
|
||||
@ -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_event_dma_addr,
|
||||
GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO);
|
||||
GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
|
||||
if (!driver)
|
||||
goto err;
|
||||
|
||||
@ -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_event_dma_addr,
|
||||
GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO);
|
||||
GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
|
||||
if (!device)
|
||||
goto err;
|
||||
|
||||
|
@ -104,6 +104,7 @@ struct vdpa_iova_range {
|
||||
};
|
||||
|
||||
struct vdpa_dev_set_config {
|
||||
u64 device_features;
|
||||
struct {
|
||||
u8 mac[ETH_ALEN];
|
||||
u16 mtu;
|
||||
|
@ -32,8 +32,6 @@ void vp_legacy_set_queue_address(struct virtio_pci_legacy_device *ldev,
|
||||
u16 index, u32 queue_pfn);
|
||||
bool vp_legacy_get_queue_enable(struct virtio_pci_legacy_device *ldev,
|
||||
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 idx);
|
||||
int vp_legacy_probe(struct virtio_pci_legacy_device *ldev);
|
||||
|
@ -46,12 +46,18 @@ enum vdpa_attr {
|
||||
|
||||
VDPA_ATTR_DEV_NEGOTIATED_FEATURES, /* u64 */
|
||||
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_QUEUE_INDEX, /* u32 */
|
||||
VDPA_ATTR_DEV_VENDOR_ATTR_NAME, /* string */
|
||||
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 */
|
||||
VDPA_ATTR_MAX,
|
||||
};
|
||||
|
@ -40,6 +40,7 @@
|
||||
#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */
|
||||
#define VIRTIO_BLK_F_DISCARD 13 /* DISCARD 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 */
|
||||
#ifndef VIRTIO_BLK_NO_LEGACY
|
||||
@ -121,6 +122,21 @@ struct virtio_blk_config {
|
||||
__u8 write_zeroes_may_unmap;
|
||||
|
||||
__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));
|
||||
|
||||
/*
|
||||
@ -155,6 +171,9 @@ struct virtio_blk_config {
|
||||
/* Write zeroes command */
|
||||
#define VIRTIO_BLK_T_WRITE_ZEROES 13
|
||||
|
||||
/* Secure erase command */
|
||||
#define VIRTIO_BLK_T_SECURE_ERASE 14
|
||||
|
||||
#ifndef VIRTIO_BLK_NO_LEGACY
|
||||
/* Barrier before this op. */
|
||||
#define VIRTIO_BLK_T_BARRIER 0x80000000
|
||||
|
Loading…
Reference in New Issue
Block a user