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 { ...@@ -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); ...@@ -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) ...@@ -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_ */
...@@ -1637,7 +1637,7 @@ int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) ...@@ -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;
......
...@@ -324,6 +324,11 @@ struct qlc_83xx_idc { ...@@ -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,
......
...@@ -455,13 +455,13 @@ int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, ...@@ -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) ...@@ -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) ...@@ -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,8 +518,7 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) ...@@ -516,8 +518,7 @@ 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);
if (netdev->flags & IFF_PROMISC) { if (netdev->flags & IFF_PROMISC) {
...@@ -526,15 +527,11 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 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) ...@@ -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 = 1;
adapter->drv_mac_learn = true; } else {
} else { adapter->drv_mac_learn = 0;
adapter->drv_mac_learn = false;
}
} }
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) ...@@ -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) ...@@ -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);
......
...@@ -308,11 +308,11 @@ int qlcnic_read_mac_addr(struct qlcnic_adapter *adapter) ...@@ -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);
......
...@@ -126,8 +126,8 @@ struct qlcnic_vport { ...@@ -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 { ...@@ -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 { ...@@ -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 *, ...@@ -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)
{ {
......
...@@ -176,6 +176,7 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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 @@ int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op) ...@@ -1441,18 +1456,27 @@ int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op)
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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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;
}
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