mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
Merge 43e1b12927 ("Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost") into android-mainline
Steps on the way to 5.16-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I5e5952a486b20df66e03214d5828c7ed92f6e2c4
This commit is contained in:
@@ -1049,6 +1049,7 @@ static struct virtio_driver virtio_blk = {
|
||||
.feature_table_size = ARRAY_SIZE(features),
|
||||
.feature_table_legacy = features_legacy,
|
||||
.feature_table_size_legacy = ARRAY_SIZE(features_legacy),
|
||||
.suppress_used_validation = true,
|
||||
.driver.name = KBUILD_MODNAME,
|
||||
.driver.owner = THIS_MODULE,
|
||||
.id_table = id_table,
|
||||
|
||||
@@ -3423,6 +3423,7 @@ static struct virtio_driver virtio_net_driver = {
|
||||
.feature_table_size = ARRAY_SIZE(features),
|
||||
.feature_table_legacy = features_legacy,
|
||||
.feature_table_size_legacy = ARRAY_SIZE(features_legacy),
|
||||
.suppress_used_validation = true,
|
||||
.driver.name = KBUILD_MODNAME,
|
||||
.driver.owner = THIS_MODULE,
|
||||
.id_table = id_table,
|
||||
|
||||
@@ -978,6 +978,7 @@ static unsigned int features[] = {
|
||||
static struct virtio_driver virtio_scsi_driver = {
|
||||
.feature_table = features,
|
||||
.feature_table_size = ARRAY_SIZE(features),
|
||||
.suppress_used_validation = true,
|
||||
.driver.name = KBUILD_MODNAME,
|
||||
.driver.owner = THIS_MODULE,
|
||||
.id_table = id_table,
|
||||
|
||||
@@ -499,7 +499,8 @@ static u32 get_dev_type(struct pci_dev *pdev)
|
||||
return dev_type;
|
||||
}
|
||||
|
||||
static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name)
|
||||
static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
|
||||
const struct vdpa_dev_set_config *config)
|
||||
{
|
||||
struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev;
|
||||
struct ifcvf_adapter *adapter;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <linux/vringh.h>
|
||||
#include <uapi/linux/virtio_net.h>
|
||||
#include <uapi/linux/virtio_ids.h>
|
||||
#include <uapi/linux/vdpa.h>
|
||||
#include <linux/virtio_config.h>
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/mlx5/cq.h>
|
||||
@@ -157,7 +158,8 @@ struct mlx5_vdpa_net {
|
||||
struct mutex reslock;
|
||||
struct mlx5_flow_table *rxft;
|
||||
struct mlx5_fc *rx_counter;
|
||||
struct mlx5_flow_handle *rx_rule;
|
||||
struct mlx5_flow_handle *rx_rule_ucast;
|
||||
struct mlx5_flow_handle *rx_rule_mcast;
|
||||
bool setup;
|
||||
u32 cur_num_vqs;
|
||||
struct notifier_block nb;
|
||||
@@ -1382,21 +1384,33 @@ static int add_fwd_to_tir(struct mlx5_vdpa_net *ndev)
|
||||
struct mlx5_flow_table_attr ft_attr = {};
|
||||
struct mlx5_flow_act flow_act = {};
|
||||
struct mlx5_flow_namespace *ns;
|
||||
struct mlx5_flow_spec *spec;
|
||||
void *headers_c;
|
||||
void *headers_v;
|
||||
u8 *dmac_c;
|
||||
u8 *dmac_v;
|
||||
int err;
|
||||
|
||||
/* for now, one entry, match all, forward to tir */
|
||||
ft_attr.max_fte = 1;
|
||||
ft_attr.autogroup.max_num_groups = 1;
|
||||
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (!spec)
|
||||
return -ENOMEM;
|
||||
|
||||
spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
|
||||
ft_attr.max_fte = 2;
|
||||
ft_attr.autogroup.max_num_groups = 2;
|
||||
|
||||
ns = mlx5_get_flow_namespace(ndev->mvdev.mdev, MLX5_FLOW_NAMESPACE_BYPASS);
|
||||
if (!ns) {
|
||||
mlx5_vdpa_warn(&ndev->mvdev, "get flow namespace\n");
|
||||
return -EOPNOTSUPP;
|
||||
mlx5_vdpa_warn(&ndev->mvdev, "failed to get flow namespace\n");
|
||||
err = -EOPNOTSUPP;
|
||||
goto err_ns;
|
||||
}
|
||||
|
||||
ndev->rxft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
|
||||
if (IS_ERR(ndev->rxft))
|
||||
return PTR_ERR(ndev->rxft);
|
||||
if (IS_ERR(ndev->rxft)) {
|
||||
err = PTR_ERR(ndev->rxft);
|
||||
goto err_ns;
|
||||
}
|
||||
|
||||
ndev->rx_counter = mlx5_fc_create(ndev->mvdev.mdev, false);
|
||||
if (IS_ERR(ndev->rx_counter)) {
|
||||
@@ -1404,37 +1418,64 @@ static int add_fwd_to_tir(struct mlx5_vdpa_net *ndev)
|
||||
goto err_fc;
|
||||
}
|
||||
|
||||
headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers);
|
||||
dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c, outer_headers.dmac_47_16);
|
||||
memset(dmac_c, 0xff, ETH_ALEN);
|
||||
headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers);
|
||||
dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v, outer_headers.dmac_47_16);
|
||||
ether_addr_copy(dmac_v, ndev->config.mac);
|
||||
|
||||
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_COUNT;
|
||||
dest[0].type = MLX5_FLOW_DESTINATION_TYPE_TIR;
|
||||
dest[0].tir_num = ndev->res.tirn;
|
||||
dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
|
||||
dest[1].counter_id = mlx5_fc_id(ndev->rx_counter);
|
||||
ndev->rx_rule = mlx5_add_flow_rules(ndev->rxft, NULL, &flow_act, dest, 2);
|
||||
if (IS_ERR(ndev->rx_rule)) {
|
||||
err = PTR_ERR(ndev->rx_rule);
|
||||
ndev->rx_rule = NULL;
|
||||
goto err_rule;
|
||||
ndev->rx_rule_ucast = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dest, 2);
|
||||
|
||||
if (IS_ERR(ndev->rx_rule_ucast)) {
|
||||
err = PTR_ERR(ndev->rx_rule_ucast);
|
||||
ndev->rx_rule_ucast = NULL;
|
||||
goto err_rule_ucast;
|
||||
}
|
||||
|
||||
memset(dmac_c, 0, ETH_ALEN);
|
||||
memset(dmac_v, 0, ETH_ALEN);
|
||||
dmac_c[0] = 1;
|
||||
dmac_v[0] = 1;
|
||||
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
|
||||
ndev->rx_rule_mcast = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dest, 1);
|
||||
if (IS_ERR(ndev->rx_rule_mcast)) {
|
||||
err = PTR_ERR(ndev->rx_rule_mcast);
|
||||
ndev->rx_rule_mcast = NULL;
|
||||
goto err_rule_mcast;
|
||||
}
|
||||
|
||||
kvfree(spec);
|
||||
return 0;
|
||||
|
||||
err_rule:
|
||||
err_rule_mcast:
|
||||
mlx5_del_flow_rules(ndev->rx_rule_ucast);
|
||||
ndev->rx_rule_ucast = NULL;
|
||||
err_rule_ucast:
|
||||
mlx5_fc_destroy(ndev->mvdev.mdev, ndev->rx_counter);
|
||||
err_fc:
|
||||
mlx5_destroy_flow_table(ndev->rxft);
|
||||
err_ns:
|
||||
kvfree(spec);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void remove_fwd_to_tir(struct mlx5_vdpa_net *ndev)
|
||||
{
|
||||
if (!ndev->rx_rule)
|
||||
if (!ndev->rx_rule_ucast)
|
||||
return;
|
||||
|
||||
mlx5_del_flow_rules(ndev->rx_rule);
|
||||
mlx5_del_flow_rules(ndev->rx_rule_mcast);
|
||||
ndev->rx_rule_mcast = NULL;
|
||||
mlx5_del_flow_rules(ndev->rx_rule_ucast);
|
||||
ndev->rx_rule_ucast = NULL;
|
||||
mlx5_fc_destroy(ndev->mvdev.mdev, ndev->rx_counter);
|
||||
mlx5_destroy_flow_table(ndev->rxft);
|
||||
|
||||
ndev->rx_rule = NULL;
|
||||
}
|
||||
|
||||
static virtio_net_ctrl_ack handle_ctrl_mac(struct mlx5_vdpa_dev *mvdev, u8 cmd)
|
||||
@@ -2194,7 +2235,6 @@ static int mlx5_vdpa_reset(struct vdpa_device *vdev)
|
||||
clear_vqs_ready(ndev);
|
||||
mlx5_vdpa_destroy_mr(&ndev->mvdev);
|
||||
ndev->mvdev.status = 0;
|
||||
ndev->mvdev.mlx_features = 0;
|
||||
memset(ndev->event_cbs, 0, sizeof(ndev->event_cbs));
|
||||
ndev->mvdev.actual_features = 0;
|
||||
++mvdev->generation;
|
||||
@@ -2482,7 +2522,8 @@ static int event_handler(struct notifier_block *nb, unsigned long event, void *p
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name)
|
||||
static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
|
||||
const struct vdpa_dev_set_config *add_config)
|
||||
{
|
||||
struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev);
|
||||
struct virtio_net_config *config;
|
||||
@@ -2524,17 +2565,20 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name)
|
||||
goto err_mtu;
|
||||
|
||||
ndev->config.mtu = cpu_to_mlx5vdpa16(mvdev, mtu);
|
||||
ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP);
|
||||
|
||||
err = mlx5_query_nic_vport_mac_address(mdev, 0, 0, config->mac);
|
||||
if (err)
|
||||
goto err_mtu;
|
||||
|
||||
if (get_link_state(mvdev))
|
||||
ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP);
|
||||
else
|
||||
ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP);
|
||||
|
||||
if (add_config->mask & (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR)) {
|
||||
memcpy(ndev->config.mac, add_config->net.mac, ETH_ALEN);
|
||||
} else {
|
||||
err = mlx5_query_nic_vport_mac_address(mdev, 0, 0, config->mac);
|
||||
if (err)
|
||||
goto err_mtu;
|
||||
}
|
||||
|
||||
if (!is_zero_ether_addr(config->mac)) {
|
||||
pfmdev = pci_get_drvdata(pci_physfn(mdev->pdev));
|
||||
err = mlx5_mpfs_add_mac(pfmdev, config->mac);
|
||||
@@ -2632,6 +2676,7 @@ static int mlx5v_probe(struct auxiliary_device *adev,
|
||||
mgtdev->mgtdev.ops = &mdev_ops;
|
||||
mgtdev->mgtdev.device = mdev->device;
|
||||
mgtdev->mgtdev.id_table = id_table;
|
||||
mgtdev->mgtdev.config_attr_mask = (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR);
|
||||
mgtdev->madev = madev;
|
||||
|
||||
err = vdpa_mgmtdev_register(&mgtdev->mgtdev);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <uapi/linux/vdpa.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/virtio_ids.h>
|
||||
|
||||
static LIST_HEAD(mdev_head);
|
||||
/* A global mutex that protects vdpa management device and device level operations. */
|
||||
@@ -66,6 +67,7 @@ static void vdpa_release_dev(struct device *d)
|
||||
ops->free(vdev);
|
||||
|
||||
ida_simple_remove(&vdpa_index_ida, vdev->index);
|
||||
mutex_destroy(&vdev->cf_mutex);
|
||||
kfree(vdev);
|
||||
}
|
||||
|
||||
@@ -127,6 +129,7 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
|
||||
if (err)
|
||||
goto err_name;
|
||||
|
||||
mutex_init(&vdev->cf_mutex);
|
||||
device_initialize(&vdev->dev);
|
||||
|
||||
return vdev;
|
||||
@@ -297,6 +300,46 @@ void vdpa_mgmtdev_unregister(struct vdpa_mgmt_dev *mdev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vdpa_mgmtdev_unregister);
|
||||
|
||||
/**
|
||||
* vdpa_get_config - Get one or more device configuration fields.
|
||||
* @vdev: vdpa device to operate on
|
||||
* @offset: starting byte offset of the field
|
||||
* @buf: buffer pointer to read to
|
||||
* @len: length of the configuration fields in bytes
|
||||
*/
|
||||
void vdpa_get_config(struct vdpa_device *vdev, unsigned int offset,
|
||||
void *buf, unsigned int len)
|
||||
{
|
||||
const struct vdpa_config_ops *ops = vdev->config;
|
||||
|
||||
mutex_lock(&vdev->cf_mutex);
|
||||
/*
|
||||
* Config accesses aren't supposed to trigger before features are set.
|
||||
* If it does happen we assume a legacy guest.
|
||||
*/
|
||||
if (!vdev->features_valid)
|
||||
vdpa_set_features(vdev, 0);
|
||||
ops->get_config(vdev, offset, buf, len);
|
||||
mutex_unlock(&vdev->cf_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vdpa_get_config);
|
||||
|
||||
/**
|
||||
* vdpa_set_config - Set one or more device configuration fields.
|
||||
* @vdev: vdpa device to operate on
|
||||
* @offset: starting byte offset of the field
|
||||
* @buf: buffer pointer to read from
|
||||
* @length: length of the configuration fields in bytes
|
||||
*/
|
||||
void vdpa_set_config(struct vdpa_device *vdev, unsigned int offset,
|
||||
const void *buf, unsigned int length)
|
||||
{
|
||||
mutex_lock(&vdev->cf_mutex);
|
||||
vdev->config->set_config(vdev, offset, buf, length);
|
||||
mutex_unlock(&vdev->cf_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vdpa_set_config);
|
||||
|
||||
static bool mgmtdev_handle_match(const struct vdpa_mgmt_dev *mdev,
|
||||
const char *busname, const char *devname)
|
||||
{
|
||||
@@ -436,9 +479,15 @@ out:
|
||||
return msg->len;
|
||||
}
|
||||
|
||||
#define VDPA_DEV_NET_ATTRS_MASK ((1 << VDPA_ATTR_DEV_NET_CFG_MACADDR) | \
|
||||
(1 << VDPA_ATTR_DEV_NET_CFG_MTU))
|
||||
|
||||
static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct vdpa_dev_set_config config = {};
|
||||
struct nlattr **nl_attrs = info->attrs;
|
||||
struct vdpa_mgmt_dev *mdev;
|
||||
const u8 *macaddr;
|
||||
const char *name;
|
||||
int err = 0;
|
||||
|
||||
@@ -447,6 +496,26 @@ static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *i
|
||||
|
||||
name = nla_data(info->attrs[VDPA_ATTR_DEV_NAME]);
|
||||
|
||||
if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MACADDR]) {
|
||||
macaddr = nla_data(nl_attrs[VDPA_ATTR_DEV_NET_CFG_MACADDR]);
|
||||
memcpy(config.net.mac, macaddr, sizeof(config.net.mac));
|
||||
config.mask |= (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR);
|
||||
}
|
||||
if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MTU]) {
|
||||
config.net.mtu =
|
||||
nla_get_u16(nl_attrs[VDPA_ATTR_DEV_NET_CFG_MTU]);
|
||||
config.mask |= (1 << VDPA_ATTR_DEV_NET_CFG_MTU);
|
||||
}
|
||||
|
||||
/* Skip checking capability if user didn't prefer to configure any
|
||||
* device networking attributes. It is likely that user might have used
|
||||
* a device specific method to configure such attributes or using device
|
||||
* default attributes.
|
||||
*/
|
||||
if ((config.mask & VDPA_DEV_NET_ATTRS_MASK) &&
|
||||
!netlink_capable(skb, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
mutex_lock(&vdpa_dev_mutex);
|
||||
mdev = vdpa_mgmtdev_get_from_attr(info->attrs);
|
||||
if (IS_ERR(mdev)) {
|
||||
@@ -454,8 +523,14 @@ static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *i
|
||||
err = PTR_ERR(mdev);
|
||||
goto err;
|
||||
}
|
||||
if ((config.mask & mdev->config_attr_mask) != config.mask) {
|
||||
NL_SET_ERR_MSG_MOD(info->extack,
|
||||
"All provided attributes are not supported");
|
||||
err = -EOPNOTSUPP;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err = mdev->ops->dev_add(mdev, name);
|
||||
err = mdev->ops->dev_add(mdev, name, &config);
|
||||
err:
|
||||
mutex_unlock(&vdpa_dev_mutex);
|
||||
return err;
|
||||
@@ -625,10 +700,175 @@ 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,
|
||||
const struct virtio_net_config *config)
|
||||
{
|
||||
u16 val_u16;
|
||||
|
||||
if ((features & (1ULL << VIRTIO_NET_F_MQ)) == 0)
|
||||
return 0;
|
||||
|
||||
val_u16 = le16_to_cpu(config->max_virtqueue_pairs);
|
||||
return nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_MAX_VQP, val_u16);
|
||||
}
|
||||
|
||||
static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *msg)
|
||||
{
|
||||
struct virtio_net_config config = {};
|
||||
u64 features;
|
||||
u16 val_u16;
|
||||
|
||||
vdpa_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 = le16_to_cpu(config.status);
|
||||
if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_STATUS, val_u16))
|
||||
return -EMSGSIZE;
|
||||
|
||||
val_u16 = le16_to_cpu(config.mtu);
|
||||
if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_MTU, val_u16))
|
||||
return -EMSGSIZE;
|
||||
|
||||
features = vdev->config->get_features(vdev);
|
||||
|
||||
return vdpa_dev_net_mq_config_fill(vdev, msg, features, &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)
|
||||
{
|
||||
u32 device_id;
|
||||
void *hdr;
|
||||
int err;
|
||||
|
||||
hdr = genlmsg_put(msg, portid, seq, &vdpa_nl_family, flags,
|
||||
VDPA_CMD_DEV_CONFIG_GET);
|
||||
if (!hdr)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (nla_put_string(msg, VDPA_ATTR_DEV_NAME, dev_name(&vdev->dev))) {
|
||||
err = -EMSGSIZE;
|
||||
goto msg_err;
|
||||
}
|
||||
|
||||
device_id = vdev->config->get_device_id(vdev);
|
||||
if (nla_put_u32(msg, VDPA_ATTR_DEV_ID, device_id)) {
|
||||
err = -EMSGSIZE;
|
||||
goto msg_err;
|
||||
}
|
||||
|
||||
switch (device_id) {
|
||||
case VIRTIO_ID_NET:
|
||||
err = vdpa_dev_net_config_fill(vdev, msg);
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
if (err)
|
||||
goto msg_err;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
msg_err:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vdpa_nl_cmd_dev_config_get_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct vdpa_device *vdev;
|
||||
struct sk_buff *msg;
|
||||
const char *devname;
|
||||
struct device *dev;
|
||||
int err;
|
||||
|
||||
if (!info->attrs[VDPA_ATTR_DEV_NAME])
|
||||
return -EINVAL;
|
||||
devname = nla_data(info->attrs[VDPA_ATTR_DEV_NAME]);
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&vdpa_dev_mutex);
|
||||
dev = bus_find_device(&vdpa_bus, NULL, devname, vdpa_name_match);
|
||||
if (!dev) {
|
||||
NL_SET_ERR_MSG_MOD(info->extack, "device not found");
|
||||
err = -ENODEV;
|
||||
goto dev_err;
|
||||
}
|
||||
vdev = container_of(dev, struct vdpa_device, dev);
|
||||
if (!vdev->mdev) {
|
||||
NL_SET_ERR_MSG_MOD(info->extack, "unmanaged vdpa device");
|
||||
err = -EINVAL;
|
||||
goto mdev_err;
|
||||
}
|
||||
err = vdpa_dev_config_fill(vdev, msg, info->snd_portid, info->snd_seq,
|
||||
0, info->extack);
|
||||
if (!err)
|
||||
err = genlmsg_reply(msg, info);
|
||||
|
||||
mdev_err:
|
||||
put_device(dev);
|
||||
dev_err:
|
||||
mutex_unlock(&vdpa_dev_mutex);
|
||||
if (err)
|
||||
nlmsg_free(msg);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vdpa_dev_config_dump(struct device *dev, void *data)
|
||||
{
|
||||
struct vdpa_device *vdev = container_of(dev, struct vdpa_device, dev);
|
||||
struct vdpa_dev_dump_info *info = data;
|
||||
int err;
|
||||
|
||||
if (!vdev->mdev)
|
||||
return 0;
|
||||
if (info->idx < info->start_idx) {
|
||||
info->idx++;
|
||||
return 0;
|
||||
}
|
||||
err = vdpa_dev_config_fill(vdev, info->msg, NETLINK_CB(info->cb->skb).portid,
|
||||
info->cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
info->cb->extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
info->idx++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vdpa_nl_cmd_dev_config_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
{
|
||||
struct vdpa_dev_dump_info info;
|
||||
|
||||
info.msg = msg;
|
||||
info.cb = cb;
|
||||
info.start_idx = cb->args[0];
|
||||
info.idx = 0;
|
||||
|
||||
mutex_lock(&vdpa_dev_mutex);
|
||||
bus_for_each_dev(&vdpa_bus, NULL, &info, vdpa_dev_config_dump);
|
||||
mutex_unlock(&vdpa_dev_mutex);
|
||||
cb->args[0] = info.idx;
|
||||
return msg->len;
|
||||
}
|
||||
|
||||
static const struct nla_policy vdpa_nl_policy[VDPA_ATTR_MAX + 1] = {
|
||||
[VDPA_ATTR_MGMTDEV_BUS_NAME] = { .type = NLA_NUL_STRING },
|
||||
[VDPA_ATTR_MGMTDEV_DEV_NAME] = { .type = NLA_STRING },
|
||||
[VDPA_ATTR_DEV_NAME] = { .type = NLA_STRING },
|
||||
[VDPA_ATTR_DEV_NET_CFG_MACADDR] = NLA_POLICY_ETH_ADDR,
|
||||
/* virtio spec 1.1 section 5.1.4.1 for valid MTU range */
|
||||
[VDPA_ATTR_DEV_NET_CFG_MTU] = NLA_POLICY_MIN(NLA_U16, 68),
|
||||
};
|
||||
|
||||
static const struct genl_ops vdpa_nl_ops[] = {
|
||||
@@ -656,6 +896,12 @@ static const struct genl_ops vdpa_nl_ops[] = {
|
||||
.doit = vdpa_nl_cmd_dev_get_doit,
|
||||
.dumpit = vdpa_nl_cmd_dev_get_dumpit,
|
||||
},
|
||||
{
|
||||
.cmd = VDPA_CMD_DEV_CONFIG_GET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = vdpa_nl_cmd_dev_config_get_doit,
|
||||
.dumpit = vdpa_nl_cmd_dev_config_get_dumpit,
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_family vdpa_nl_family __ro_after_init = {
|
||||
|
||||
@@ -248,7 +248,8 @@ static struct device vdpasim_blk_mgmtdev = {
|
||||
.release = vdpasim_blk_mgmtdev_release,
|
||||
};
|
||||
|
||||
static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name)
|
||||
static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
|
||||
const struct vdpa_dev_set_config *config)
|
||||
{
|
||||
struct vdpasim_dev_attr dev_attr = {};
|
||||
struct vdpasim *simdev;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/vringh.h>
|
||||
#include <linux/vdpa.h>
|
||||
#include <uapi/linux/virtio_net.h>
|
||||
#include <uapi/linux/vdpa.h>
|
||||
|
||||
#include "vdpa_sim.h"
|
||||
|
||||
@@ -29,12 +30,6 @@
|
||||
|
||||
#define VDPASIM_NET_VQ_NUM 2
|
||||
|
||||
static char *macaddr;
|
||||
module_param(macaddr, charp, 0);
|
||||
MODULE_PARM_DESC(macaddr, "Ethernet MAC address");
|
||||
|
||||
static u8 macaddr_buf[ETH_ALEN];
|
||||
|
||||
static void vdpasim_net_work(struct work_struct *work)
|
||||
{
|
||||
struct vdpasim *vdpasim = container_of(work, struct vdpasim, work);
|
||||
@@ -112,9 +107,21 @@ static void vdpasim_net_get_config(struct vdpasim *vdpasim, void *config)
|
||||
{
|
||||
struct virtio_net_config *net_config = config;
|
||||
|
||||
net_config->mtu = cpu_to_vdpasim16(vdpasim, 1500);
|
||||
net_config->status = cpu_to_vdpasim16(vdpasim, VIRTIO_NET_S_LINK_UP);
|
||||
memcpy(net_config->mac, macaddr_buf, ETH_ALEN);
|
||||
}
|
||||
|
||||
static void vdpasim_net_setup_config(struct vdpasim *vdpasim,
|
||||
const struct vdpa_dev_set_config *config)
|
||||
{
|
||||
struct virtio_net_config *vio_config = vdpasim->config;
|
||||
|
||||
if (config->mask & (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR))
|
||||
memcpy(vio_config->mac, config->net.mac, ETH_ALEN);
|
||||
if (config->mask & (1 << VDPA_ATTR_DEV_NET_CFG_MTU))
|
||||
vio_config->mtu = cpu_to_vdpasim16(vdpasim, config->net.mtu);
|
||||
else
|
||||
/* Setup default MTU to be 1500 */
|
||||
vio_config->mtu = cpu_to_vdpasim16(vdpasim, 1500);
|
||||
}
|
||||
|
||||
static void vdpasim_net_mgmtdev_release(struct device *dev)
|
||||
@@ -126,7 +133,8 @@ static struct device vdpasim_net_mgmtdev = {
|
||||
.release = vdpasim_net_mgmtdev_release,
|
||||
};
|
||||
|
||||
static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name)
|
||||
static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
|
||||
const struct vdpa_dev_set_config *config)
|
||||
{
|
||||
struct vdpasim_dev_attr dev_attr = {};
|
||||
struct vdpasim *simdev;
|
||||
@@ -146,6 +154,8 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name)
|
||||
if (IS_ERR(simdev))
|
||||
return PTR_ERR(simdev);
|
||||
|
||||
vdpasim_net_setup_config(simdev, config);
|
||||
|
||||
ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_NET_VQ_NUM);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
@@ -179,20 +189,14 @@ static struct vdpa_mgmt_dev mgmt_dev = {
|
||||
.device = &vdpasim_net_mgmtdev,
|
||||
.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),
|
||||
};
|
||||
|
||||
static int __init vdpasim_net_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (macaddr) {
|
||||
mac_pton(macaddr, macaddr_buf);
|
||||
if (!is_valid_ether_addr(macaddr_buf))
|
||||
return -EADDRNOTAVAIL;
|
||||
} else {
|
||||
eth_random_addr(macaddr_buf);
|
||||
}
|
||||
|
||||
ret = device_register(&vdpasim_net_mgmtdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1503,7 +1503,8 @@ static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name)
|
||||
static int vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
|
||||
const struct vdpa_dev_set_config *config)
|
||||
{
|
||||
struct vduse_dev *dev;
|
||||
int ret;
|
||||
|
||||
@@ -237,7 +237,6 @@ static long vhost_vdpa_set_config(struct vhost_vdpa *v,
|
||||
struct vhost_vdpa_config __user *c)
|
||||
{
|
||||
struct vdpa_device *vdpa = v->vdpa;
|
||||
const struct vdpa_config_ops *ops = vdpa->config;
|
||||
struct vhost_vdpa_config config;
|
||||
unsigned long size = offsetof(struct vhost_vdpa_config, buf);
|
||||
u8 *buf;
|
||||
@@ -251,7 +250,7 @@ static long vhost_vdpa_set_config(struct vhost_vdpa *v,
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
|
||||
ops->set_config(vdpa, config.off, buf, config.len);
|
||||
vdpa_set_config(vdpa, config.off, buf, config.len);
|
||||
|
||||
kvfree(buf);
|
||||
return 0;
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <xen/xen.h>
|
||||
|
||||
static bool force_used_validation = false;
|
||||
module_param(force_used_validation, bool, 0444);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* For development, we want to crash whenever the ring is screwed. */
|
||||
#define BAD_RING(_vq, fmt, args...) \
|
||||
@@ -182,6 +185,9 @@ struct vring_virtqueue {
|
||||
} packed;
|
||||
};
|
||||
|
||||
/* Per-descriptor in buffer length */
|
||||
u32 *buflen;
|
||||
|
||||
/* How to notify other side. FIXME: commonalize hcalls! */
|
||||
bool (*notify)(struct virtqueue *vq);
|
||||
|
||||
@@ -490,6 +496,7 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
|
||||
unsigned int i, n, avail, descs_used, prev, err_idx;
|
||||
int head;
|
||||
bool indirect;
|
||||
u32 buflen = 0;
|
||||
|
||||
START_USE(vq);
|
||||
|
||||
@@ -571,6 +578,7 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
|
||||
VRING_DESC_F_NEXT |
|
||||
VRING_DESC_F_WRITE,
|
||||
indirect);
|
||||
buflen += sg->length;
|
||||
}
|
||||
}
|
||||
/* Last one doesn't continue. */
|
||||
@@ -610,6 +618,10 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
|
||||
else
|
||||
vq->split.desc_state[head].indir_desc = ctx;
|
||||
|
||||
/* Store in buffer length if necessary */
|
||||
if (vq->buflen)
|
||||
vq->buflen[head] = buflen;
|
||||
|
||||
/* Put entry in available array (but don't update avail->idx until they
|
||||
* do sync). */
|
||||
avail = vq->split.avail_idx_shadow & (vq->split.vring.num - 1);
|
||||
@@ -784,6 +796,11 @@ static void *virtqueue_get_buf_ctx_split(struct virtqueue *_vq,
|
||||
BAD_RING(vq, "id %u is not a head!\n", i);
|
||||
return NULL;
|
||||
}
|
||||
if (vq->buflen && unlikely(*len > vq->buflen[i])) {
|
||||
BAD_RING(vq, "used len %d is larger than in buflen %u\n",
|
||||
*len, vq->buflen[i]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* detach_buf_split clears data, so grab it now. */
|
||||
ret = vq->split.desc_state[i].data;
|
||||
@@ -1062,6 +1079,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
|
||||
unsigned int i, n, err_idx;
|
||||
u16 head, id;
|
||||
dma_addr_t addr;
|
||||
u32 buflen = 0;
|
||||
|
||||
head = vq->packed.next_avail_idx;
|
||||
desc = alloc_indirect_packed(total_sg, gfp);
|
||||
@@ -1091,6 +1109,8 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
|
||||
desc[i].addr = cpu_to_le64(addr);
|
||||
desc[i].len = cpu_to_le32(sg->length);
|
||||
i++;
|
||||
if (n >= out_sgs)
|
||||
buflen += sg->length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1144,6 +1164,10 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
|
||||
vq->packed.desc_state[id].indir_desc = desc;
|
||||
vq->packed.desc_state[id].last = id;
|
||||
|
||||
/* Store in buffer length if necessary */
|
||||
if (vq->buflen)
|
||||
vq->buflen[id] = buflen;
|
||||
|
||||
vq->num_added += 1;
|
||||
|
||||
pr_debug("Added buffer head %i to %p\n", head, vq);
|
||||
@@ -1179,6 +1203,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
|
||||
__le16 head_flags, flags;
|
||||
u16 head, id, prev, curr, avail_used_flags;
|
||||
int err;
|
||||
u32 buflen = 0;
|
||||
|
||||
START_USE(vq);
|
||||
|
||||
@@ -1258,6 +1283,8 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
|
||||
1 << VRING_PACKED_DESC_F_AVAIL |
|
||||
1 << VRING_PACKED_DESC_F_USED;
|
||||
}
|
||||
if (n >= out_sgs)
|
||||
buflen += sg->length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1277,6 +1304,10 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
|
||||
vq->packed.desc_state[id].indir_desc = ctx;
|
||||
vq->packed.desc_state[id].last = prev;
|
||||
|
||||
/* Store in buffer length if necessary */
|
||||
if (vq->buflen)
|
||||
vq->buflen[id] = buflen;
|
||||
|
||||
/*
|
||||
* A driver MUST NOT make the first descriptor in the list
|
||||
* available before all subsequent descriptors comprising
|
||||
@@ -1463,6 +1494,11 @@ static void *virtqueue_get_buf_ctx_packed(struct virtqueue *_vq,
|
||||
BAD_RING(vq, "id %u is not a head!\n", id);
|
||||
return NULL;
|
||||
}
|
||||
if (vq->buflen && unlikely(*len > vq->buflen[id])) {
|
||||
BAD_RING(vq, "used len %d is larger than in buflen %u\n",
|
||||
*len, vq->buflen[id]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* detach_buf_packed clears data, so grab it now. */
|
||||
ret = vq->packed.desc_state[id].data;
|
||||
@@ -1668,6 +1704,7 @@ static struct virtqueue *vring_create_virtqueue_packed(
|
||||
struct vring_virtqueue *vq;
|
||||
struct vring_packed_desc *ring;
|
||||
struct vring_packed_desc_event *driver, *device;
|
||||
struct virtio_driver *drv = drv_to_virtio(vdev->dev.driver);
|
||||
dma_addr_t ring_dma_addr, driver_event_dma_addr, device_event_dma_addr;
|
||||
size_t ring_size_in_bytes, event_size_in_bytes;
|
||||
|
||||
@@ -1757,6 +1794,15 @@ static struct virtqueue *vring_create_virtqueue_packed(
|
||||
if (!vq->packed.desc_extra)
|
||||
goto err_desc_extra;
|
||||
|
||||
if (!drv->suppress_used_validation || force_used_validation) {
|
||||
vq->buflen = kmalloc_array(num, sizeof(*vq->buflen),
|
||||
GFP_KERNEL);
|
||||
if (!vq->buflen)
|
||||
goto err_buflen;
|
||||
} else {
|
||||
vq->buflen = NULL;
|
||||
}
|
||||
|
||||
/* No callback? Tell other side not to bother us. */
|
||||
if (!callback) {
|
||||
vq->packed.event_flags_shadow = VRING_PACKED_EVENT_FLAG_DISABLE;
|
||||
@@ -1769,6 +1815,8 @@ static struct virtqueue *vring_create_virtqueue_packed(
|
||||
spin_unlock(&vdev->vqs_list_lock);
|
||||
return &vq->vq;
|
||||
|
||||
err_buflen:
|
||||
kfree(vq->packed.desc_extra);
|
||||
err_desc_extra:
|
||||
kfree(vq->packed.desc_state);
|
||||
err_desc_state:
|
||||
@@ -2176,6 +2224,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
|
||||
void (*callback)(struct virtqueue *),
|
||||
const char *name)
|
||||
{
|
||||
struct virtio_driver *drv = drv_to_virtio(vdev->dev.driver);
|
||||
struct vring_virtqueue *vq;
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
|
||||
@@ -2235,6 +2284,15 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
|
||||
if (!vq->split.desc_extra)
|
||||
goto err_extra;
|
||||
|
||||
if (!drv->suppress_used_validation || force_used_validation) {
|
||||
vq->buflen = kmalloc_array(vring.num, sizeof(*vq->buflen),
|
||||
GFP_KERNEL);
|
||||
if (!vq->buflen)
|
||||
goto err_buflen;
|
||||
} else {
|
||||
vq->buflen = NULL;
|
||||
}
|
||||
|
||||
/* Put everything in free lists. */
|
||||
vq->free_head = 0;
|
||||
memset(vq->split.desc_state, 0, vring.num *
|
||||
@@ -2245,6 +2303,8 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
|
||||
spin_unlock(&vdev->vqs_list_lock);
|
||||
return &vq->vq;
|
||||
|
||||
err_buflen:
|
||||
kfree(vq->split.desc_extra);
|
||||
err_extra:
|
||||
kfree(vq->split.desc_state);
|
||||
err_state:
|
||||
|
||||
@@ -65,9 +65,8 @@ static void virtio_vdpa_set(struct virtio_device *vdev, unsigned offset,
|
||||
const void *buf, unsigned len)
|
||||
{
|
||||
struct vdpa_device *vdpa = vd_get_vdpa(vdev);
|
||||
const struct vdpa_config_ops *ops = vdpa->config;
|
||||
|
||||
ops->set_config(vdpa, offset, buf, len);
|
||||
vdpa_set_config(vdpa, offset, buf, len);
|
||||
}
|
||||
|
||||
static u32 virtio_vdpa_generation(struct virtio_device *vdev)
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/vhost_iotlb.h>
|
||||
#include <linux/virtio_net.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
/**
|
||||
* struct vdpa_calllback - vDPA callback definition.
|
||||
@@ -63,6 +65,7 @@ struct vdpa_mgmt_dev;
|
||||
* @dev: underlying device
|
||||
* @dma_dev: the actual device that is performing DMA
|
||||
* @config: the configuration ops for this device.
|
||||
* @cf_mutex: Protects get and set access to configuration layout.
|
||||
* @index: device index
|
||||
* @features_valid: were features initialized? for legacy guests
|
||||
* @use_va: indicate whether virtual address must be used by this device
|
||||
@@ -74,6 +77,7 @@ struct vdpa_device {
|
||||
struct device dev;
|
||||
struct device *dma_dev;
|
||||
const struct vdpa_config_ops *config;
|
||||
struct mutex cf_mutex; /* Protects get/set config */
|
||||
unsigned int index;
|
||||
bool features_valid;
|
||||
bool use_va;
|
||||
@@ -91,6 +95,14 @@ struct vdpa_iova_range {
|
||||
u64 last;
|
||||
};
|
||||
|
||||
struct vdpa_dev_set_config {
|
||||
struct {
|
||||
u8 mac[ETH_ALEN];
|
||||
u16 mtu;
|
||||
} net;
|
||||
u64 mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* Corresponding file area for device memory mapping
|
||||
* @file: vma->vm_file for the mapping
|
||||
@@ -386,26 +398,16 @@ static inline int vdpa_set_features(struct vdpa_device *vdev, u64 features)
|
||||
return ops->set_features(vdev, features);
|
||||
}
|
||||
|
||||
static inline void vdpa_get_config(struct vdpa_device *vdev,
|
||||
unsigned int offset, void *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
const struct vdpa_config_ops *ops = vdev->config;
|
||||
|
||||
/*
|
||||
* Config accesses aren't supposed to trigger before features are set.
|
||||
* If it does happen we assume a legacy guest.
|
||||
*/
|
||||
if (!vdev->features_valid)
|
||||
vdpa_set_features(vdev, 0);
|
||||
ops->get_config(vdev, offset, buf, len);
|
||||
}
|
||||
|
||||
void vdpa_get_config(struct vdpa_device *vdev, unsigned int offset,
|
||||
void *buf, unsigned int len);
|
||||
void vdpa_set_config(struct vdpa_device *dev, unsigned int offset,
|
||||
const void *buf, unsigned int length);
|
||||
/**
|
||||
* struct vdpa_mgmtdev_ops - vdpa device ops
|
||||
* @dev_add: Add a vdpa device using alloc and register
|
||||
* @mdev: parent device to use for device addition
|
||||
* @name: name of the new vdpa device
|
||||
* @config: config attributes to apply to the device under creation
|
||||
* Driver need to add a new device using _vdpa_register_device()
|
||||
* after fully initializing the vdpa device. Driver must return 0
|
||||
* on success or appropriate error code.
|
||||
@@ -416,14 +418,25 @@ static inline void vdpa_get_config(struct vdpa_device *vdev,
|
||||
* _vdpa_unregister_device().
|
||||
*/
|
||||
struct vdpa_mgmtdev_ops {
|
||||
int (*dev_add)(struct vdpa_mgmt_dev *mdev, const char *name);
|
||||
int (*dev_add)(struct vdpa_mgmt_dev *mdev, const char *name,
|
||||
const struct vdpa_dev_set_config *config);
|
||||
void (*dev_del)(struct vdpa_mgmt_dev *mdev, struct vdpa_device *dev);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vdpa_mgmt_dev - vdpa management device
|
||||
* @device: Management parent device
|
||||
* @ops: operations supported by management device
|
||||
* @id_table: Pointer to device id table of supported ids
|
||||
* @config_attr_mask: bit mask of attributes of type enum vdpa_attr that
|
||||
* management device support during dev_add callback
|
||||
* @list: list entry
|
||||
*/
|
||||
struct vdpa_mgmt_dev {
|
||||
struct device *device;
|
||||
const struct vdpa_mgmtdev_ops *ops;
|
||||
const struct virtio_device_id *id_table; /* supported ids */
|
||||
const struct virtio_device_id *id_table;
|
||||
u64 config_attr_mask;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
||||
@@ -152,6 +152,7 @@ size_t virtio_max_dma_size(struct virtio_device *vdev);
|
||||
* @feature_table_size: number of entries in the feature table array.
|
||||
* @feature_table_legacy: same as feature_table but when working in legacy mode.
|
||||
* @feature_table_size_legacy: number of entries in feature table legacy array.
|
||||
* @suppress_used_validation: set to not have core validate used length
|
||||
* @probe: the function to call when a device is found. Returns 0 or -errno.
|
||||
* @scan: optional function to call after successful probe; intended
|
||||
* for virtio-scsi to invoke a scan.
|
||||
@@ -168,6 +169,7 @@ struct virtio_driver {
|
||||
unsigned int feature_table_size;
|
||||
const unsigned int *feature_table_legacy;
|
||||
unsigned int feature_table_size_legacy;
|
||||
bool suppress_used_validation;
|
||||
int (*validate)(struct virtio_device *dev);
|
||||
int (*probe)(struct virtio_device *dev);
|
||||
void (*scan)(struct virtio_device *dev);
|
||||
|
||||
@@ -17,6 +17,7 @@ enum vdpa_command {
|
||||
VDPA_CMD_DEV_NEW,
|
||||
VDPA_CMD_DEV_DEL,
|
||||
VDPA_CMD_DEV_GET, /* can dump */
|
||||
VDPA_CMD_DEV_CONFIG_GET, /* can dump */
|
||||
};
|
||||
|
||||
enum vdpa_attr {
|
||||
@@ -34,6 +35,11 @@ enum vdpa_attr {
|
||||
VDPA_ATTR_DEV_MAX_VQ_SIZE, /* u16 */
|
||||
VDPA_ATTR_DEV_MIN_VQ_SIZE, /* u16 */
|
||||
|
||||
VDPA_ATTR_DEV_NET_CFG_MACADDR, /* binary */
|
||||
VDPA_ATTR_DEV_NET_STATUS, /* u8 */
|
||||
VDPA_ATTR_DEV_NET_CFG_MAX_VQP, /* u16 */
|
||||
VDPA_ATTR_DEV_NET_CFG_MTU, /* u16 */
|
||||
|
||||
/* new attributes must be added above here */
|
||||
VDPA_ATTR_MAX,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user