diff options
author | Ajit Khaparde <ajit.khaparde@emulex.com> | 2013-04-24 11:52:50 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-24 19:37:21 -0400 |
commit | bc0c3405abbb7d7115df824c0e41422396923c1f (patch) | |
tree | bd0a657ebd43dcb8e342a8831f9151be300f37c1 /drivers/net/ethernet/emulex/benet/be_cmds.c | |
parent | 1297f9db4fe8b5c7d77e8da71c2a21ea2d8076ba (diff) |
be2net: fix a Tx stall bug caused by a specific ipv6 packet
The ASIC could lockup in the transmit path when it tries
to insert VLAN in a specific ipv6 packet.
1) Identify the packet which can cause this.
2) Check if the firmware provides a workaround to prevent this.
3) If workaround is not present, drop the packet.
4) If the firmware provides a workaround, insert the VLAN tag in the
packet and inform the firmware to skip further VLAN insertions.
Signed-off-by: Ajit Khaparde <ajit.khaparde@emulex.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c')
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 3c9b4f12e3e..ce5af9b3b70 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -263,6 +263,27 @@ static void be_async_grp5_evt_process(struct be_adapter *adapter, } } +static void be_async_dbg_evt_process(struct be_adapter *adapter, + u32 trailer, struct be_mcc_compl *cmp) +{ + u8 event_type = 0; + struct be_async_event_qnq *evt = (struct be_async_event_qnq *) cmp; + + event_type = (trailer >> ASYNC_TRAILER_EVENT_TYPE_SHIFT) & + ASYNC_TRAILER_EVENT_TYPE_MASK; + + switch (event_type) { + case ASYNC_DEBUG_EVENT_TYPE_QNQ: + if (evt->valid) + adapter->qnq_vid = le16_to_cpu(evt->vlan_tag); + adapter->flags |= BE_FLAGS_QNQ_ASYNC_EVT_RCVD; + break; + default: + dev_warn(&adapter->pdev->dev, "Unknown debug event\n"); + break; + } +} + static inline bool is_link_state_evt(u32 trailer) { return ((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & @@ -277,6 +298,13 @@ static inline bool is_grp5_evt(u32 trailer) ASYNC_EVENT_CODE_GRP_5); } +static inline bool is_dbg_evt(u32 trailer) +{ + return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & + ASYNC_TRAILER_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_QNQ); +} + static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) { struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq; @@ -325,6 +353,9 @@ int be_process_mcc(struct be_adapter *adapter) else if (is_grp5_evt(compl->flags)) be_async_grp5_evt_process(adapter, compl->flags, compl); + else if (is_dbg_evt(compl->flags)) + be_async_dbg_evt_process(adapter, + compl->flags, compl); } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { status = be_mcc_compl_process(adapter, compl); atomic_dec(&mcc_obj->q.used); @@ -1022,6 +1053,7 @@ int be_cmd_mccq_ext_create(struct be_adapter *adapter, /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */ req->async_event_bitmap[0] = cpu_to_le32(0x00000022); + req->async_event_bitmap[0] |= cpu_to_le32(1 << ASYNC_EVENT_CODE_QNQ); be_dws_cpu_to_le(ctxt, sizeof(req->context)); be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); |