Commit 154d0c81 authored by Manish Chopra's avatar Manish Chopra Committed by David S. Miller

qlcnic: VLAN enhancement for 84XX adapters

o Support multiple VLANs on 84xx VF devices
Signed-off-by: default avatarManish Chopra <manish.chopra@qlogic.com>
Signed-off-by: default avatarSucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 80c0e4f3
......@@ -788,9 +788,10 @@ struct qlcnic_cardrsp_tx_ctx {
#define QLCNIC_MAC_VLAN_ADD 3
#define QLCNIC_MAC_VLAN_DEL 4
struct qlcnic_mac_list_s {
struct qlcnic_mac_vlan_list {
struct list_head list;
uint8_t mac_addr[ETH_ALEN+2];
u16 vlan_id;
};
/* MAC Learn */
......@@ -1637,7 +1638,6 @@ int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int);
void qlcnic_set_netdev_features(struct qlcnic_adapter *,
struct qlcnic_esw_func_cfg *);
void qlcnic_sriov_vf_schedule_multi(struct net_device *);
void qlcnic_vf_add_mc_list(struct net_device *, u16);
/*
* QLOGIC Board information
......@@ -2136,4 +2136,18 @@ static inline bool qlcnic_sriov_vf_check(struct qlcnic_adapter *adapter)
return status;
}
static inline bool qlcnic_83xx_pf_check(struct qlcnic_adapter *adapter)
{
unsigned short device = adapter->pdev->device;
return (device == PCI_DEVICE_ID_QLOGIC_QLE834X) ? true : false;
}
static inline bool qlcnic_83xx_vf_check(struct qlcnic_adapter *adapter)
{
unsigned short device = adapter->pdev->device;
return (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X) ? true : false;
}
#endif /* __QLCNIC_H_ */
......@@ -1637,7 +1637,7 @@ int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
cmd->type = QLC_83XX_MBX_CMD_NO_WAIT;
qlcnic_83xx_set_interface_id_promisc(adapter, &temp);
cmd->req.arg[1] = (mode ? 1 : 0) | temp;
cmd->req.arg[1] = mode | temp;
err = qlcnic_issue_cmd(adapter, cmd);
if (!err)
return err;
......
......@@ -324,6 +324,11 @@ struct qlc_83xx_idc {
char **name;
};
enum qlcnic_vlan_operations {
QLC_VLAN_ADD = 0,
QLC_VLAN_DELETE
};
/* Device States */
enum qlcnic_83xx_states {
QLC_83XX_IDC_DEV_UNKNOWN,
......
......@@ -455,13 +455,13 @@ int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
{
struct qlcnic_mac_vlan_list *cur;
struct list_head *head;
struct qlcnic_mac_list_s *cur;
int err = -EINVAL;
/* Delete MAC from the existing list */
list_for_each(head, &adapter->mac_list) {
cur = list_entry(head, struct qlcnic_mac_list_s, list);
cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) {
err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
0, QLCNIC_MAC_DEL);
......@@ -477,17 +477,18 @@ int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)
{
struct qlcnic_mac_vlan_list *cur;
struct list_head *head;
struct qlcnic_mac_list_s *cur;
/* look up if already exists */
list_for_each(head, &adapter->mac_list) {
cur = list_entry(head, struct qlcnic_mac_list_s, list);
if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0)
cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0 &&
cur->vlan_id == vlan)
return 0;
}
cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC);
cur = kzalloc(sizeof(*cur), GFP_ATOMIC);
if (cur == NULL)
return -ENOMEM;
......@@ -499,6 +500,7 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)
return -EIO;
}
cur->vlan_id = vlan;
list_add_tail(&cur->list, &adapter->mac_list);
return 0;
}
......@@ -516,8 +518,7 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return;
if (!qlcnic_sriov_vf_check(adapter))
qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan);
qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan);
qlcnic_nic_add_mac(adapter, bcast_addr, vlan);
if (netdev->flags & IFF_PROMISC) {
......@@ -526,15 +527,11 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
} else if ((netdev->flags & IFF_ALLMULTI) ||
(netdev_mc_count(netdev) > ahw->max_mc_count)) {
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
} else if (!netdev_mc_empty(netdev) &&
!qlcnic_sriov_vf_check(adapter)) {
} else if (!netdev_mc_empty(netdev)) {
netdev_for_each_mc_addr(ha, netdev)
qlcnic_nic_add_mac(adapter, ha->addr, vlan);
}
if (qlcnic_sriov_vf_check(adapter))
qlcnic_vf_add_mc_list(netdev, vlan);
/* configure unicast MAC address, if there is not sufficient space
* to store all the unicast addresses then enable promiscuous mode
*/
......@@ -545,14 +542,12 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
qlcnic_nic_add_mac(adapter, ha->addr, vlan);
}
if (!qlcnic_sriov_vf_check(adapter)) {
if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
!adapter->fdb_mac_learn) {
qlcnic_alloc_lb_filters_mem(adapter);
adapter->drv_mac_learn = true;
} else {
adapter->drv_mac_learn = false;
}
if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
!adapter->fdb_mac_learn) {
qlcnic_alloc_lb_filters_mem(adapter);
adapter->drv_mac_learn = 1;
} else {
adapter->drv_mac_learn = 0;
}
qlcnic_nic_set_promisc(adapter, mode);
......@@ -561,16 +556,17 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
void qlcnic_set_multi(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_mac_vlan_list *cur;
struct netdev_hw_addr *ha;
struct qlcnic_mac_list_s *cur;
size_t temp;
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return;
if (qlcnic_sriov_vf_check(adapter)) {
if (!netdev_mc_empty(netdev)) {
netdev_for_each_mc_addr(ha, netdev) {
cur = kzalloc(sizeof(struct qlcnic_mac_list_s),
GFP_ATOMIC);
temp = sizeof(struct qlcnic_mac_vlan_list);
cur = kzalloc(temp, GFP_ATOMIC);
if (cur == NULL)
break;
memcpy(cur->mac_addr,
......@@ -605,11 +601,11 @@ int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter)
{
struct qlcnic_mac_list_s *cur;
struct list_head *head = &adapter->mac_list;
struct qlcnic_mac_vlan_list *cur;
while (!list_empty(head)) {
cur = list_entry(head->next, struct qlcnic_mac_list_s, list);
cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list);
qlcnic_sre_macaddr_change(adapter,
cur->mac_addr, 0, QLCNIC_MAC_DEL);
list_del(&cur->list);
......
......@@ -308,11 +308,11 @@ int qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
static void qlcnic_delete_adapter_mac(struct qlcnic_adapter *adapter)
{
struct qlcnic_mac_list_s *cur;
struct qlcnic_mac_vlan_list *cur;
struct list_head *head;
list_for_each(head, &adapter->mac_list) {
cur = list_entry(head, struct qlcnic_mac_list_s, list);
cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
if (!memcmp(adapter->mac_addr, cur->mac_addr, ETH_ALEN)) {
qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
0, QLCNIC_MAC_DEL);
......
......@@ -126,8 +126,8 @@ struct qlcnic_vport {
u16 handle;
u16 max_tx_bw;
u16 min_tx_bw;
u16 pvid;
u8 vlan_mode;
u16 vlan;
u8 qos;
bool spoofchk;
u8 mac[6];
......@@ -137,6 +137,8 @@ struct qlcnic_vf_info {
u8 pci_func;
u16 rx_ctx_id;
u16 tx_ctx_id;
u16 *sriov_vlans;
int num_vlan;
unsigned long state;
struct completion ch_free_cmpl;
struct work_struct trans_work;
......@@ -149,6 +151,7 @@ struct qlcnic_vf_info {
struct qlcnic_trans_list rcv_pend;
struct qlcnic_adapter *adapter;
struct qlcnic_vport *vp;
struct mutex vlan_list_lock; /* Lock for VLAN list */
};
struct qlcnic_async_work_list {
......@@ -197,6 +200,13 @@ int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *,
int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *, u16, u8);
int qlcnic_sriov_vf_shutdown(struct pci_dev *);
int qlcnic_sriov_vf_resume(struct qlcnic_adapter *);
void qlcnic_sriov_free_vlans(struct qlcnic_adapter *);
void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *);
bool qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info *);
void qlcnic_sriov_del_vlan_id(struct qlcnic_sriov *,
struct qlcnic_vf_info *, u16);
void qlcnic_sriov_add_vlan_id(struct qlcnic_sriov *,
struct qlcnic_vf_info *, u16);
static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)
{
......
......@@ -176,6 +176,7 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
vf->adapter = adapter;
vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i);
mutex_init(&vf->send_cmd_lock);
mutex_init(&vf->vlan_list_lock);
INIT_LIST_HEAD(&vf->rcv_act.wait_list);
INIT_LIST_HEAD(&vf->rcv_pend.wait_list);
spin_lock_init(&vf->rcv_act.lock);
......@@ -276,6 +277,13 @@ static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter)
void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
{
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
if (!sriov)
return;
qlcnic_sriov_free_vlans(adapter);
if (qlcnic_sriov_pf_check(adapter))
qlcnic_sriov_pf_cleanup(adapter);
......@@ -416,10 +424,15 @@ static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter,
return 0;
sriov->any_vlan = cmd->rsp.arg[2] & 0xf;
sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16;
dev_info(&adapter->pdev->dev, "Number of allowed Guest VLANs = %d\n",
sriov->num_allowed_vlans);
qlcnic_sriov_alloc_vlans(adapter);
if (!sriov->any_vlan)
return 0;
sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16;
num_vlans = sriov->num_allowed_vlans;
sriov->allowed_vlans = kzalloc(sizeof(u16) * num_vlans, GFP_KERNEL);
if (!sriov->allowed_vlans)
......@@ -473,6 +486,8 @@ static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter)
if (err)
return err;
ahw->max_mc_count = nic_info.max_rx_mcast_mac_filters;
err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func);
if (err)
return -EIO;
......@@ -1441,18 +1456,27 @@ int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op)
return ret;
}
void qlcnic_vf_add_mc_list(struct net_device *netdev, u16 vlan)
static void qlcnic_vf_add_mc_list(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_mac_list_s *cur;
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
struct qlcnic_mac_vlan_list *cur;
struct list_head *head, tmp_list;
struct qlcnic_vf_info *vf;
u16 vlan_id;
int i;
static const u8 bcast_addr[ETH_ALEN] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
vf = &adapter->ahw->sriov->vf_info[0];
INIT_LIST_HEAD(&tmp_list);
head = &adapter->vf_mc_list;
netif_addr_lock_bh(netdev);
while (!list_empty(head)) {
cur = list_entry(head->next, struct qlcnic_mac_list_s, list);
cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list);
list_move(&cur->list, &tmp_list);
}
......@@ -1460,8 +1484,28 @@ void qlcnic_vf_add_mc_list(struct net_device *netdev, u16 vlan)
while (!list_empty(&tmp_list)) {
cur = list_entry((&tmp_list)->next,
struct qlcnic_mac_list_s, list);
qlcnic_nic_add_mac(adapter, cur->mac_addr, vlan);
struct qlcnic_mac_vlan_list, list);
if (!qlcnic_sriov_check_any_vlan(vf)) {
qlcnic_nic_add_mac(adapter, bcast_addr, 0);
qlcnic_nic_add_mac(adapter, cur->mac_addr, 0);
} else {
mutex_lock(&vf->vlan_list_lock);
for (i = 0; i < sriov->num_allowed_vlans; i++) {
vlan_id = vf->sriov_vlans[i];
if (vlan_id) {
qlcnic_nic_add_mac(adapter, bcast_addr,
vlan_id);
qlcnic_nic_add_mac(adapter,
cur->mac_addr,
vlan_id);
}
}
mutex_unlock(&vf->vlan_list_lock);
if (qlcnic_84xx_check(adapter)) {
qlcnic_nic_add_mac(adapter, bcast_addr, 0);
qlcnic_nic_add_mac(adapter, cur->mac_addr, 0);
}
}
list_del(&cur->list);
kfree(cur);
}
......@@ -1484,13 +1528,24 @@ void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *bc)
static void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
u16 vlan;
struct qlcnic_hardware_context *ahw = adapter->ahw;
u32 mode = VPORT_MISS_MODE_DROP;
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return;
vlan = adapter->ahw->sriov->vlan;
__qlcnic_set_multi(netdev, vlan);
if (netdev->flags & IFF_PROMISC) {
if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
mode = VPORT_MISS_MODE_ACCEPT_ALL;
} else if ((netdev->flags & IFF_ALLMULTI) ||
(netdev_mc_count(netdev) > ahw->max_mc_count)) {
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
}
if (qlcnic_sriov_vf_check(adapter))
qlcnic_vf_add_mc_list(netdev);
qlcnic_nic_set_promisc(adapter, mode);
}
static void qlcnic_sriov_handle_async_multi(struct work_struct *work)
......@@ -1825,18 +1880,60 @@ static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *adapter)
cancel_delayed_work_sync(&adapter->fw_work);
}
static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_sriov *sriov,
static int qlcnic_sriov_check_vlan_id(struct qlcnic_sriov *sriov,
struct qlcnic_vf_info *vf, u16 vlan_id)
{
int i, err = -EINVAL;
if (!vf->sriov_vlans)
return err;
mutex_lock(&vf->vlan_list_lock);
for (i = 0; i < sriov->num_allowed_vlans; i++) {
if (vf->sriov_vlans[i] == vlan_id) {
err = 0;
break;
}
}
mutex_unlock(&vf->vlan_list_lock);
return err;
}
static int qlcnic_sriov_validate_num_vlans(struct qlcnic_sriov *sriov,
struct qlcnic_vf_info *vf)
{
int err = 0;
mutex_lock(&vf->vlan_list_lock);
if (vf->num_vlan >= sriov->num_allowed_vlans)
err = -EINVAL;
mutex_unlock(&vf->vlan_list_lock);
return err;
}
static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_adapter *adapter,
u16 vid, u8 enable)
{
u16 vlan = sriov->vlan;
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
struct qlcnic_vf_info *vf;
bool vlan_exist;
u8 allowed = 0;
int i;
vf = &adapter->ahw->sriov->vf_info[0];
vlan_exist = qlcnic_sriov_check_any_vlan(vf);
if (sriov->vlan_mode != QLC_GUEST_VLAN_MODE)
return -EINVAL;
if (enable) {
if (vlan)
if (qlcnic_83xx_vf_check(adapter) && vlan_exist)
return -EINVAL;
if (qlcnic_sriov_validate_num_vlans(sriov, vf))
return -EINVAL;
if (sriov->any_vlan) {
......@@ -1849,24 +1946,54 @@ static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_sriov *sriov,
return -EINVAL;
}
} else {
if (!vlan || vlan != vid)
if (!vlan_exist || qlcnic_sriov_check_vlan_id(sriov, vf, vid))
return -EINVAL;
}
return 0;
}
static void qlcnic_sriov_vlan_operation(struct qlcnic_vf_info *vf, u16 vlan_id,
enum qlcnic_vlan_operations opcode)
{
struct qlcnic_adapter *adapter = vf->adapter;
struct qlcnic_sriov *sriov;
sriov = adapter->ahw->sriov;
if (!vf->sriov_vlans)
return;
mutex_lock(&vf->vlan_list_lock);
switch (opcode) {
case QLC_VLAN_ADD:
qlcnic_sriov_add_vlan_id(sriov, vf, vlan_id);
break;
case QLC_VLAN_DELETE:
qlcnic_sriov_del_vlan_id(sriov, vf, vlan_id);
break;
default:
netdev_err(adapter->netdev, "Invalid VLAN operation\n");
}
mutex_unlock(&vf->vlan_list_lock);
return;
}
int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,
u16 vid, u8 enable)
{
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
struct qlcnic_vf_info *vf;
struct qlcnic_cmd_args cmd;
int ret;
if (vid == 0)
return 0;
ret = qlcnic_sriov_validate_vlan_cfg(sriov, vid, enable);
vf = &adapter->ahw->sriov->vf_info[0];
ret = qlcnic_sriov_validate_vlan_cfg(adapter, vid, enable);
if (ret)
return ret;
......@@ -1886,11 +2013,11 @@ int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,
qlcnic_free_mac_list(adapter);
if (enable)
sriov->vlan = vid;
qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_ADD);
else
sriov->vlan = 0;
qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_DELETE);
qlcnic_sriov_vf_set_multi(adapter->netdev);
qlcnic_set_multi(adapter->netdev);
}
qlcnic_free_mbx_args(&cmd);
......@@ -1900,20 +2027,18 @@ int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,
static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *adapter)
{
struct list_head *head = &adapter->mac_list;
struct qlcnic_mac_list_s *cur;
u16 vlan;
vlan = adapter->ahw->sriov->vlan;
struct qlcnic_mac_vlan_list *cur;
while (!list_empty(head)) {
cur = list_entry(head->next, struct qlcnic_mac_list_s, list);
qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
vlan, QLCNIC_MAC_DEL);
cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list);
qlcnic_sre_macaddr_change(adapter, cur->mac_addr, cur->vlan_id,
QLCNIC_MAC_DEL);
list_del(&cur->list);
kfree(cur);
}
}
int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev)
{
struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
......@@ -1964,3 +2089,70 @@ int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter)
idc->delay);
return err;
}
void qlcnic_sriov_alloc_vlans(struct qlcnic_adapter *adapter)
{
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
struct qlcnic_vf_info *vf;
int i;
for (i = 0; i < sriov->num_vfs; i++) {
vf = &sriov->vf_info[i];
vf->sriov_vlans = kcalloc(sriov->num_allowed_vlans,
sizeof(*vf->sriov_vlans), GFP_KERNEL);
}
}
void qlcnic_sriov_free_vlans(struct qlcnic_adapter *adapter)
{
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
struct qlcnic_vf_info *vf;
int i;
for (i = 0; i < sriov->num_vfs; i++) {
vf = &sriov->vf_info[i];
kfree(vf->sriov_vlans);
vf->sriov_vlans = NULL;
}
}
void qlcnic_sriov_add_vlan_id(struct qlcnic_sriov *sriov,
struct qlcnic_vf_info *vf, u16 vlan_id)
{
int i;
for (i = 0; i < sriov->num_allowed_vlans; i++) {
if (!vf->sriov_vlans[i]) {
vf->sriov_vlans[i] = vlan_id;
vf->num_vlan++;
return;
}
}
}
void qlcnic_sriov_del_vlan_id(struct qlcnic_sriov *sriov,
struct qlcnic_vf_info *vf, u16 vlan_id)
{
int i;
for (i = 0; i < sriov->num_allowed_vlans; i++) {
if (vf->sriov_vlans[i] == vlan_id) {
vf->sriov_vlans[i] = 0;
vf->num_vlan--;
return;
}
}
}
bool qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info *vf)
{
bool err = false;
mutex_lock(&vf->vlan_list_lock);
if (vf->num_vlan)
err = true;
mutex_unlock(&vf->vlan_list_lock);
return err;
}
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