Commit d1163e91 authored by David S. Miller's avatar David S. Miller

Merge branch 'be2net-fixes'

Sathya Perla says:

====================
be2net: patch set

This patch set contains 2 driver fixes to a Lancer HW issue and a fix
to a double free bug. Pls apply to the "net" tree. Thanks!

Patch 1 now enables filters only after creating RXQs. This is done as
HW issues were observed on Lancer adapters if filters
(flags, mac addrs etc) are enabled *before* creating RXQs. This patch
changes the driver design by enabling filters in be_open() --
instead of be_setup() -- after RXQs are created and buffers posted.

Patch 2 fixes an RX stall issue that was seen on Lancer adapters when
RXQs are destroyed while they are in an "out of buffer" state.
This patch fixes this issue by posting 64 buffers to each RXQ before
destroying them in the close path. This is done after ensuring that no
more new packets are selected for transfer to the RXQs by disabling
interface filters.

Patch 3 protects eqo->affinity_mask variable from being freed twice and
resulting in a crash.  It's now freed only when EQs haven't yet been
destroyed.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 48900cb6 649886a3
...@@ -620,6 +620,11 @@ enum be_if_flags { ...@@ -620,6 +620,11 @@ enum be_if_flags {
BE_IF_FLAGS_VLAN_PROMISCUOUS |\ BE_IF_FLAGS_VLAN_PROMISCUOUS |\
BE_IF_FLAGS_MCAST_PROMISCUOUS) BE_IF_FLAGS_MCAST_PROMISCUOUS)
#define BE_IF_EN_FLAGS (BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |\
BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_UNTAGGED)
#define BE_IF_ALL_FILT_FLAGS (BE_IF_EN_FLAGS | BE_IF_FLAGS_ALL_PROMISCUOUS)
/* An RX interface is an object with one or more MAC addresses and /* An RX interface is an object with one or more MAC addresses and
* filtering capabilities. */ * filtering capabilities. */
struct be_cmd_req_if_create { struct be_cmd_req_if_create {
......
...@@ -273,6 +273,10 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) ...@@ -273,6 +273,10 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
if (ether_addr_equal(addr->sa_data, netdev->dev_addr)) if (ether_addr_equal(addr->sa_data, netdev->dev_addr))
return 0; return 0;
/* if device is not running, copy MAC to netdev->dev_addr */
if (!netif_running(netdev))
goto done;
/* The PMAC_ADD cmd may fail if the VF doesn't have FILTMGMT /* The PMAC_ADD cmd may fail if the VF doesn't have FILTMGMT
* privilege or if PF did not provision the new MAC address. * privilege or if PF did not provision the new MAC address.
* On BE3, this cmd will always fail if the VF doesn't have the * On BE3, this cmd will always fail if the VF doesn't have the
...@@ -307,9 +311,9 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) ...@@ -307,9 +311,9 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
status = -EPERM; status = -EPERM;
goto err; goto err;
} }
done:
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ether_addr_copy(netdev->dev_addr, addr->sa_data);
dev_info(dev, "MAC address changed to %pM\n", mac); dev_info(dev, "MAC address changed to %pM\n", addr->sa_data);
return 0; return 0;
err: err:
dev_warn(dev, "MAC address change to %pM failed\n", addr->sa_data); dev_warn(dev, "MAC address change to %pM failed\n", addr->sa_data);
...@@ -2447,10 +2451,24 @@ static void be_eq_clean(struct be_eq_obj *eqo) ...@@ -2447,10 +2451,24 @@ static void be_eq_clean(struct be_eq_obj *eqo)
be_eq_notify(eqo->adapter, eqo->q.id, false, true, num, 0); be_eq_notify(eqo->adapter, eqo->q.id, false, true, num, 0);
} }
static void be_rx_cq_clean(struct be_rx_obj *rxo) /* Free posted rx buffers that were not used */
static void be_rxq_clean(struct be_rx_obj *rxo)
{ {
struct be_rx_page_info *page_info;
struct be_queue_info *rxq = &rxo->q; struct be_queue_info *rxq = &rxo->q;
struct be_rx_page_info *page_info;
while (atomic_read(&rxq->used) > 0) {
page_info = get_rx_page_info(rxo);
put_page(page_info->page);
memset(page_info, 0, sizeof(*page_info));
}
BUG_ON(atomic_read(&rxq->used));
rxq->tail = 0;
rxq->head = 0;
}
static void be_rx_cq_clean(struct be_rx_obj *rxo)
{
struct be_queue_info *rx_cq = &rxo->cq; struct be_queue_info *rx_cq = &rxo->cq;
struct be_rx_compl_info *rxcp; struct be_rx_compl_info *rxcp;
struct be_adapter *adapter = rxo->adapter; struct be_adapter *adapter = rxo->adapter;
...@@ -2487,16 +2505,6 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo) ...@@ -2487,16 +2505,6 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
/* After cleanup, leave the CQ in unarmed state */ /* After cleanup, leave the CQ in unarmed state */
be_cq_notify(adapter, rx_cq->id, false, 0); be_cq_notify(adapter, rx_cq->id, false, 0);
/* Then free posted rx buffers that were not used */
while (atomic_read(&rxq->used) > 0) {
page_info = get_rx_page_info(rxo);
put_page(page_info->page);
memset(page_info, 0, sizeof(*page_info));
}
BUG_ON(atomic_read(&rxq->used));
rxq->tail = 0;
rxq->head = 0;
} }
static void be_tx_compl_clean(struct be_adapter *adapter) static void be_tx_compl_clean(struct be_adapter *adapter)
...@@ -2576,8 +2584,8 @@ static void be_evt_queues_destroy(struct be_adapter *adapter) ...@@ -2576,8 +2584,8 @@ static void be_evt_queues_destroy(struct be_adapter *adapter)
be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ); be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ);
napi_hash_del(&eqo->napi); napi_hash_del(&eqo->napi);
netif_napi_del(&eqo->napi); netif_napi_del(&eqo->napi);
free_cpumask_var(eqo->affinity_mask);
} }
free_cpumask_var(eqo->affinity_mask);
be_queue_free(adapter, &eqo->q); be_queue_free(adapter, &eqo->q);
} }
} }
...@@ -2594,13 +2602,7 @@ static int be_evt_queues_create(struct be_adapter *adapter) ...@@ -2594,13 +2602,7 @@ static int be_evt_queues_create(struct be_adapter *adapter)
for_all_evt_queues(adapter, eqo, i) { for_all_evt_queues(adapter, eqo, i) {
int numa_node = dev_to_node(&adapter->pdev->dev); int numa_node = dev_to_node(&adapter->pdev->dev);
if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL))
return -ENOMEM;
cpumask_set_cpu(cpumask_local_spread(i, numa_node),
eqo->affinity_mask);
netif_napi_add(adapter->netdev, &eqo->napi, be_poll,
BE_NAPI_WEIGHT);
napi_hash_add(&eqo->napi);
aic = &adapter->aic_obj[i]; aic = &adapter->aic_obj[i];
eqo->adapter = adapter; eqo->adapter = adapter;
eqo->idx = i; eqo->idx = i;
...@@ -2616,6 +2618,14 @@ static int be_evt_queues_create(struct be_adapter *adapter) ...@@ -2616,6 +2618,14 @@ static int be_evt_queues_create(struct be_adapter *adapter)
rc = be_cmd_eq_create(adapter, eqo); rc = be_cmd_eq_create(adapter, eqo);
if (rc) if (rc)
return rc; return rc;
if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL))
return -ENOMEM;
cpumask_set_cpu(cpumask_local_spread(i, numa_node),
eqo->affinity_mask);
netif_napi_add(adapter->netdev, &eqo->napi, be_poll,
BE_NAPI_WEIGHT);
napi_hash_add(&eqo->napi);
} }
return 0; return 0;
} }
...@@ -3354,13 +3364,54 @@ static void be_rx_qs_destroy(struct be_adapter *adapter) ...@@ -3354,13 +3364,54 @@ static void be_rx_qs_destroy(struct be_adapter *adapter)
for_all_rx_queues(adapter, rxo, i) { for_all_rx_queues(adapter, rxo, i) {
q = &rxo->q; q = &rxo->q;
if (q->created) { if (q->created) {
/* If RXQs are destroyed while in an "out of buffer"
* state, there is a possibility of an HW stall on
* Lancer. So, post 64 buffers to each queue to relieve
* the "out of buffer" condition.
* Make sure there's space in the RXQ before posting.
*/
if (lancer_chip(adapter)) {
be_rx_cq_clean(rxo);
if (atomic_read(&q->used) == 0)
be_post_rx_frags(rxo, GFP_KERNEL,
MAX_RX_POST);
}
be_cmd_rxq_destroy(adapter, q); be_cmd_rxq_destroy(adapter, q);
be_rx_cq_clean(rxo); be_rx_cq_clean(rxo);
be_rxq_clean(rxo);
} }
be_queue_free(adapter, q); be_queue_free(adapter, q);
} }
} }
static void be_disable_if_filters(struct be_adapter *adapter)
{
be_cmd_pmac_del(adapter, adapter->if_handle,
adapter->pmac_id[0], 0);
be_clear_uc_list(adapter);
/* The IFACE flags are enabled in the open path and cleared
* in the close path. When a VF gets detached from the host and
* assigned to a VM the following happens:
* - VF's IFACE flags get cleared in the detach path
* - IFACE create is issued by the VF in the attach path
* Due to a bug in the BE3/Skyhawk-R FW
* (Lancer FW doesn't have the bug), the IFACE capability flags
* specified along with the IFACE create cmd issued by a VF are not
* honoured by FW. As a consequence, if a *new* driver
* (that enables/disables IFACE flags in open/close)
* is loaded in the host and an *old* driver is * used by a VM/VF,
* the IFACE gets created *without* the needed flags.
* To avoid this, disable RX-filter flags only for Lancer.
*/
if (lancer_chip(adapter)) {
be_cmd_rx_filter(adapter, BE_IF_ALL_FILT_FLAGS, OFF);
adapter->if_flags &= ~BE_IF_ALL_FILT_FLAGS;
}
}
static int be_close(struct net_device *netdev) static int be_close(struct net_device *netdev)
{ {
struct be_adapter *adapter = netdev_priv(netdev); struct be_adapter *adapter = netdev_priv(netdev);
...@@ -3373,6 +3424,8 @@ static int be_close(struct net_device *netdev) ...@@ -3373,6 +3424,8 @@ static int be_close(struct net_device *netdev)
if (!(adapter->flags & BE_FLAGS_SETUP_DONE)) if (!(adapter->flags & BE_FLAGS_SETUP_DONE))
return 0; return 0;
be_disable_if_filters(adapter);
be_roce_dev_close(adapter); be_roce_dev_close(adapter);
if (adapter->flags & BE_FLAGS_NAPI_ENABLED) { if (adapter->flags & BE_FLAGS_NAPI_ENABLED) {
...@@ -3392,7 +3445,6 @@ static int be_close(struct net_device *netdev) ...@@ -3392,7 +3445,6 @@ static int be_close(struct net_device *netdev)
be_tx_compl_clean(adapter); be_tx_compl_clean(adapter);
be_rx_qs_destroy(adapter); be_rx_qs_destroy(adapter);
be_clear_uc_list(adapter);
for_all_evt_queues(adapter, eqo, i) { for_all_evt_queues(adapter, eqo, i) {
if (msix_enabled(adapter)) if (msix_enabled(adapter))
...@@ -3477,6 +3529,31 @@ static int be_rx_qs_create(struct be_adapter *adapter) ...@@ -3477,6 +3529,31 @@ static int be_rx_qs_create(struct be_adapter *adapter)
return 0; return 0;
} }
static int be_enable_if_filters(struct be_adapter *adapter)
{
int status;
status = be_cmd_rx_filter(adapter, BE_IF_EN_FLAGS, ON);
if (status)
return status;
/* For BE3 VFs, the PF programs the initial MAC address */
if (!(BEx_chip(adapter) && be_virtfn(adapter))) {
status = be_cmd_pmac_add(adapter, adapter->netdev->dev_addr,
adapter->if_handle,
&adapter->pmac_id[0], 0);
if (status)
return status;
}
if (adapter->vlans_added)
be_vid_config(adapter);
be_set_rx_mode(adapter->netdev);
return 0;
}
static int be_open(struct net_device *netdev) static int be_open(struct net_device *netdev)
{ {
struct be_adapter *adapter = netdev_priv(netdev); struct be_adapter *adapter = netdev_priv(netdev);
...@@ -3490,6 +3567,10 @@ static int be_open(struct net_device *netdev) ...@@ -3490,6 +3567,10 @@ static int be_open(struct net_device *netdev)
if (status) if (status)
goto err; goto err;
status = be_enable_if_filters(adapter);
if (status)
goto err;
status = be_irq_register(adapter); status = be_irq_register(adapter);
if (status) if (status)
goto err; goto err;
...@@ -3686,16 +3767,6 @@ static void be_cancel_err_detection(struct be_adapter *adapter) ...@@ -3686,16 +3767,6 @@ static void be_cancel_err_detection(struct be_adapter *adapter)
} }
} }
static void be_mac_clear(struct be_adapter *adapter)
{
if (adapter->pmac_id) {
be_cmd_pmac_del(adapter, adapter->if_handle,
adapter->pmac_id[0], 0);
kfree(adapter->pmac_id);
adapter->pmac_id = NULL;
}
}
#ifdef CONFIG_BE2NET_VXLAN #ifdef CONFIG_BE2NET_VXLAN
static void be_disable_vxlan_offloads(struct be_adapter *adapter) static void be_disable_vxlan_offloads(struct be_adapter *adapter)
{ {
...@@ -3770,8 +3841,8 @@ static int be_clear(struct be_adapter *adapter) ...@@ -3770,8 +3841,8 @@ static int be_clear(struct be_adapter *adapter)
#ifdef CONFIG_BE2NET_VXLAN #ifdef CONFIG_BE2NET_VXLAN
be_disable_vxlan_offloads(adapter); be_disable_vxlan_offloads(adapter);
#endif #endif
/* delete the primary mac along with the uc-mac list */ kfree(adapter->pmac_id);
be_mac_clear(adapter); adapter->pmac_id = NULL;
be_cmd_if_destroy(adapter, adapter->if_handle, 0); be_cmd_if_destroy(adapter, adapter->if_handle, 0);
...@@ -3782,25 +3853,11 @@ static int be_clear(struct be_adapter *adapter) ...@@ -3782,25 +3853,11 @@ static int be_clear(struct be_adapter *adapter)
return 0; return 0;
} }
static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
u32 cap_flags, u32 vf)
{
u32 en_flags;
en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS;
en_flags &= cap_flags;
return be_cmd_if_create(adapter, cap_flags, en_flags, if_handle, vf);
}
static int be_vfs_if_create(struct be_adapter *adapter) static int be_vfs_if_create(struct be_adapter *adapter)
{ {
struct be_resources res = {0}; struct be_resources res = {0};
u32 cap_flags, en_flags, vf;
struct be_vf_cfg *vf_cfg; struct be_vf_cfg *vf_cfg;
u32 cap_flags, vf;
int status; int status;
/* If a FW profile exists, then cap_flags are updated */ /* If a FW profile exists, then cap_flags are updated */
...@@ -3821,8 +3878,12 @@ static int be_vfs_if_create(struct be_adapter *adapter) ...@@ -3821,8 +3878,12 @@ static int be_vfs_if_create(struct be_adapter *adapter)
} }
} }
status = be_if_create(adapter, &vf_cfg->if_handle, en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
cap_flags, vf + 1); BE_IF_FLAGS_BROADCAST |
BE_IF_FLAGS_MULTICAST |
BE_IF_FLAGS_PASS_L3L4_ERRORS);
status = be_cmd_if_create(adapter, cap_flags, en_flags,
&vf_cfg->if_handle, vf + 1);
if (status) if (status)
return status; return status;
} }
...@@ -4194,15 +4255,8 @@ static int be_mac_setup(struct be_adapter *adapter) ...@@ -4194,15 +4255,8 @@ static int be_mac_setup(struct be_adapter *adapter)
memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
} else {
/* Maybe the HW was reset; dev_addr must be re-programmed */
memcpy(mac, adapter->netdev->dev_addr, ETH_ALEN);
} }
/* For BE3-R VFs, the PF programs the initial MAC address */
if (!(BEx_chip(adapter) && be_virtfn(adapter)))
be_cmd_pmac_add(adapter, mac, adapter->if_handle,
&adapter->pmac_id[0], 0);
return 0; return 0;
} }
...@@ -4342,6 +4396,7 @@ static int be_func_init(struct be_adapter *adapter) ...@@ -4342,6 +4396,7 @@ static int be_func_init(struct be_adapter *adapter)
static int be_setup(struct be_adapter *adapter) static int be_setup(struct be_adapter *adapter)
{ {
struct device *dev = &adapter->pdev->dev; struct device *dev = &adapter->pdev->dev;
u32 en_flags;
int status; int status;
status = be_func_init(adapter); status = be_func_init(adapter);
...@@ -4364,8 +4419,11 @@ static int be_setup(struct be_adapter *adapter) ...@@ -4364,8 +4419,11 @@ static int be_setup(struct be_adapter *adapter)
if (status) if (status)
goto err; goto err;
status = be_if_create(adapter, &adapter->if_handle, /* will enable all the needed filter flags in be_open() */
be_if_cap_flags(adapter), 0); en_flags = BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS;
en_flags = en_flags & be_if_cap_flags(adapter);
status = be_cmd_if_create(adapter, be_if_cap_flags(adapter), en_flags,
&adapter->if_handle, 0);
if (status) if (status)
goto err; goto err;
...@@ -4391,11 +4449,6 @@ static int be_setup(struct be_adapter *adapter) ...@@ -4391,11 +4449,6 @@ static int be_setup(struct be_adapter *adapter)
dev_err(dev, "Please upgrade firmware to version >= 4.0\n"); dev_err(dev, "Please upgrade firmware to version >= 4.0\n");
} }
if (adapter->vlans_added)
be_vid_config(adapter);
be_set_rx_mode(adapter->netdev);
status = be_cmd_set_flow_control(adapter, adapter->tx_fc, status = be_cmd_set_flow_control(adapter, adapter->tx_fc,
adapter->rx_fc); adapter->rx_fc);
if (status) if (status)
......
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