qlcnic: VLAN enhancement for 84XX adapters

o Support multiple VLANs on 84xx VF devices

Signed-off-by: Manish Chopra <manish.chopra@qlogic.com>
Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Manish Chopra 2013-12-17 09:01:53 -05:00 committed by David S. Miller
parent 80c0e4f3a3
commit 154d0c810c
8 changed files with 410 additions and 115 deletions

View File

@ -788,9 +788,10 @@ struct qlcnic_cardrsp_tx_ctx {
#define QLCNIC_MAC_VLAN_ADD 3 #define QLCNIC_MAC_VLAN_ADD 3
#define QLCNIC_MAC_VLAN_DEL 4 #define QLCNIC_MAC_VLAN_DEL 4
struct qlcnic_mac_list_s { struct qlcnic_mac_vlan_list {
struct list_head list; struct list_head list;
uint8_t mac_addr[ETH_ALEN+2]; uint8_t mac_addr[ETH_ALEN+2];
u16 vlan_id;
}; };
/* MAC Learn */ /* 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 *, void qlcnic_set_netdev_features(struct qlcnic_adapter *,
struct qlcnic_esw_func_cfg *); struct qlcnic_esw_func_cfg *);
void qlcnic_sriov_vf_schedule_multi(struct net_device *); void qlcnic_sriov_vf_schedule_multi(struct net_device *);
void qlcnic_vf_add_mc_list(struct net_device *, u16);
/* /*
* QLOGIC Board information * QLOGIC Board information
@ -2136,4 +2136,18 @@ static inline bool qlcnic_sriov_vf_check(struct qlcnic_adapter *adapter)
return status; 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_ */ #endif /* __QLCNIC_H_ */

View File

@ -1637,7 +1637,7 @@ int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
cmd->type = QLC_83XX_MBX_CMD_NO_WAIT; cmd->type = QLC_83XX_MBX_CMD_NO_WAIT;
qlcnic_83xx_set_interface_id_promisc(adapter, &temp); 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); err = qlcnic_issue_cmd(adapter, cmd);
if (!err) if (!err)
return err; return err;

View File

@ -324,6 +324,11 @@ struct qlc_83xx_idc {
char **name; char **name;
}; };
enum qlcnic_vlan_operations {
QLC_VLAN_ADD = 0,
QLC_VLAN_DELETE
};
/* Device States */ /* Device States */
enum qlcnic_83xx_states { enum qlcnic_83xx_states {
QLC_83XX_IDC_DEV_UNKNOWN, QLC_83XX_IDC_DEV_UNKNOWN,

View File

@ -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) int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
{ {
struct qlcnic_mac_vlan_list *cur;
struct list_head *head; struct list_head *head;
struct qlcnic_mac_list_s *cur;
int err = -EINVAL; int err = -EINVAL;
/* Delete MAC from the existing list */ /* Delete MAC from the existing list */
list_for_each(head, &adapter->mac_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) { if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) {
err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr, err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
0, QLCNIC_MAC_DEL); 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) 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 list_head *head;
struct qlcnic_mac_list_s *cur;
/* look up if already exists */ /* look up if already exists */
list_for_each(head, &adapter->mac_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) if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0 &&
cur->vlan_id == vlan)
return 0; return 0;
} }
cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC); cur = kzalloc(sizeof(*cur), GFP_ATOMIC);
if (cur == NULL) if (cur == NULL)
return -ENOMEM; return -ENOMEM;
@ -499,6 +500,7 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)
return -EIO; return -EIO;
} }
cur->vlan_id = vlan;
list_add_tail(&cur->list, &adapter->mac_list); list_add_tail(&cur->list, &adapter->mac_list);
return 0; return 0;
} }
@ -516,7 +518,6 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return; 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); qlcnic_nic_add_mac(adapter, bcast_addr, vlan);
@ -526,15 +527,11 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
} else if ((netdev->flags & IFF_ALLMULTI) || } else if ((netdev->flags & IFF_ALLMULTI) ||
(netdev_mc_count(netdev) > ahw->max_mc_count)) { (netdev_mc_count(netdev) > ahw->max_mc_count)) {
mode = VPORT_MISS_MODE_ACCEPT_MULTI; mode = VPORT_MISS_MODE_ACCEPT_MULTI;
} else if (!netdev_mc_empty(netdev) && } else if (!netdev_mc_empty(netdev)) {
!qlcnic_sriov_vf_check(adapter)) {
netdev_for_each_mc_addr(ha, netdev) netdev_for_each_mc_addr(ha, netdev)
qlcnic_nic_add_mac(adapter, ha->addr, vlan); 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 /* configure unicast MAC address, if there is not sufficient space
* to store all the unicast addresses then enable promiscuous mode * 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); qlcnic_nic_add_mac(adapter, ha->addr, vlan);
} }
if (!qlcnic_sriov_vf_check(adapter)) {
if (mode == VPORT_MISS_MODE_ACCEPT_ALL && if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
!adapter->fdb_mac_learn) { !adapter->fdb_mac_learn) {
qlcnic_alloc_lb_filters_mem(adapter); qlcnic_alloc_lb_filters_mem(adapter);
adapter->drv_mac_learn = true; adapter->drv_mac_learn = 1;
} else { } else {
adapter->drv_mac_learn = false; adapter->drv_mac_learn = 0;
}
} }
qlcnic_nic_set_promisc(adapter, mode); 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) void qlcnic_set_multi(struct net_device *netdev)
{ {
struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_mac_vlan_list *cur;
struct netdev_hw_addr *ha; struct netdev_hw_addr *ha;
struct qlcnic_mac_list_s *cur; size_t temp;
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return; return;
if (qlcnic_sriov_vf_check(adapter)) { if (qlcnic_sriov_vf_check(adapter)) {
if (!netdev_mc_empty(netdev)) { if (!netdev_mc_empty(netdev)) {
netdev_for_each_mc_addr(ha, netdev) { netdev_for_each_mc_addr(ha, netdev) {
cur = kzalloc(sizeof(struct qlcnic_mac_list_s), temp = sizeof(struct qlcnic_mac_vlan_list);
GFP_ATOMIC); cur = kzalloc(temp, GFP_ATOMIC);
if (cur == NULL) if (cur == NULL)
break; break;
memcpy(cur->mac_addr, 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) void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter)
{ {
struct qlcnic_mac_list_s *cur;
struct list_head *head = &adapter->mac_list; struct list_head *head = &adapter->mac_list;
struct qlcnic_mac_vlan_list *cur;
while (!list_empty(head)) { 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, qlcnic_sre_macaddr_change(adapter,
cur->mac_addr, 0, QLCNIC_MAC_DEL); cur->mac_addr, 0, QLCNIC_MAC_DEL);
list_del(&cur->list); list_del(&cur->list);

View File

@ -308,11 +308,11 @@ int qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
static void qlcnic_delete_adapter_mac(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; struct list_head *head;
list_for_each(head, &adapter->mac_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(adapter->mac_addr, cur->mac_addr, ETH_ALEN)) { if (!memcmp(adapter->mac_addr, cur->mac_addr, ETH_ALEN)) {
qlcnic_sre_macaddr_change(adapter, cur->mac_addr, qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
0, QLCNIC_MAC_DEL); 0, QLCNIC_MAC_DEL);

View File

@ -126,8 +126,8 @@ struct qlcnic_vport {
u16 handle; u16 handle;
u16 max_tx_bw; u16 max_tx_bw;
u16 min_tx_bw; u16 min_tx_bw;
u16 pvid;
u8 vlan_mode; u8 vlan_mode;
u16 vlan;
u8 qos; u8 qos;
bool spoofchk; bool spoofchk;
u8 mac[6]; u8 mac[6];
@ -137,6 +137,8 @@ struct qlcnic_vf_info {
u8 pci_func; u8 pci_func;
u16 rx_ctx_id; u16 rx_ctx_id;
u16 tx_ctx_id; u16 tx_ctx_id;
u16 *sriov_vlans;
int num_vlan;
unsigned long state; unsigned long state;
struct completion ch_free_cmpl; struct completion ch_free_cmpl;
struct work_struct trans_work; struct work_struct trans_work;
@ -149,6 +151,7 @@ struct qlcnic_vf_info {
struct qlcnic_trans_list rcv_pend; struct qlcnic_trans_list rcv_pend;
struct qlcnic_adapter *adapter; struct qlcnic_adapter *adapter;
struct qlcnic_vport *vp; struct qlcnic_vport *vp;
struct mutex vlan_list_lock; /* Lock for VLAN list */
}; };
struct qlcnic_async_work_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_cfg_vf_guest_vlan(struct qlcnic_adapter *, u16, u8);
int qlcnic_sriov_vf_shutdown(struct pci_dev *); int qlcnic_sriov_vf_shutdown(struct pci_dev *);
int qlcnic_sriov_vf_resume(struct qlcnic_adapter *); 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) static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)
{ {

View File

@ -176,6 +176,7 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
vf->adapter = adapter; vf->adapter = adapter;
vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i); vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i);
mutex_init(&vf->send_cmd_lock); 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_act.wait_list);
INIT_LIST_HEAD(&vf->rcv_pend.wait_list); INIT_LIST_HEAD(&vf->rcv_pend.wait_list);
spin_lock_init(&vf->rcv_act.lock); 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) 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)) if (qlcnic_sriov_pf_check(adapter))
qlcnic_sriov_pf_cleanup(adapter); qlcnic_sriov_pf_cleanup(adapter);
@ -416,10 +424,15 @@ static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter,
return 0; return 0;
sriov->any_vlan = cmd->rsp.arg[2] & 0xf; 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) if (!sriov->any_vlan)
return 0; return 0;
sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16;
num_vlans = sriov->num_allowed_vlans; num_vlans = sriov->num_allowed_vlans;
sriov->allowed_vlans = kzalloc(sizeof(u16) * num_vlans, GFP_KERNEL); sriov->allowed_vlans = kzalloc(sizeof(u16) * num_vlans, GFP_KERNEL);
if (!sriov->allowed_vlans) if (!sriov->allowed_vlans)
@ -473,6 +486,8 @@ static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter)
if (err) if (err)
return 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); err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func);
if (err) if (err)
return -EIO; return -EIO;
@ -1441,18 +1456,27 @@ out:
return ret; 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_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 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); INIT_LIST_HEAD(&tmp_list);
head = &adapter->vf_mc_list; head = &adapter->vf_mc_list;
netif_addr_lock_bh(netdev); netif_addr_lock_bh(netdev);
while (!list_empty(head)) { 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); 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)) { while (!list_empty(&tmp_list)) {
cur = list_entry((&tmp_list)->next, cur = list_entry((&tmp_list)->next,
struct qlcnic_mac_list_s, list); struct qlcnic_mac_vlan_list, list);
qlcnic_nic_add_mac(adapter, cur->mac_addr, vlan); 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); list_del(&cur->list);
kfree(cur); 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) static void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
{ {
struct qlcnic_adapter *adapter = netdev_priv(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)) if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return; return;
vlan = adapter->ahw->sriov->vlan; if (netdev->flags & IFF_PROMISC) {
__qlcnic_set_multi(netdev, vlan); 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) 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); 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 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; u8 allowed = 0;
int i; 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) if (sriov->vlan_mode != QLC_GUEST_VLAN_MODE)
return -EINVAL; return -EINVAL;
if (enable) { if (enable) {
if (vlan) if (qlcnic_83xx_vf_check(adapter) && vlan_exist)
return -EINVAL;
if (qlcnic_sriov_validate_num_vlans(sriov, vf))
return -EINVAL; return -EINVAL;
if (sriov->any_vlan) { if (sriov->any_vlan) {
@ -1849,24 +1946,54 @@ static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_sriov *sriov,
return -EINVAL; return -EINVAL;
} }
} else { } else {
if (!vlan || vlan != vid) if (!vlan_exist || qlcnic_sriov_check_vlan_id(sriov, vf, vid))
return -EINVAL; return -EINVAL;
} }
return 0; 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, int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,
u16 vid, u8 enable) u16 vid, u8 enable)
{ {
struct qlcnic_sriov *sriov = adapter->ahw->sriov; struct qlcnic_sriov *sriov = adapter->ahw->sriov;
struct qlcnic_vf_info *vf;
struct qlcnic_cmd_args cmd; struct qlcnic_cmd_args cmd;
int ret; int ret;
if (vid == 0) if (vid == 0)
return 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) if (ret)
return ret; return ret;
@ -1886,11 +2013,11 @@ int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,
qlcnic_free_mac_list(adapter); qlcnic_free_mac_list(adapter);
if (enable) if (enable)
sriov->vlan = vid; qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_ADD);
else 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); 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) static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *adapter)
{ {
struct list_head *head = &adapter->mac_list; struct list_head *head = &adapter->mac_list;
struct qlcnic_mac_list_s *cur; struct qlcnic_mac_vlan_list *cur;
u16 vlan;
vlan = adapter->ahw->sriov->vlan;
while (!list_empty(head)) { 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, qlcnic_sre_macaddr_change(adapter, cur->mac_addr, cur->vlan_id,
vlan, QLCNIC_MAC_DEL); QLCNIC_MAC_DEL);
list_del(&cur->list); list_del(&cur->list);
kfree(cur); kfree(cur);
} }
} }
int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev) int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev)
{ {
struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
@ -1964,3 +2089,70 @@ int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter)
idc->delay); idc->delay);
return err; 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;
}

View File

@ -9,7 +9,7 @@
#include "qlcnic.h" #include "qlcnic.h"
#include <linux/types.h> #include <linux/types.h>
#define QLCNIC_SRIOV_VF_MAX_MAC 1 #define QLCNIC_SRIOV_VF_MAX_MAC 8
#define QLC_VF_MIN_TX_RATE 100 #define QLC_VF_MIN_TX_RATE 100
#define QLC_VF_MAX_TX_RATE 9999 #define QLC_VF_MAX_TX_RATE 9999
@ -64,9 +64,10 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter,
{ {
struct qlcnic_sriov *sriov = adapter->ahw->sriov; struct qlcnic_sriov *sriov = adapter->ahw->sriov;
struct qlcnic_resources *res = &sriov->ff_max; struct qlcnic_resources *res = &sriov->ff_max;
u32 temp, num_vf_macs, num_vfs, max; u16 num_macs = sriov->num_allowed_vlans + 1;
int ret = -EIO, vpid, id; int ret = -EIO, vpid, id;
struct qlcnic_vport *vp; struct qlcnic_vport *vp;
u32 num_vfs, max, temp;
vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func); vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func);
if (vpid < 0) if (vpid < 0)
@ -76,16 +77,21 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter,
max = num_vfs + 1; max = num_vfs + 1;
info->bit_offsets = 0xffff; info->bit_offsets = 0xffff;
info->max_tx_ques = res->num_tx_queues / max; info->max_tx_ques = res->num_tx_queues / max;
info->max_rx_mcast_mac_filters = res->num_rx_mcast_mac_filters;
num_vf_macs = QLCNIC_SRIOV_VF_MAX_MAC; if (qlcnic_83xx_pf_check(adapter))
num_macs = 1;
if (adapter->ahw->pci_func == func) { if (adapter->ahw->pci_func == func) {
temp = res->num_rx_mcast_mac_filters - (num_vfs * num_vf_macs);
info->max_rx_ucast_mac_filters = temp;
temp = res->num_tx_mac_filters - (num_vfs * num_vf_macs);
info->max_tx_mac_filters = temp;
info->min_tx_bw = 0; info->min_tx_bw = 0;
info->max_tx_bw = MAX_BW; info->max_tx_bw = MAX_BW;
temp = res->num_rx_ucast_mac_filters - num_macs * num_vfs;
info->max_rx_ucast_mac_filters = temp;
temp = res->num_tx_mac_filters - num_macs * num_vfs;
info->max_tx_mac_filters = temp;
temp = num_macs * num_vfs * QLCNIC_SRIOV_VF_MAX_MAC;
temp = res->num_rx_mcast_mac_filters - temp;
info->max_rx_mcast_mac_filters = temp;
} else { } else {
id = qlcnic_sriov_func_to_index(adapter, func); id = qlcnic_sriov_func_to_index(adapter, func);
if (id < 0) if (id < 0)
@ -93,8 +99,10 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter,
vp = sriov->vf_info[id].vp; vp = sriov->vf_info[id].vp;
info->min_tx_bw = vp->min_tx_bw; info->min_tx_bw = vp->min_tx_bw;
info->max_tx_bw = vp->max_tx_bw; info->max_tx_bw = vp->max_tx_bw;
info->max_rx_ucast_mac_filters = num_vf_macs; info->max_rx_ucast_mac_filters = num_macs;
info->max_tx_mac_filters = num_vf_macs; info->max_tx_mac_filters = num_macs;
temp = num_macs * QLCNIC_SRIOV_VF_MAX_MAC;
info->max_rx_mcast_mac_filters = temp;
} }
info->max_rx_ip_addr = res->num_destip / max; info->max_rx_ip_addr = res->num_destip / max;
@ -132,6 +140,25 @@ static void qlcnic_sriov_pf_set_ff_max_res(struct qlcnic_adapter *adapter,
ff_max->max_local_ipv6_addrs = info->max_local_ipv6_addrs; ff_max->max_local_ipv6_addrs = info->max_local_ipv6_addrs;
} }
static void qlcnic_sriov_set_vf_max_vlan(struct qlcnic_adapter *adapter,
struct qlcnic_info *npar_info)
{
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
int temp, total_fn;
temp = npar_info->max_rx_mcast_mac_filters;
total_fn = sriov->num_vfs + 1;
temp = temp / (QLCNIC_SRIOV_VF_MAX_MAC * total_fn);
sriov->num_allowed_vlans = temp - 1;
if (qlcnic_83xx_pf_check(adapter))
sriov->num_allowed_vlans = 1;
netdev_info(adapter->netdev, "Max Guest VLANs supported per VF = %d\n",
sriov->num_allowed_vlans);
}
static int qlcnic_sriov_get_pf_info(struct qlcnic_adapter *adapter, static int qlcnic_sriov_get_pf_info(struct qlcnic_adapter *adapter,
struct qlcnic_info *npar_info) struct qlcnic_info *npar_info)
{ {
@ -165,6 +192,7 @@ static int qlcnic_sriov_get_pf_info(struct qlcnic_adapter *adapter,
npar_info->max_local_ipv6_addrs = LSW(cmd.rsp.arg[8]); npar_info->max_local_ipv6_addrs = LSW(cmd.rsp.arg[8]);
npar_info->max_remote_ipv6_addrs = MSW(cmd.rsp.arg[8]); npar_info->max_remote_ipv6_addrs = MSW(cmd.rsp.arg[8]);
qlcnic_sriov_set_vf_max_vlan(adapter, npar_info);
qlcnic_sriov_pf_set_ff_max_res(adapter, npar_info); qlcnic_sriov_pf_set_ff_max_res(adapter, npar_info);
dev_info(&adapter->pdev->dev, dev_info(&adapter->pdev->dev,
"\n\ttotal_pf: %d,\n" "\n\ttotal_pf: %d,\n"
@ -403,6 +431,8 @@ static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter)
qlcnic_sriov_pf_disable(adapter); qlcnic_sriov_pf_disable(adapter);
qlcnic_sriov_free_vlans(adapter);
qlcnic_sriov_pf_cleanup(adapter); qlcnic_sriov_pf_cleanup(adapter);
/* After disabling SRIOV re-init the driver in default mode /* After disabling SRIOV re-init the driver in default mode
@ -511,6 +541,8 @@ static int __qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter,
if (err) if (err)
goto del_flr_queue; goto del_flr_queue;
qlcnic_sriov_alloc_vlans(adapter);
err = qlcnic_sriov_pf_enable(adapter, num_vfs); err = qlcnic_sriov_pf_enable(adapter, num_vfs);
return err; return err;
@ -608,7 +640,7 @@ static int qlcnic_sriov_set_vf_acl(struct qlcnic_adapter *adapter, u8 func)
if (vp->vlan_mode == QLC_PVID_MODE) { if (vp->vlan_mode == QLC_PVID_MODE) {
cmd.req.arg[2] |= BIT_6; cmd.req.arg[2] |= BIT_6;
cmd.req.arg[3] |= vp->vlan << 8; cmd.req.arg[3] |= vp->pvid << 8;
} }
err = qlcnic_issue_cmd(adapter, &cmd); err = qlcnic_issue_cmd(adapter, &cmd);
@ -643,10 +675,13 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
struct qlcnic_vf_info *vf = trans->vf; struct qlcnic_vf_info *vf = trans->vf;
struct qlcnic_vport *vp = vf->vp; struct qlcnic_vport *vp = vf->vp;
struct qlcnic_adapter *adapter; struct qlcnic_adapter *adapter;
struct qlcnic_sriov *sriov;
u16 func = vf->pci_func; u16 func = vf->pci_func;
size_t size;
int err; int err;
adapter = vf->adapter; adapter = vf->adapter;
sriov = adapter->ahw->sriov;
if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) { if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) {
err = qlcnic_sriov_pf_config_vport(adapter, 1, func); err = qlcnic_sriov_pf_config_vport(adapter, 1, func);
@ -656,8 +691,12 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
qlcnic_sriov_pf_config_vport(adapter, 0, func); qlcnic_sriov_pf_config_vport(adapter, 0, func);
} }
} else { } else {
if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) {
vp->vlan = 0; size = sizeof(*vf->sriov_vlans);
size = size * sriov->num_allowed_vlans;
memset(vf->sriov_vlans, 0, size);
}
err = qlcnic_sriov_pf_config_vport(adapter, 0, func); err = qlcnic_sriov_pf_config_vport(adapter, 0, func);
} }
@ -679,20 +718,23 @@ err_out:
} }
static int qlcnic_sriov_cfg_vf_def_mac(struct qlcnic_adapter *adapter, static int qlcnic_sriov_cfg_vf_def_mac(struct qlcnic_adapter *adapter,
struct qlcnic_vport *vp, struct qlcnic_vf_info *vf,
u16 func, u16 vlan, u8 op) u16 vlan, u8 op)
{ {
struct qlcnic_cmd_args cmd; struct qlcnic_cmd_args cmd;
struct qlcnic_macvlan_mbx mv; struct qlcnic_macvlan_mbx mv;
struct qlcnic_vport *vp;
u8 *addr; u8 *addr;
int err; int err;
u32 *buf; u32 *buf;
int vpid; int vpid;
vp = vf->vp;
if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN)) if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN))
return -ENOMEM; return -ENOMEM;
vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func); vpid = qlcnic_sriov_pf_get_vport_handle(adapter, vf->pci_func);
if (vpid < 0) { if (vpid < 0) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
@ -736,6 +778,35 @@ static int qlcnic_sriov_validate_create_rx_ctx(struct qlcnic_cmd_args *cmd)
return 0; return 0;
} }
static void qlcnic_83xx_cfg_default_mac_vlan(struct qlcnic_adapter *adapter,
struct qlcnic_vf_info *vf,
int opcode)
{
struct qlcnic_sriov *sriov;
u16 vlan;
int i;
sriov = adapter->ahw->sriov;
mutex_lock(&vf->vlan_list_lock);
if (vf->num_vlan) {
for (i = 0; i < sriov->num_allowed_vlans; i++) {
vlan = vf->sriov_vlans[i];
if (vlan)
qlcnic_sriov_cfg_vf_def_mac(adapter, vf, vlan,
opcode);
}
}
mutex_unlock(&vf->vlan_list_lock);
if (vf->vp->vlan_mode != QLC_PVID_MODE) {
if (qlcnic_83xx_pf_check(adapter) &&
qlcnic_sriov_check_any_vlan(vf))
return;
qlcnic_sriov_cfg_vf_def_mac(adapter, vf, 0, opcode);
}
}
static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran, static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran,
struct qlcnic_cmd_args *cmd) struct qlcnic_cmd_args *cmd)
{ {
@ -743,7 +814,6 @@ static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran,
struct qlcnic_adapter *adapter = vf->adapter; struct qlcnic_adapter *adapter = vf->adapter;
struct qlcnic_rcv_mbx_out *mbx_out; struct qlcnic_rcv_mbx_out *mbx_out;
int err; int err;
u16 vlan;
err = qlcnic_sriov_validate_create_rx_ctx(cmd); err = qlcnic_sriov_validate_create_rx_ctx(cmd);
if (err) { if (err) {
@ -754,12 +824,10 @@ static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran,
cmd->req.arg[6] = vf->vp->handle; cmd->req.arg[6] = vf->vp->handle;
err = qlcnic_issue_cmd(adapter, cmd); err = qlcnic_issue_cmd(adapter, cmd);
vlan = vf->vp->vlan;
if (!err) { if (!err) {
mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd->rsp.arg[1]; mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd->rsp.arg[1];
vf->rx_ctx_id = mbx_out->ctx_id; vf->rx_ctx_id = mbx_out->ctx_id;
qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, qlcnic_83xx_cfg_default_mac_vlan(adapter, vf, QLCNIC_MAC_ADD);
vlan, QLCNIC_MAC_ADD);
} else { } else {
vf->rx_ctx_id = 0; vf->rx_ctx_id = 0;
} }
@ -843,7 +911,6 @@ static int qlcnic_sriov_pf_del_rx_ctx_cmd(struct qlcnic_bc_trans *trans,
struct qlcnic_vf_info *vf = trans->vf; struct qlcnic_vf_info *vf = trans->vf;
struct qlcnic_adapter *adapter = vf->adapter; struct qlcnic_adapter *adapter = vf->adapter;
int err; int err;
u16 vlan;
err = qlcnic_sriov_validate_del_rx_ctx(vf, cmd); err = qlcnic_sriov_validate_del_rx_ctx(vf, cmd);
if (err) { if (err) {
@ -851,9 +918,7 @@ static int qlcnic_sriov_pf_del_rx_ctx_cmd(struct qlcnic_bc_trans *trans,
return err; return err;
} }
vlan = vf->vp->vlan; qlcnic_83xx_cfg_default_mac_vlan(adapter, vf, QLCNIC_MAC_DEL);
qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func,
vlan, QLCNIC_MAC_DEL);
cmd->req.arg[1] |= vf->vp->handle << 16; cmd->req.arg[1] |= vf->vp->handle << 16;
err = qlcnic_issue_cmd(adapter, cmd); err = qlcnic_issue_cmd(adapter, cmd);
@ -1120,7 +1185,7 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter,
cmd->req.arg[1] &= ~0x7; cmd->req.arg[1] &= ~0x7;
new_op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ? new_op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ?
QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL; QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL;
cmd->req.arg[3] |= vp->vlan << 16; cmd->req.arg[3] |= vp->pvid << 16;
cmd->req.arg[1] |= new_op; cmd->req.arg[1] |= new_op;
} }
@ -1190,8 +1255,10 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,
struct qlcnic_vport *vp = vf->vp; struct qlcnic_vport *vp = vf->vp;
u8 cmd_op, mode = vp->vlan_mode; u8 cmd_op, mode = vp->vlan_mode;
struct qlcnic_adapter *adapter; struct qlcnic_adapter *adapter;
struct qlcnic_sriov *sriov;
adapter = vf->adapter; adapter = vf->adapter;
sriov = adapter->ahw->sriov;
cmd_op = trans->req_hdr->cmd_op; cmd_op = trans->req_hdr->cmd_op;
cmd->rsp.arg[0] |= 1 << 25; cmd->rsp.arg[0] |= 1 << 25;
@ -1205,10 +1272,10 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,
switch (mode) { switch (mode) {
case QLC_GUEST_VLAN_MODE: case QLC_GUEST_VLAN_MODE:
cmd->rsp.arg[1] = mode | 1 << 8; cmd->rsp.arg[1] = mode | 1 << 8;
cmd->rsp.arg[2] = 1 << 16; cmd->rsp.arg[2] = sriov->num_allowed_vlans << 16;
break; break;
case QLC_PVID_MODE: case QLC_PVID_MODE:
cmd->rsp.arg[1] = mode | 1 << 8 | vp->vlan << 16; cmd->rsp.arg[1] = mode | 1 << 8 | vp->pvid << 16;
break; break;
} }
@ -1216,23 +1283,26 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,
} }
static int qlcnic_sriov_pf_del_guest_vlan(struct qlcnic_adapter *adapter, static int qlcnic_sriov_pf_del_guest_vlan(struct qlcnic_adapter *adapter,
struct qlcnic_vf_info *vf) struct qlcnic_vf_info *vf,
struct qlcnic_cmd_args *cmd)
{ {
struct qlcnic_vport *vp = vf->vp; struct qlcnic_sriov *sriov = adapter->ahw->sriov;
u16 vlan;
if (!vp->vlan) if (!qlcnic_sriov_check_any_vlan(vf))
return -EINVAL; return -EINVAL;
vlan = cmd->req.arg[1] >> 16;
if (!vf->rx_ctx_id) { if (!vf->rx_ctx_id) {
vp->vlan = 0; qlcnic_sriov_del_vlan_id(sriov, vf, vlan);
return 0; return 0;
} }
qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, qlcnic_sriov_cfg_vf_def_mac(adapter, vf, vlan, QLCNIC_MAC_DEL);
vp->vlan, QLCNIC_MAC_DEL); qlcnic_sriov_del_vlan_id(sriov, vf, vlan);
vp->vlan = 0;
qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, if (qlcnic_83xx_pf_check(adapter))
qlcnic_sriov_cfg_vf_def_mac(adapter, vf,
0, QLCNIC_MAC_ADD); 0, QLCNIC_MAC_ADD);
return 0; return 0;
} }
@ -1241,32 +1311,37 @@ static int qlcnic_sriov_pf_add_guest_vlan(struct qlcnic_adapter *adapter,
struct qlcnic_vf_info *vf, struct qlcnic_vf_info *vf,
struct qlcnic_cmd_args *cmd) struct qlcnic_cmd_args *cmd)
{ {
struct qlcnic_vport *vp = vf->vp; struct qlcnic_sriov *sriov = adapter->ahw->sriov;
int err = -EIO; int err = -EIO;
u16 vlan;
if (vp->vlan) if (qlcnic_83xx_pf_check(adapter) && qlcnic_sriov_check_any_vlan(vf))
return err; return err;
vlan = cmd->req.arg[1] >> 16;
if (!vf->rx_ctx_id) { if (!vf->rx_ctx_id) {
vp->vlan = cmd->req.arg[1] >> 16; qlcnic_sriov_add_vlan_id(sriov, vf, vlan);
return 0; return 0;
} }
err = qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, if (qlcnic_83xx_pf_check(adapter)) {
0, QLCNIC_MAC_DEL); err = qlcnic_sriov_cfg_vf_def_mac(adapter, vf, 0,
QLCNIC_MAC_DEL);
if (err) if (err)
return err; return err;
vp->vlan = cmd->req.arg[1] >> 16;
err = qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func,
vp->vlan, QLCNIC_MAC_ADD);
if (err) {
qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func,
0, QLCNIC_MAC_ADD);
vp->vlan = 0;
} }
err = qlcnic_sriov_cfg_vf_def_mac(adapter, vf, vlan, QLCNIC_MAC_ADD);
if (err) {
if (qlcnic_83xx_pf_check(adapter))
qlcnic_sriov_cfg_vf_def_mac(adapter, vf, 0,
QLCNIC_MAC_ADD);
return err;
}
qlcnic_sriov_add_vlan_id(sriov, vf, vlan);
return err; return err;
} }
@ -1289,7 +1364,7 @@ static int qlcnic_sriov_pf_cfg_guest_vlan_cmd(struct qlcnic_bc_trans *tran,
if (op) if (op)
err = qlcnic_sriov_pf_add_guest_vlan(adapter, vf, cmd); err = qlcnic_sriov_pf_add_guest_vlan(adapter, vf, cmd);
else else
err = qlcnic_sriov_pf_del_guest_vlan(adapter, vf); err = qlcnic_sriov_pf_del_guest_vlan(adapter, vf, cmd);
cmd->rsp.arg[0] |= err ? 2 << 25 : 1 << 25; cmd->rsp.arg[0] |= err ? 2 << 25 : 1 << 25;
return err; return err;
@ -1594,7 +1669,8 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
} }
if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) if (vp->vlan_mode == QLC_GUEST_VLAN_MODE)
vp->vlan = 0; memset(vf->sriov_vlans, 0,
sizeof(*vf->sriov_vlans) * sriov->num_allowed_vlans);
qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr); qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr);
netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func); netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func);
@ -1764,20 +1840,22 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
memset(vf_info->sriov_vlans, 0,
sizeof(*vf_info->sriov_vlans) * sriov->num_allowed_vlans);
switch (vlan) { switch (vlan) {
case 4095: case 4095:
vp->vlan = 0;
vp->vlan_mode = QLC_GUEST_VLAN_MODE; vp->vlan_mode = QLC_GUEST_VLAN_MODE;
break; break;
case 0: case 0:
vp->vlan_mode = QLC_NO_VLAN_MODE; vp->vlan_mode = QLC_NO_VLAN_MODE;
vp->vlan = 0;
vp->qos = 0; vp->qos = 0;
break; break;
default: default:
vp->vlan_mode = QLC_PVID_MODE; vp->vlan_mode = QLC_PVID_MODE;
vp->vlan = vlan; qlcnic_sriov_add_vlan_id(sriov, vf_info, vlan);
vp->qos = qos; vp->qos = qos;
vp->pvid = vlan;
} }
netdev_info(netdev, "Setting VLAN %d, QoS %d, for VF %d\n", netdev_info(netdev, "Setting VLAN %d, QoS %d, for VF %d\n",
@ -1792,7 +1870,7 @@ static __u32 qlcnic_sriov_get_vf_vlan(struct qlcnic_adapter *adapter,
switch (vp->vlan_mode) { switch (vp->vlan_mode) {
case QLC_PVID_MODE: case QLC_PVID_MODE:
vlan = vp->vlan; vlan = vp->pvid;
break; break;
case QLC_GUEST_VLAN_MODE: case QLC_GUEST_VLAN_MODE:
vlan = MAX_VLAN_ID; vlan = MAX_VLAN_ID;