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: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
d1163e91ce
|
@ -620,6 +620,11 @@ enum be_if_flags {
|
|||
BE_IF_FLAGS_VLAN_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
|
||||
* filtering capabilities. */
|
||||
struct be_cmd_req_if_create {
|
||||
|
|
|
@ -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))
|
||||
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
|
||||
* 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
|
||||
|
@ -307,9 +311,9 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
|
|||
status = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
|
||||
dev_info(dev, "MAC address changed to %pM\n", mac);
|
||||
done:
|
||||
ether_addr_copy(netdev->dev_addr, addr->sa_data);
|
||||
dev_info(dev, "MAC address changed to %pM\n", addr->sa_data);
|
||||
return 0;
|
||||
err:
|
||||
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)
|
|||
be_eq_notify(eqo->adapter, eqo->q.id, false, true, num, 0);
|
||||
}
|
||||
|
||||
/* Free posted rx buffers that were not used */
|
||||
static void be_rxq_clean(struct be_rx_obj *rxo)
|
||||
{
|
||||
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_rx_page_info *page_info;
|
||||
struct be_queue_info *rxq = &rxo->q;
|
||||
struct be_queue_info *rx_cq = &rxo->cq;
|
||||
struct be_rx_compl_info *rxcp;
|
||||
struct be_adapter *adapter = rxo->adapter;
|
||||
|
@ -2487,16 +2505,6 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
|
|||
|
||||
/* After cleanup, leave the CQ in unarmed state */
|
||||
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)
|
||||
|
@ -2576,8 +2584,8 @@ static void be_evt_queues_destroy(struct be_adapter *adapter)
|
|||
be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ);
|
||||
napi_hash_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);
|
||||
}
|
||||
}
|
||||
|
@ -2594,13 +2602,7 @@ static int be_evt_queues_create(struct be_adapter *adapter)
|
|||
|
||||
for_all_evt_queues(adapter, eqo, i) {
|
||||
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];
|
||||
eqo->adapter = adapter;
|
||||
eqo->idx = i;
|
||||
|
@ -2616,6 +2618,14 @@ static int be_evt_queues_create(struct be_adapter *adapter)
|
|||
rc = be_cmd_eq_create(adapter, eqo);
|
||||
if (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;
|
||||
}
|
||||
|
@ -3354,13 +3364,54 @@ static void be_rx_qs_destroy(struct be_adapter *adapter)
|
|||
for_all_rx_queues(adapter, rxo, i) {
|
||||
q = &rxo->q;
|
||||
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_rx_cq_clean(rxo);
|
||||
be_rxq_clean(rxo);
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct be_adapter *adapter = netdev_priv(netdev);
|
||||
|
@ -3373,6 +3424,8 @@ static int be_close(struct net_device *netdev)
|
|||
if (!(adapter->flags & BE_FLAGS_SETUP_DONE))
|
||||
return 0;
|
||||
|
||||
be_disable_if_filters(adapter);
|
||||
|
||||
be_roce_dev_close(adapter);
|
||||
|
||||
if (adapter->flags & BE_FLAGS_NAPI_ENABLED) {
|
||||
|
@ -3392,7 +3445,6 @@ static int be_close(struct net_device *netdev)
|
|||
be_tx_compl_clean(adapter);
|
||||
|
||||
be_rx_qs_destroy(adapter);
|
||||
be_clear_uc_list(adapter);
|
||||
|
||||
for_all_evt_queues(adapter, eqo, i) {
|
||||
if (msix_enabled(adapter))
|
||||
|
@ -3477,6 +3529,31 @@ static int be_rx_qs_create(struct be_adapter *adapter)
|
|||
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)
|
||||
{
|
||||
struct be_adapter *adapter = netdev_priv(netdev);
|
||||
|
@ -3490,6 +3567,10 @@ static int be_open(struct net_device *netdev)
|
|||
if (status)
|
||||
goto err;
|
||||
|
||||
status = be_enable_if_filters(adapter);
|
||||
if (status)
|
||||
goto err;
|
||||
|
||||
status = be_irq_register(adapter);
|
||||
if (status)
|
||||
goto err;
|
||||
|
@ -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
|
||||
static void be_disable_vxlan_offloads(struct be_adapter *adapter)
|
||||
{
|
||||
|
@ -3770,8 +3841,8 @@ static int be_clear(struct be_adapter *adapter)
|
|||
#ifdef CONFIG_BE2NET_VXLAN
|
||||
be_disable_vxlan_offloads(adapter);
|
||||
#endif
|
||||
/* delete the primary mac along with the uc-mac list */
|
||||
be_mac_clear(adapter);
|
||||
kfree(adapter->pmac_id);
|
||||
adapter->pmac_id = NULL;
|
||||
|
||||
be_cmd_if_destroy(adapter, adapter->if_handle, 0);
|
||||
|
||||
|
@ -3782,25 +3853,11 @@ static int be_clear(struct be_adapter *adapter)
|
|||
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)
|
||||
{
|
||||
struct be_resources res = {0};
|
||||
u32 cap_flags, en_flags, vf;
|
||||
struct be_vf_cfg *vf_cfg;
|
||||
u32 cap_flags, vf;
|
||||
int status;
|
||||
|
||||
/* If a FW profile exists, then cap_flags are updated */
|
||||
|
@ -3821,8 +3878,12 @@ static int be_vfs_if_create(struct be_adapter *adapter)
|
|||
}
|
||||
}
|
||||
|
||||
status = be_if_create(adapter, &vf_cfg->if_handle,
|
||||
cap_flags, vf + 1);
|
||||
en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
|
||||
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)
|
||||
return status;
|
||||
}
|
||||
|
@ -4194,15 +4255,8 @@ static int be_mac_setup(struct be_adapter *adapter)
|
|||
|
||||
memcpy(adapter->netdev->dev_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;
|
||||
}
|
||||
|
||||
|
@ -4342,6 +4396,7 @@ static int be_func_init(struct be_adapter *adapter)
|
|||
static int be_setup(struct be_adapter *adapter)
|
||||
{
|
||||
struct device *dev = &adapter->pdev->dev;
|
||||
u32 en_flags;
|
||||
int status;
|
||||
|
||||
status = be_func_init(adapter);
|
||||
|
@ -4364,8 +4419,11 @@ static int be_setup(struct be_adapter *adapter)
|
|||
if (status)
|
||||
goto err;
|
||||
|
||||
status = be_if_create(adapter, &adapter->if_handle,
|
||||
be_if_cap_flags(adapter), 0);
|
||||
/* will enable all the needed filter flags in be_open() */
|
||||
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)
|
||||
goto err;
|
||||
|
||||
|
@ -4391,11 +4449,6 @@ static int be_setup(struct be_adapter *adapter)
|
|||
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,
|
||||
adapter->rx_fc);
|
||||
if (status)
|
||||
|
|
Загрузка…
Ссылка в новой задаче