From 1297f9db4fe8b5c7d77e8da71c2a21ea2d8076ba Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 24 Apr 2013 11:52:28 +0000 Subject: be2net: Remove an incorrect pvid check in Tx To work-around a HW bug that corrupts certain packets while inserting a pvid, the driver needs to invoke a special hack in firmware to avoid the VLAN tagging in the HW. Since this logic is missing from the driver, removing the check for pvid. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 2886c9b63f90..a254942ed5a6 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -626,11 +626,6 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, return vlan_tag; } -static int be_vlan_tag_chk(struct be_adapter *adapter, struct sk_buff *skb) -{ - return vlan_tx_tag_present(skb) || adapter->pvid; -} - static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, struct sk_buff *skb, u32 wrb_cnt, u32 len) { @@ -781,11 +776,10 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? VLAN_ETH_HLEN : ETH_HLEN; - /* HW has a bug which considers padding bytes as legal - * and modifies the IPv4 hdr's 'tot_len' field + /* For padded packets, BE HW modifies tot_len field in IP header + * incorrecly when VLAN tag is inserted by HW. */ - if (skb->len <= 60 && be_vlan_tag_chk(adapter, skb) && - is_ipv4_pkt(skb)) { + if (skb->len <= 60 && vlan_tx_tag_present(skb) && is_ipv4_pkt(skb)) { ip = (struct iphdr *)ip_hdr(skb); pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len)); } @@ -795,7 +789,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, * Manually insert VLAN in pkt. */ if (skb->ip_summed != CHECKSUM_PARTIAL && - be_vlan_tag_chk(adapter, skb)) { + vlan_tx_tag_present(skb)) { skb = be_insert_vlan_in_pkt(adapter, skb); if (unlikely(!skb)) goto tx_drop; -- cgit v1.2.3 From bc0c3405abbb7d7115df824c0e41422396923c1f Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 24 Apr 2013 11:52:50 +0000 Subject: 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 Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 7 ++ drivers/net/ethernet/emulex/benet/be_cmds.c | 32 ++++++++++ drivers/net/ethernet/emulex/benet/be_cmds.h | 13 ++++ drivers/net/ethernet/emulex/benet/be_main.c | 99 +++++++++++++++++++++++++++-- 4 files changed, 144 insertions(+), 7 deletions(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 29aff55f2eea..941aa1f5cf9b 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -328,6 +328,7 @@ enum vf_state { #define BE_FLAGS_WORKER_SCHEDULED (1 << 3) #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 +#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11) struct phy_info { u8 transceiver; @@ -434,6 +435,7 @@ struct be_adapter { u8 wol_cap; bool wol; u32 uc_macs; /* Count of secondary UC MAC programmed */ + u16 qnq_vid; u32 msg_enable; int be_get_temp_freq; u16 max_mcast_mac; @@ -648,6 +650,11 @@ static inline bool be_is_wol_excluded(struct be_adapter *adapter) } } +static inline int qnq_async_evt_rcvd(struct be_adapter *adapter) +{ + return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD; +} + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); extern void be_link_status_update(struct be_adapter *adapter, u8 link_status); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 3c9b4f12e3e5..ce5af9b3b704 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); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 96970860c915..07fd9277d3cb 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -84,6 +84,9 @@ struct be_mcc_compl { #define ASYNC_EVENT_QOS_SPEED 0x1 #define ASYNC_EVENT_COS_PRIORITY 0x2 #define ASYNC_EVENT_PVID_STATE 0x3 +#define ASYNC_EVENT_CODE_QNQ 0x6 +#define ASYNC_DEBUG_EVENT_TYPE_QNQ 1 + struct be_async_event_trailer { u32 code; }; @@ -144,6 +147,16 @@ struct be_async_event_grp5_pvid_state { struct be_async_event_trailer trailer; } __packed; +/* async event indicating outer VLAN tag in QnQ */ +struct be_async_event_qnq { + u8 valid; /* Indicates if outer VLAN is valid */ + u8 rsvd0; + u16 vlan_tag; + u32 event_tag; + u8 rsvd1[4]; + struct be_async_event_trailer trailer; +} __packed; + struct be_mcc_mailbox { struct be_mcc_wrb wrb; struct be_mcc_compl compl; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index a254942ed5a6..21109b59fcfc 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -627,7 +627,7 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, } static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, - struct sk_buff *skb, u32 wrb_cnt, u32 len) + struct sk_buff *skb, u32 wrb_cnt, u32 len, bool skip_hw_vlan) { u16 vlan_tag; @@ -654,8 +654,9 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag); } + /* To skip HW VLAN tagging: evt = 1, compl = 0 */ + AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, !skip_hw_vlan); AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1); - AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, 1); AMAP_SET_BITS(struct amap_eth_hdr_wrb, num_wrb, hdr, wrb_cnt); AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len); } @@ -678,7 +679,8 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, } static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, - struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb) + struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb, + bool skip_hw_vlan) { dma_addr_t busaddr; int i, copied = 0; @@ -727,7 +729,7 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, queue_head_inc(txq); } - wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied); + wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied, skip_hw_vlan); be_dws_cpu_to_le(hdr, sizeof(*hdr)); return copied; @@ -744,7 +746,8 @@ dma_err: } static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, - struct sk_buff *skb) + struct sk_buff *skb, + bool *skip_hw_vlan) { u16 vlan_tag = 0; @@ -759,9 +762,67 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, skb->vlan_tci = 0; } + if (qnq_async_evt_rcvd(adapter) && adapter->pvid) { + if (!vlan_tag) + vlan_tag = adapter->pvid; + if (skip_hw_vlan) + *skip_hw_vlan = true; + } + + if (vlan_tag) { + skb = __vlan_put_tag(skb, vlan_tag); + if (unlikely(!skb)) + return skb; + + skb->vlan_tci = 0; + } + + /* Insert the outer VLAN, if any */ + if (adapter->qnq_vid) { + vlan_tag = adapter->qnq_vid; + skb = __vlan_put_tag(skb, vlan_tag); + if (unlikely(!skb)) + return skb; + if (skip_hw_vlan) + *skip_hw_vlan = true; + } + return skb; } +static bool be_ipv6_exthdr_check(struct sk_buff *skb) +{ + struct ethhdr *eh = (struct ethhdr *)skb->data; + u16 offset = ETH_HLEN; + + if (eh->h_proto == htons(ETH_P_IPV6)) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + offset); + + offset += sizeof(struct ipv6hdr); + if (ip6h->nexthdr != NEXTHDR_TCP && + ip6h->nexthdr != NEXTHDR_UDP) { + struct ipv6_opt_hdr *ehdr = + (struct ipv6_opt_hdr *) (skb->data + offset); + + /* offending pkt: 2nd byte following IPv6 hdr is 0xff */ + if (ehdr->hdrlen == 0xff) + return true; + } + } + return false; +} + +static int be_vlan_tag_tx_chk(struct be_adapter *adapter, struct sk_buff *skb) +{ + return vlan_tx_tag_present(skb) || adapter->pvid || adapter->qnq_vid; +} + +static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb) +{ + return BE3_chip(adapter) && + be_ipv6_exthdr_check(skb); +} + static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) { @@ -772,6 +833,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, u32 wrb_cnt = 0, copied = 0; u32 start = txq->head, eth_hdr_len; bool dummy_wrb, stopped = false; + bool skip_hw_vlan = false; eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? VLAN_ETH_HLEN : ETH_HLEN; @@ -790,14 +852,37 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, */ if (skb->ip_summed != CHECKSUM_PARTIAL && vlan_tx_tag_present(skb)) { - skb = be_insert_vlan_in_pkt(adapter, skb); + skb = be_insert_vlan_in_pkt(adapter, skb, &skip_hw_vlan); + if (unlikely(!skb)) + goto tx_drop; + } + + /* HW may lockup when VLAN HW tagging is requested on + * certain ipv6 packets. Drop such pkts if the HW workaround to + * skip HW tagging is not enabled by FW. + */ + if (unlikely(be_ipv6_tx_stall_chk(adapter, skb) && + (adapter->pvid || adapter->qnq_vid) && + !qnq_async_evt_rcvd(adapter))) + goto tx_drop; + + /* Manual VLAN tag insertion to prevent: + * ASIC lockup when the ASIC inserts VLAN tag into + * certain ipv6 packets. Insert VLAN tags in driver, + * and set event, completion, vlan bits accordingly + * in the Tx WRB. + */ + if (be_ipv6_tx_stall_chk(adapter, skb) && + be_vlan_tag_tx_chk(adapter, skb)) { + skb = be_insert_vlan_in_pkt(adapter, skb, &skip_hw_vlan); if (unlikely(!skb)) goto tx_drop; } wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); - copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); + copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb, + skip_hw_vlan); if (copied) { int gso_segs = skb_shinfo(skb)->gso_segs; -- cgit v1.2.3 From d2cb6ce7306997c753976b65bf81495e1efe7074 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 24 Apr 2013 11:53:08 +0000 Subject: be2net: Fix PVID tag offload for packets with inline VLAN tag. BE3 HW in UMC mode could wrongly double tag a packet with PVID when the packet already has a inlined VLAN tag. In UMC mode, When HW finds that a packet is already VLAN tagged PVID should not be inserted into the packet. To fix this use the FW hack to instruct the HW to skip PVID tagging. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 21109b59fcfc..1232e9164bf1 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -834,6 +834,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, u32 start = txq->head, eth_hdr_len; bool dummy_wrb, stopped = false; bool skip_hw_vlan = false; + struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? VLAN_ETH_HLEN : ETH_HLEN; @@ -846,6 +847,13 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len)); } + /* If vlan tag is already inlined in the packet, skip HW VLAN + * tagging in UMC mode + */ + if ((adapter->function_mode & UMC_ENABLED) && + veh->h_vlan_proto == htons(ETH_P_8021Q)) + skip_hw_vlan = true; + /* HW has a bug wherein it will calculate CSUM for VLAN * pkts even though it is disabled. * Manually insert VLAN in pkt. -- cgit v1.2.3 From 89cc80a44b7c320e08599cb86f6aef0ead8986a1 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 22 Apr 2013 22:40:07 +0100 Subject: sfc: Fix naming of MTD partitions for FPGA bitfiles efx_mcdi_get_board_cfg() uses a buffer for the firmware response that is only large enough to hold subtypes for the originally defined set of NVRAM partitions. Longer responses are truncated, and we may read off the end of the buffer when copying out subtypes for additional partitions. In particular, this can result in the MTD partition for an FPGA bitfile being named e.g. 'eth5 sfc_fpga:00' when it should be 'eth5 sfc_fpga:01'. This means the firmware update tool (sfupdate) can't tell which bitfile should be written to the partition. Correct the response buffer size. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mcdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 0095ce95150b..97dd8f18c001 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -667,7 +667,7 @@ fail: int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, u16 *fw_subtype_list, u32 *capabilities) { - uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LENMIN]; + uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LENMAX]; size_t outlen, offset, i; int port_num = efx_port_num(efx); int rc; -- cgit v1.2.3 From cd4baaaa04b4aaa3b0ec4d13a6f3d203b92eadbd Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Mon, 22 Apr 2013 19:42:16 +0000 Subject: gianfar: do not advertise any alarm capability. An early draft of the PHC patch series included an alarm in the gianfar driver. During the review process, the alarm code was dropped, but the capability removal was overlooked. This patch fixes the issue by advertising zero alarms. This patch should be applied to every 3.x stable kernel. Signed-off-by: Richard Cochran Reported-by: Chris LaRocque Cc: Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar_ptp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index 2e5daee0438a..a3f8a2551f2d 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -127,7 +127,6 @@ struct gianfar_ptp_registers { #define DRIVER "gianfar_ptp" #define DEFAULT_CKSEL 1 -#define N_ALARM 1 /* first alarm is used internally to reset fipers */ #define N_EXT_TS 2 #define REG_SIZE sizeof(struct gianfar_ptp_registers) @@ -410,7 +409,7 @@ static struct ptp_clock_info ptp_gianfar_caps = { .owner = THIS_MODULE, .name = "gianfar clock", .max_adj = 512000, - .n_alarm = N_ALARM, + .n_alarm = 0, .n_ext_ts = N_EXT_TS, .n_per_out = 0, .pps = 1, -- cgit v1.2.3 From ecf01c22be034690b621d92c9ff488d607a9995a Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Mon, 22 Apr 2013 02:53:03 +0000 Subject: bnx2x: Prevent NULL pointer dereference in kdump In scenarios in which a previous driver was removed without proper cleanup (e.g., kdump), it is possible for the chip to generate an interrupt without any apparent reason once interrupts are requested. Due to an erroneous initialization of resources, some of the bnx2x structs which are required for interrupt handling are initialized only after an interface's interrupt is requested from the OS. As a result, once such a spurious interrupt occurs, it will cause a NULL pointer dereference - the driver will access those structs in its interrupt handling routine. This patch change the interrupt request scheme so that bnx2x would only request interrupts from the kernel after it has finished initializing all the inner structs required for interrupt handling. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 11 +++++--- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 19 +++++++++++--- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 32 ++++++++++++------------ 3 files changed, 39 insertions(+), 23 deletions(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 57619dd4a92b..51a6030138e3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1037,6 +1037,7 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) DP(NETIF_MSG_INTR, "got an MSI-X interrupt on IDX:SB [fp %d fw_sd %d igusb %d]\n", fp->index, fp->fw_sb_id, fp->igu_sb_id); + bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0); #ifdef BNX2X_STOP_ON_ERROR @@ -1718,7 +1719,7 @@ static int bnx2x_req_irq(struct bnx2x *bp) return request_irq(irq, bnx2x_interrupt, flags, bp->dev->name, bp->dev); } -static int bnx2x_setup_irqs(struct bnx2x *bp) +int bnx2x_setup_irqs(struct bnx2x *bp) { int rc = 0; if (bp->flags & USING_MSIX_FLAG && @@ -2574,6 +2575,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) } } + bnx2x_pre_irq_nic_init(bp); + /* Connect to IRQs */ rc = bnx2x_setup_irqs(bp); if (rc) { @@ -2583,11 +2586,11 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) LOAD_ERROR_EXIT(bp, load_error2); } - /* Setup NIC internals and enable interrupts */ - bnx2x_nic_init(bp, load_code); - /* Init per-function objects */ if (IS_PF(bp)) { + /* Setup NIC internals and enable interrupts */ + bnx2x_post_irq_nic_init(bp, load_code); + bnx2x_init_bp_objs(bp); bnx2x_iov_nic_init(bp); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index aee7671ff4c1..c3a65d04c8c9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -295,16 +295,29 @@ void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw); void bnx2x_nic_init_cnic(struct bnx2x *bp); /** - * bnx2x_nic_init - init driver internals. + * bnx2x_preirq_nic_init - init driver internals. * * @bp: driver handle * * Initializes: - * - rings + * - fastpath object + * - fastpath rings + * etc. + */ +void bnx2x_pre_irq_nic_init(struct bnx2x *bp); + +/** + * bnx2x_postirq_nic_init - init driver internals. + * + * @bp: driver handle + * @load_code: COMMON, PORT or FUNCTION + * + * Initializes: * - status blocks + * - slowpath rings * - etc. */ -void bnx2x_nic_init(struct bnx2x *bp, u32 load_code); +void bnx2x_post_irq_nic_init(struct bnx2x *bp, u32 load_code); /** * bnx2x_alloc_mem_cnic - allocate driver's memory for cnic. * diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index c50696b396f1..a8f1ee31de77 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -6018,10 +6018,11 @@ void bnx2x_nic_init_cnic(struct bnx2x *bp) mmiowb(); } -void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) +void bnx2x_pre_irq_nic_init(struct bnx2x *bp) { int i; + /* Setup NIC internals and enable interrupts */ for_each_eth_queue(bp, i) bnx2x_init_eth_fp(bp, i); @@ -6030,17 +6031,21 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) bnx2x_init_rx_rings(bp); bnx2x_init_tx_rings(bp); - if (IS_VF(bp)) - return; + if (IS_PF(bp)) { + /* Initialize MOD_ABS interrupts */ + bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id, + bp->common.shmem_base, + bp->common.shmem2_base, BP_PORT(bp)); - /* Initialize MOD_ABS interrupts */ - bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id, - bp->common.shmem_base, bp->common.shmem2_base, - BP_PORT(bp)); + /* initialize the default status block and sp ring */ + bnx2x_init_def_sb(bp); + bnx2x_update_dsb_idx(bp); + bnx2x_init_sp_ring(bp); + } +} - bnx2x_init_def_sb(bp); - bnx2x_update_dsb_idx(bp); - bnx2x_init_sp_ring(bp); +void bnx2x_post_irq_nic_init(struct bnx2x *bp, u32 load_code) +{ bnx2x_init_eq_ring(bp); bnx2x_init_internal(bp, load_code); bnx2x_pf_init(bp); @@ -6058,12 +6063,7 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) AEU_INPUTS_ATTN_BITS_SPIO5); } -/* end of nic init */ - -/* - * gzip service functions - */ - +/* gzip service functions */ static int bnx2x_gunzip_init(struct bnx2x *bp) { bp->gunzip_buf = dma_alloc_coherent(&bp->pdev->dev, FW_BUF_SIZE, -- cgit v1.2.3 From d98ef50fd99585e43b77b5ac5943e4450031a18e Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Thu, 25 Apr 2013 00:56:55 +0000 Subject: be2net: Fixed memory leak Signed-off-by: Suresh Reddy Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 38 +++++++++++++++++------------ 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index ce5af9b3b704..24c80d1d70ba 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2493,6 +2493,9 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) struct mgmt_controller_attrib *attribs; struct be_dma_mem attribs_cmd; + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + memset(&attribs_cmd, 0, sizeof(struct be_dma_mem)); attribs_cmd.size = sizeof(struct be_cmd_resp_cntl_attribs); attribs_cmd.va = pci_alloc_consistent(adapter->pdev, attribs_cmd.size, @@ -2500,12 +2503,10 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) if (!attribs_cmd.va) { dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); - return -ENOMEM; + status = -ENOMEM; + goto err; } - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; - wrb = wrb_from_mbox(adapter); if (!wrb) { status = -EBUSY; @@ -2525,8 +2526,9 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) err: mutex_unlock(&adapter->mbox_lock); - pci_free_consistent(adapter->pdev, attribs_cmd.size, attribs_cmd.va, - attribs_cmd.dma); + if (attribs_cmd.va) + pci_free_consistent(adapter->pdev, attribs_cmd.size, + attribs_cmd.va, attribs_cmd.dma); return status; } @@ -2826,6 +2828,9 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) CMD_SUBSYSTEM_ETH)) return -EPERM; + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + memset(&cmd, 0, sizeof(struct be_dma_mem)); cmd.size = sizeof(struct be_cmd_resp_acpi_wol_magic_config_v1); cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, @@ -2833,12 +2838,10 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) if (!cmd.va) { dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); - return -ENOMEM; + status = -ENOMEM; + goto err; } - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; - wrb = wrb_from_mbox(adapter); if (!wrb) { status = -EBUSY; @@ -2869,7 +2872,8 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) } err: mutex_unlock(&adapter->mbox_lock); - pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); + if (cmd.va) + pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); return status; } @@ -3001,16 +3005,18 @@ int be_cmd_get_func_config(struct be_adapter *adapter) int status; struct be_dma_mem cmd; + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + memset(&cmd, 0, sizeof(struct be_dma_mem)); cmd.size = sizeof(struct be_cmd_resp_get_func_config); cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma); if (!cmd.va) { dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); - return -ENOMEM; + status = -ENOMEM; + goto err; } - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; wrb = wrb_from_mbox(adapter); if (!wrb) { @@ -3050,8 +3056,8 @@ int be_cmd_get_func_config(struct be_adapter *adapter) } err: mutex_unlock(&adapter->mbox_lock); - pci_free_consistent(adapter->pdev, cmd.size, - cmd.va, cmd.dma); + if (cmd.va) + pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); return status; } -- cgit v1.2.3 From b424332d0a812799b83ab6e1d3c8c32a3c5ecfb5 Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Thu, 25 Apr 2013 00:56:56 +0000 Subject: be2net: Fix to show wol disabled/enabled state correctly. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_ethtool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 76b302f30c87..1b7233c11af3 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -680,7 +680,8 @@ be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) if (be_is_wol_supported(adapter)) { wol->supported |= WAKE_MAGIC; - wol->wolopts |= WAKE_MAGIC; + if (adapter->wol) + wol->wolopts |= WAKE_MAGIC; } else wol->wolopts = 0; memset(&wol->sopass, 0, sizeof(wol->sopass)); -- cgit v1.2.3 From e5195c1f31f399289347e043d6abf3ffa80f0005 Mon Sep 17 00:00:00 2001 From: Stefan Bader Date: Fri, 26 Apr 2013 13:49:32 +0000 Subject: r8169: fix 8168evl frame padding. Signed-off-by: Stefan Bader Acked-by: Francois Romieu Cc: hayeswang Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 4ecbe64a758d..15ba8c47d79f 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5787,6 +5787,14 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, goto err_stop_0; } + /* 8168evl does not automatically pad to minimum length. */ + if (unlikely(tp->mac_version == RTL_GIGA_MAC_VER_34 && + skb->len < ETH_ZLEN)) { + if (skb_padto(skb, ETH_ZLEN)) + goto err_update_stats; + skb_put(skb, ETH_ZLEN - skb->len); + } + if (unlikely(le32_to_cpu(txd->opts1) & DescOwn)) goto err_stop_0; @@ -5858,6 +5866,7 @@ err_dma_1: rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd); err_dma_0: dev_kfree_skb(skb); +err_update_stats: dev->stats.tx_dropped++; return NETDEV_TX_OK; -- cgit v1.2.3