forked from Minki/linux
netdevsim: move device registration and related code to bus.c
Move netdevsim device registration into bus.c and alongside with that the related sysfs attributes. Introduce new struct nsim_bus_dev to represent a netdevsim device on netdevsim bus. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
925f5afedb
commit
40e4fe4ce1
@ -4,15 +4,155 @@
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include "netdevsim.h"
|
||||
|
||||
struct bus_type nsim_bus = {
|
||||
static u32 nsim_bus_dev_id;
|
||||
|
||||
static struct nsim_bus_dev *to_nsim_bus_dev(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct nsim_bus_dev, dev);
|
||||
}
|
||||
|
||||
static int nsim_bus_dev_vfs_enable(struct nsim_bus_dev *nsim_bus_dev,
|
||||
unsigned int num_vfs)
|
||||
{
|
||||
nsim_bus_dev->vfconfigs = kcalloc(num_vfs,
|
||||
sizeof(struct nsim_vf_config),
|
||||
GFP_KERNEL);
|
||||
if (!nsim_bus_dev->vfconfigs)
|
||||
return -ENOMEM;
|
||||
nsim_bus_dev->num_vfs = num_vfs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nsim_bus_dev_vfs_disable(struct nsim_bus_dev *nsim_bus_dev)
|
||||
{
|
||||
kfree(nsim_bus_dev->vfconfigs);
|
||||
nsim_bus_dev->vfconfigs = NULL;
|
||||
nsim_bus_dev->num_vfs = 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
|
||||
unsigned int num_vfs;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 0, &num_vfs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rtnl_lock();
|
||||
if (nsim_bus_dev->num_vfs == num_vfs)
|
||||
goto exit_good;
|
||||
if (nsim_bus_dev->num_vfs && num_vfs) {
|
||||
ret = -EBUSY;
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
if (num_vfs) {
|
||||
ret = nsim_bus_dev_vfs_enable(nsim_bus_dev, num_vfs);
|
||||
if (ret)
|
||||
goto exit_unlock;
|
||||
} else {
|
||||
nsim_bus_dev_vfs_disable(nsim_bus_dev);
|
||||
}
|
||||
exit_good:
|
||||
ret = count;
|
||||
exit_unlock:
|
||||
rtnl_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
nsim_bus_dev_numvfs_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", nsim_bus_dev->num_vfs);
|
||||
}
|
||||
|
||||
static struct device_attribute nsim_bus_dev_numvfs_attr =
|
||||
__ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show,
|
||||
nsim_bus_dev_numvfs_store);
|
||||
|
||||
static struct attribute *nsim_bus_dev_attrs[] = {
|
||||
&nsim_bus_dev_numvfs_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group nsim_bus_dev_attr_group = {
|
||||
.attrs = nsim_bus_dev_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *nsim_bus_dev_attr_groups[] = {
|
||||
&nsim_bus_dev_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void nsim_bus_dev_release(struct device *dev)
|
||||
{
|
||||
struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
|
||||
|
||||
nsim_bus_dev_vfs_disable(nsim_bus_dev);
|
||||
}
|
||||
|
||||
static struct device_type nsim_bus_dev_type = {
|
||||
.groups = nsim_bus_dev_attr_groups,
|
||||
.release = nsim_bus_dev_release,
|
||||
};
|
||||
|
||||
int nsim_num_vf(struct device *dev)
|
||||
{
|
||||
struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
|
||||
|
||||
return nsim_bus_dev->num_vfs;
|
||||
}
|
||||
|
||||
static struct bus_type nsim_bus = {
|
||||
.name = DRV_NAME,
|
||||
.dev_name = DRV_NAME,
|
||||
.num_vf = nsim_num_vf,
|
||||
};
|
||||
|
||||
struct nsim_bus_dev *nsim_bus_dev_new(void)
|
||||
{
|
||||
struct nsim_bus_dev *nsim_bus_dev;
|
||||
int err;
|
||||
|
||||
nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL);
|
||||
if (!nsim_bus_dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
nsim_bus_dev->dev.id = nsim_bus_dev_id++;
|
||||
nsim_bus_dev->dev.bus = &nsim_bus;
|
||||
nsim_bus_dev->dev.type = &nsim_bus_dev_type;
|
||||
err = device_register(&nsim_bus_dev->dev);
|
||||
if (err)
|
||||
goto err_nsim_bus_dev_free;
|
||||
return nsim_bus_dev;
|
||||
|
||||
err_nsim_bus_dev_free:
|
||||
kfree(nsim_bus_dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev)
|
||||
{
|
||||
device_unregister(&nsim_bus_dev->dev);
|
||||
kfree(nsim_bus_dev);
|
||||
}
|
||||
|
||||
int nsim_bus_init(void)
|
||||
{
|
||||
return bus_register(&nsim_bus);
|
||||
|
@ -199,7 +199,7 @@ static int __nsim_dev_init(struct netdevsim *ns)
|
||||
if (err)
|
||||
goto err_fib_destroy;
|
||||
|
||||
err = devlink_register(devlink, &ns->dev);
|
||||
err = devlink_register(devlink, &ns->nsim_bus_dev->dev);
|
||||
if (err)
|
||||
goto err_resources_unregister;
|
||||
|
||||
|
@ -25,120 +25,8 @@
|
||||
|
||||
#include "netdevsim.h"
|
||||
|
||||
static u32 nsim_dev_id;
|
||||
|
||||
struct nsim_vf_config {
|
||||
int link_state;
|
||||
u16 min_tx_rate;
|
||||
u16 max_tx_rate;
|
||||
u16 vlan;
|
||||
__be16 vlan_proto;
|
||||
u16 qos;
|
||||
u8 vf_mac[ETH_ALEN];
|
||||
bool spoofchk_enabled;
|
||||
bool trusted;
|
||||
bool rss_query_enabled;
|
||||
};
|
||||
|
||||
static struct dentry *nsim_ddir;
|
||||
|
||||
int nsim_num_vf(struct device *dev)
|
||||
{
|
||||
struct netdevsim *ns = to_nsim(dev);
|
||||
|
||||
return ns->num_vfs;
|
||||
}
|
||||
|
||||
static int nsim_vfs_enable(struct netdevsim *ns, unsigned int num_vfs)
|
||||
{
|
||||
ns->vfconfigs = kcalloc(num_vfs, sizeof(struct nsim_vf_config),
|
||||
GFP_KERNEL);
|
||||
if (!ns->vfconfigs)
|
||||
return -ENOMEM;
|
||||
ns->num_vfs = num_vfs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nsim_vfs_disable(struct netdevsim *ns)
|
||||
{
|
||||
kfree(ns->vfconfigs);
|
||||
ns->vfconfigs = NULL;
|
||||
ns->num_vfs = 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
nsim_numvfs_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct netdevsim *ns = to_nsim(dev);
|
||||
unsigned int num_vfs;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 0, &num_vfs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rtnl_lock();
|
||||
if (ns->num_vfs == num_vfs)
|
||||
goto exit_good;
|
||||
if (ns->num_vfs && num_vfs) {
|
||||
ret = -EBUSY;
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
if (num_vfs) {
|
||||
ret = nsim_vfs_enable(ns, num_vfs);
|
||||
if (ret)
|
||||
goto exit_unlock;
|
||||
} else {
|
||||
nsim_vfs_disable(ns);
|
||||
}
|
||||
exit_good:
|
||||
ret = count;
|
||||
exit_unlock:
|
||||
rtnl_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
nsim_numvfs_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct netdevsim *ns = to_nsim(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", ns->num_vfs);
|
||||
}
|
||||
|
||||
static struct device_attribute nsim_numvfs_attr =
|
||||
__ATTR(sriov_numvfs, 0664, nsim_numvfs_show, nsim_numvfs_store);
|
||||
|
||||
static struct attribute *nsim_dev_attrs[] = {
|
||||
&nsim_numvfs_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group nsim_dev_attr_group = {
|
||||
.attrs = nsim_dev_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *nsim_dev_attr_groups[] = {
|
||||
&nsim_dev_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void nsim_dev_release(struct device *dev)
|
||||
{
|
||||
struct netdevsim *ns = to_nsim(dev);
|
||||
|
||||
nsim_vfs_disable(ns);
|
||||
}
|
||||
|
||||
static struct device_type nsim_dev_type = {
|
||||
.groups = nsim_dev_attr_groups,
|
||||
.release = nsim_dev_release,
|
||||
};
|
||||
|
||||
static int nsim_get_port_parent_id(struct net_device *dev,
|
||||
struct netdev_phys_item_id *ppid)
|
||||
{
|
||||
@ -190,7 +78,7 @@ static void nsim_free(struct net_device *dev)
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
|
||||
nsim_dev_exit(ns);
|
||||
device_unregister(&ns->dev);
|
||||
nsim_bus_dev_del(ns->nsim_bus_dev);
|
||||
/* netdev and vf state will be freed out of device_release() */
|
||||
nsim_sdev_put(ns->sdev);
|
||||
}
|
||||
@ -271,11 +159,12 @@ nsim_setup_tc_block(struct net_device *dev, struct tc_block_offload *f)
|
||||
static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev;
|
||||
|
||||
/* Only refuse multicast addresses, zero address can mean unset/any. */
|
||||
if (vf >= ns->num_vfs || is_multicast_ether_addr(mac))
|
||||
if (vf >= nsim_bus_dev->num_vfs || is_multicast_ether_addr(mac))
|
||||
return -EINVAL;
|
||||
memcpy(ns->vfconfigs[vf].vf_mac, mac, ETH_ALEN);
|
||||
memcpy(nsim_bus_dev->vfconfigs[vf].vf_mac, mac, ETH_ALEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -284,13 +173,14 @@ static int nsim_set_vf_vlan(struct net_device *dev, int vf,
|
||||
u16 vlan, u8 qos, __be16 vlan_proto)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev;
|
||||
|
||||
if (vf >= ns->num_vfs || vlan > 4095 || qos > 7)
|
||||
if (vf >= nsim_bus_dev->num_vfs || vlan > 4095 || qos > 7)
|
||||
return -EINVAL;
|
||||
|
||||
ns->vfconfigs[vf].vlan = vlan;
|
||||
ns->vfconfigs[vf].qos = qos;
|
||||
ns->vfconfigs[vf].vlan_proto = vlan_proto;
|
||||
nsim_bus_dev->vfconfigs[vf].vlan = vlan;
|
||||
nsim_bus_dev->vfconfigs[vf].qos = qos;
|
||||
nsim_bus_dev->vfconfigs[vf].vlan_proto = vlan_proto;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -298,12 +188,13 @@ static int nsim_set_vf_vlan(struct net_device *dev, int vf,
|
||||
static int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev;
|
||||
|
||||
if (vf >= ns->num_vfs)
|
||||
if (vf >= nsim_bus_dev->num_vfs)
|
||||
return -EINVAL;
|
||||
|
||||
ns->vfconfigs[vf].min_tx_rate = min;
|
||||
ns->vfconfigs[vf].max_tx_rate = max;
|
||||
nsim_bus_dev->vfconfigs[vf].min_tx_rate = min;
|
||||
nsim_bus_dev->vfconfigs[vf].max_tx_rate = max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -311,10 +202,11 @@ static int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max)
|
||||
static int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev;
|
||||
|
||||
if (vf >= ns->num_vfs)
|
||||
if (vf >= nsim_bus_dev->num_vfs)
|
||||
return -EINVAL;
|
||||
ns->vfconfigs[vf].spoofchk_enabled = val;
|
||||
nsim_bus_dev->vfconfigs[vf].spoofchk_enabled = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -322,10 +214,11 @@ static int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val)
|
||||
static int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev;
|
||||
|
||||
if (vf >= ns->num_vfs)
|
||||
if (vf >= nsim_bus_dev->num_vfs)
|
||||
return -EINVAL;
|
||||
ns->vfconfigs[vf].rss_query_enabled = val;
|
||||
nsim_bus_dev->vfconfigs[vf].rss_query_enabled = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -333,10 +226,11 @@ static int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val)
|
||||
static int nsim_set_vf_trust(struct net_device *dev, int vf, bool val)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev;
|
||||
|
||||
if (vf >= ns->num_vfs)
|
||||
if (vf >= nsim_bus_dev->num_vfs)
|
||||
return -EINVAL;
|
||||
ns->vfconfigs[vf].trusted = val;
|
||||
nsim_bus_dev->vfconfigs[vf].trusted = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -345,21 +239,22 @@ static int
|
||||
nsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev;
|
||||
|
||||
if (vf >= ns->num_vfs)
|
||||
if (vf >= nsim_bus_dev->num_vfs)
|
||||
return -EINVAL;
|
||||
|
||||
ivi->vf = vf;
|
||||
ivi->linkstate = ns->vfconfigs[vf].link_state;
|
||||
ivi->min_tx_rate = ns->vfconfigs[vf].min_tx_rate;
|
||||
ivi->max_tx_rate = ns->vfconfigs[vf].max_tx_rate;
|
||||
ivi->vlan = ns->vfconfigs[vf].vlan;
|
||||
ivi->vlan_proto = ns->vfconfigs[vf].vlan_proto;
|
||||
ivi->qos = ns->vfconfigs[vf].qos;
|
||||
memcpy(&ivi->mac, ns->vfconfigs[vf].vf_mac, ETH_ALEN);
|
||||
ivi->spoofchk = ns->vfconfigs[vf].spoofchk_enabled;
|
||||
ivi->trusted = ns->vfconfigs[vf].trusted;
|
||||
ivi->rss_query_en = ns->vfconfigs[vf].rss_query_enabled;
|
||||
ivi->linkstate = nsim_bus_dev->vfconfigs[vf].link_state;
|
||||
ivi->min_tx_rate = nsim_bus_dev->vfconfigs[vf].min_tx_rate;
|
||||
ivi->max_tx_rate = nsim_bus_dev->vfconfigs[vf].max_tx_rate;
|
||||
ivi->vlan = nsim_bus_dev->vfconfigs[vf].vlan;
|
||||
ivi->vlan_proto = nsim_bus_dev->vfconfigs[vf].vlan_proto;
|
||||
ivi->qos = nsim_bus_dev->vfconfigs[vf].qos;
|
||||
memcpy(&ivi->mac, nsim_bus_dev->vfconfigs[vf].vf_mac, ETH_ALEN);
|
||||
ivi->spoofchk = nsim_bus_dev->vfconfigs[vf].spoofchk_enabled;
|
||||
ivi->trusted = nsim_bus_dev->vfconfigs[vf].trusted;
|
||||
ivi->rss_query_en = nsim_bus_dev->vfconfigs[vf].rss_query_enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -367,8 +262,9 @@ nsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi)
|
||||
static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev;
|
||||
|
||||
if (vf >= ns->num_vfs)
|
||||
if (vf >= nsim_bus_dev->num_vfs)
|
||||
return -EINVAL;
|
||||
|
||||
switch (state) {
|
||||
@ -380,7 +276,7 @@ static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ns->vfconfigs[vf].link_state = state;
|
||||
nsim_bus_dev->vfconfigs[vf].link_state = state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -490,19 +386,18 @@ static int nsim_newlink(struct net *src_net, struct net_device *dev,
|
||||
if (IS_ERR(ns->sdev))
|
||||
return PTR_ERR(ns->sdev);
|
||||
|
||||
ns->dev.id = nsim_dev_id++;
|
||||
ns->dev.bus = &nsim_bus;
|
||||
ns->dev.type = &nsim_dev_type;
|
||||
err = device_register(&ns->dev);
|
||||
if (err)
|
||||
ns->nsim_bus_dev = nsim_bus_dev_new();
|
||||
if (IS_ERR(ns->nsim_bus_dev)) {
|
||||
err = PTR_ERR(ns->nsim_bus_dev);
|
||||
goto err_sdev_put;
|
||||
}
|
||||
|
||||
SET_NETDEV_DEV(dev, &ns->dev);
|
||||
SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev);
|
||||
ns->netdev = dev;
|
||||
|
||||
err = nsim_dev_init(ns);
|
||||
if (err)
|
||||
goto err_unreg_dev;
|
||||
goto err_dev_del;
|
||||
|
||||
err = register_netdevice(dev);
|
||||
if (err)
|
||||
@ -511,8 +406,8 @@ static int nsim_newlink(struct net *src_net, struct net_device *dev,
|
||||
|
||||
err_dev_exit:
|
||||
nsim_dev_exit(ns);
|
||||
err_unreg_dev:
|
||||
device_unregister(&ns->dev);
|
||||
err_dev_del:
|
||||
nsim_bus_dev_del(ns->nsim_bus_dev);
|
||||
err_sdev_put:
|
||||
nsim_sdev_put(ns->sdev);
|
||||
return err;
|
||||
|
@ -85,14 +85,11 @@ struct netdevsim {
|
||||
u64 tx_bytes;
|
||||
struct u64_stats_sync syncp;
|
||||
|
||||
struct device dev;
|
||||
struct nsim_bus_dev *nsim_bus_dev;
|
||||
struct netdevsim_shared_dev *sdev;
|
||||
|
||||
struct dentry *ddir;
|
||||
|
||||
unsigned int num_vfs;
|
||||
struct nsim_vf_config *vfconfigs;
|
||||
|
||||
struct bpf_prog *bpf_offloaded;
|
||||
u32 bpf_offloaded_id;
|
||||
|
||||
@ -184,14 +181,26 @@ static inline bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline struct netdevsim *to_nsim(struct device *ptr)
|
||||
{
|
||||
return container_of(ptr, struct netdevsim, dev);
|
||||
}
|
||||
struct nsim_vf_config {
|
||||
int link_state;
|
||||
u16 min_tx_rate;
|
||||
u16 max_tx_rate;
|
||||
u16 vlan;
|
||||
__be16 vlan_proto;
|
||||
u16 qos;
|
||||
u8 vf_mac[ETH_ALEN];
|
||||
bool spoofchk_enabled;
|
||||
bool trusted;
|
||||
bool rss_query_enabled;
|
||||
};
|
||||
|
||||
int nsim_num_vf(struct device *dev);
|
||||
|
||||
extern struct bus_type nsim_bus;
|
||||
struct nsim_bus_dev {
|
||||
struct device dev;
|
||||
unsigned int num_vfs;
|
||||
struct nsim_vf_config *vfconfigs;
|
||||
};
|
||||
|
||||
struct nsim_bus_dev *nsim_bus_dev_new(void);
|
||||
void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev);
|
||||
int nsim_bus_init(void);
|
||||
void nsim_bus_exit(void);
|
||||
|
Loading…
Reference in New Issue
Block a user