|
@@ -39,6 +39,8 @@ static int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *, u8);
|
|
|
static void qlcnic_sriov_process_bc_cmd(struct work_struct *);
|
|
|
static int qlcnic_sriov_vf_shutdown(struct pci_dev *);
|
|
|
static int qlcnic_sriov_vf_resume(struct qlcnic_adapter *);
|
|
|
+static int qlcnic_sriov_async_issue_cmd(struct qlcnic_adapter *,
|
|
|
+ struct qlcnic_cmd_args *);
|
|
|
|
|
|
static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
|
|
|
.read_crb = qlcnic_83xx_read_crb,
|
|
@@ -181,7 +183,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);
|
|
|
+ spin_lock_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);
|
|
@@ -1356,7 +1358,7 @@ static int qlcnic_sriov_retry_bc_cmd(struct qlcnic_adapter *adapter,
|
|
|
return -EIO;
|
|
|
}
|
|
|
|
|
|
-static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,
|
|
|
+static int __qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,
|
|
|
struct qlcnic_cmd_args *cmd)
|
|
|
{
|
|
|
struct qlcnic_hardware_context *ahw = adapter->ahw;
|
|
@@ -1428,6 +1430,16 @@ cleanup_transaction:
|
|
|
return rsp;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,
|
|
|
+ struct qlcnic_cmd_args *cmd)
|
|
|
+{
|
|
|
+ if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT)
|
|
|
+ return qlcnic_sriov_async_issue_cmd(adapter, cmd);
|
|
|
+ else
|
|
|
+ return __qlcnic_sriov_issue_cmd(adapter, cmd);
|
|
|
+}
|
|
|
+
|
|
|
static int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op)
|
|
|
{
|
|
|
struct qlcnic_cmd_args cmd;
|
|
@@ -1458,58 +1470,28 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void qlcnic_vf_add_mc_list(struct net_device *netdev)
|
|
|
+static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac)
|
|
|
{
|
|
|
struct qlcnic_adapter *adapter = netdev_priv(netdev);
|
|
|
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_vlan_list, list);
|
|
|
- list_move(&cur->list, &tmp_list);
|
|
|
- }
|
|
|
-
|
|
|
- netif_addr_unlock_bh(netdev);
|
|
|
|
|
|
- while (!list_empty(&tmp_list)) {
|
|
|
- cur = list_entry((&tmp_list)->next,
|
|
|
- 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);
|
|
|
- }
|
|
|
+ if (!qlcnic_sriov_check_any_vlan(vf)) {
|
|
|
+ qlcnic_nic_add_mac(adapter, mac, 0);
|
|
|
+ } else {
|
|
|
+ spin_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, mac, vlan_id);
|
|
|
}
|
|
|
- list_del(&cur->list);
|
|
|
- kfree(cur);
|
|
|
+ spin_unlock(&vf->vlan_list_lock);
|
|
|
+ if (qlcnic_84xx_check(adapter))
|
|
|
+ qlcnic_nic_add_mac(adapter, mac, 0);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1518,6 +1500,7 @@ void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *bc)
|
|
|
struct list_head *head = &bc->async_list;
|
|
|
struct qlcnic_async_work_list *entry;
|
|
|
|
|
|
+ flush_workqueue(bc->bc_async_wq);
|
|
|
while (!list_empty(head)) {
|
|
|
entry = list_entry(head->next, struct qlcnic_async_work_list,
|
|
|
list);
|
|
@@ -1527,10 +1510,14 @@ void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *bc)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
|
|
|
+void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
|
|
|
{
|
|
|
struct qlcnic_adapter *adapter = netdev_priv(netdev);
|
|
|
struct qlcnic_hardware_context *ahw = adapter->ahw;
|
|
|
+ static const u8 bcast_addr[ETH_ALEN] = {
|
|
|
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
|
|
+ };
|
|
|
+ struct netdev_hw_addr *ha;
|
|
|
u32 mode = VPORT_MISS_MODE_DROP;
|
|
|
|
|
|
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
|
|
@@ -1542,23 +1529,27 @@ static void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
|
|
|
} else if ((netdev->flags & IFF_ALLMULTI) ||
|
|
|
(netdev_mc_count(netdev) > ahw->max_mc_count)) {
|
|
|
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
|
|
|
+ } else {
|
|
|
+ qlcnic_vf_add_mc_list(netdev, bcast_addr);
|
|
|
+ if (!netdev_mc_empty(netdev)) {
|
|
|
+ netdev_for_each_mc_addr(ha, netdev)
|
|
|
+ qlcnic_vf_add_mc_list(netdev, ha->addr);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- 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_issue_cmd(struct work_struct *work)
|
|
|
{
|
|
|
struct qlcnic_async_work_list *entry;
|
|
|
- struct net_device *netdev;
|
|
|
+ struct qlcnic_adapter *adapter;
|
|
|
+ struct qlcnic_cmd_args *cmd;
|
|
|
|
|
|
entry = container_of(work, struct qlcnic_async_work_list, work);
|
|
|
- netdev = (struct net_device *)entry->ptr;
|
|
|
-
|
|
|
- qlcnic_sriov_vf_set_multi(netdev);
|
|
|
+ adapter = entry->ptr;
|
|
|
+ cmd = entry->cmd;
|
|
|
+ __qlcnic_sriov_issue_cmd(adapter, cmd);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -1588,8 +1579,9 @@ qlcnic_sriov_get_free_node_async_work(struct qlcnic_back_channel *bc)
|
|
|
return entry;
|
|
|
}
|
|
|
|
|
|
-static void qlcnic_sriov_schedule_bc_async_work(struct qlcnic_back_channel *bc,
|
|
|
- work_func_t func, void *data)
|
|
|
+static void qlcnic_sriov_schedule_async_cmd(struct qlcnic_back_channel *bc,
|
|
|
+ work_func_t func, void *data,
|
|
|
+ struct qlcnic_cmd_args *cmd)
|
|
|
{
|
|
|
struct qlcnic_async_work_list *entry = NULL;
|
|
|
|
|
@@ -1598,21 +1590,23 @@ static void qlcnic_sriov_schedule_bc_async_work(struct qlcnic_back_channel *bc,
|
|
|
return;
|
|
|
|
|
|
entry->ptr = data;
|
|
|
+ entry->cmd = cmd;
|
|
|
INIT_WORK(&entry->work, func);
|
|
|
queue_work(bc->bc_async_wq, &entry->work);
|
|
|
}
|
|
|
|
|
|
-void qlcnic_sriov_vf_schedule_multi(struct net_device *netdev)
|
|
|
+static int qlcnic_sriov_async_issue_cmd(struct qlcnic_adapter *adapter,
|
|
|
+ struct qlcnic_cmd_args *cmd)
|
|
|
{
|
|
|
|
|
|
- struct qlcnic_adapter *adapter = netdev_priv(netdev);
|
|
|
struct qlcnic_back_channel *bc = &adapter->ahw->sriov->bc;
|
|
|
|
|
|
if (adapter->need_fw_reset)
|
|
|
- return;
|
|
|
+ return -EIO;
|
|
|
|
|
|
- qlcnic_sriov_schedule_bc_async_work(bc, qlcnic_sriov_handle_async_multi,
|
|
|
- netdev);
|
|
|
+ qlcnic_sriov_schedule_async_cmd(bc, qlcnic_sriov_handle_async_issue_cmd,
|
|
|
+ adapter, cmd);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter)
|
|
@@ -1890,7 +1884,7 @@ static int qlcnic_sriov_check_vlan_id(struct qlcnic_sriov *sriov,
|
|
|
if (!vf->sriov_vlans)
|
|
|
return err;
|
|
|
|
|
|
- mutex_lock(&vf->vlan_list_lock);
|
|
|
+ spin_lock_bh(&vf->vlan_list_lock);
|
|
|
|
|
|
for (i = 0; i < sriov->num_allowed_vlans; i++) {
|
|
|
if (vf->sriov_vlans[i] == vlan_id) {
|
|
@@ -1899,7 +1893,7 @@ static int qlcnic_sriov_check_vlan_id(struct qlcnic_sriov *sriov,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- mutex_unlock(&vf->vlan_list_lock);
|
|
|
+ spin_unlock_bh(&vf->vlan_list_lock);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -1908,12 +1902,12 @@ static int qlcnic_sriov_validate_num_vlans(struct qlcnic_sriov *sriov,
|
|
|
{
|
|
|
int err = 0;
|
|
|
|
|
|
- mutex_lock(&vf->vlan_list_lock);
|
|
|
+ spin_lock_bh(&vf->vlan_list_lock);
|
|
|
|
|
|
if (vf->num_vlan >= sriov->num_allowed_vlans)
|
|
|
err = -EINVAL;
|
|
|
|
|
|
- mutex_unlock(&vf->vlan_list_lock);
|
|
|
+ spin_unlock_bh(&vf->vlan_list_lock);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -1966,7 +1960,7 @@ static void qlcnic_sriov_vlan_operation(struct qlcnic_vf_info *vf, u16 vlan_id,
|
|
|
if (!vf->sriov_vlans)
|
|
|
return;
|
|
|
|
|
|
- mutex_lock(&vf->vlan_list_lock);
|
|
|
+ spin_lock_bh(&vf->vlan_list_lock);
|
|
|
|
|
|
switch (opcode) {
|
|
|
case QLC_VLAN_ADD:
|
|
@@ -1979,7 +1973,7 @@ static void qlcnic_sriov_vlan_operation(struct qlcnic_vf_info *vf, u16 vlan_id,
|
|
|
netdev_err(adapter->netdev, "Invalid VLAN operation\n");
|
|
|
}
|
|
|
|
|
|
- mutex_unlock(&vf->vlan_list_lock);
|
|
|
+ spin_unlock_bh(&vf->vlan_list_lock);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -1987,6 +1981,7 @@ int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,
|
|
|
u16 vid, u8 enable)
|
|
|
{
|
|
|
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
|
|
|
+ struct net_device *netdev = adapter->netdev;
|
|
|
struct qlcnic_vf_info *vf;
|
|
|
struct qlcnic_cmd_args cmd;
|
|
|
int ret;
|
|
@@ -2012,14 +2007,18 @@ int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,
|
|
|
dev_err(&adapter->pdev->dev,
|
|
|
"Failed to configure guest VLAN, err=%d\n", ret);
|
|
|
} else {
|
|
|
+ netif_addr_lock_bh(netdev);
|
|
|
qlcnic_free_mac_list(adapter);
|
|
|
+ netif_addr_unlock_bh(netdev);
|
|
|
|
|
|
if (enable)
|
|
|
qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_ADD);
|
|
|
else
|
|
|
qlcnic_sriov_vlan_operation(vf, vid, QLC_VLAN_DELETE);
|
|
|
|
|
|
- qlcnic_set_multi(adapter->netdev);
|
|
|
+ netif_addr_lock_bh(netdev);
|
|
|
+ qlcnic_set_multi(netdev);
|
|
|
+ netif_addr_unlock_bh(netdev);
|
|
|
}
|
|
|
|
|
|
qlcnic_free_mbx_args(&cmd);
|
|
@@ -2150,11 +2149,11 @@ bool qlcnic_sriov_check_any_vlan(struct qlcnic_vf_info *vf)
|
|
|
{
|
|
|
bool err = false;
|
|
|
|
|
|
- mutex_lock(&vf->vlan_list_lock);
|
|
|
+ spin_lock_bh(&vf->vlan_list_lock);
|
|
|
|
|
|
if (vf->num_vlan)
|
|
|
err = true;
|
|
|
|
|
|
- mutex_unlock(&vf->vlan_list_lock);
|
|
|
+ spin_unlock_bh(&vf->vlan_list_lock);
|
|
|
return err;
|
|
|
}
|