diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 6 | ||||
-rw-r--r-- | drivers/net/caif/caif_spi.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 19 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 32 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be.h | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.c | 70 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.h | 13 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_ethtool.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 121 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/gianfar_ptp.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/r8169.c | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.c | 2 | ||||
-rw-r--r-- | drivers/net/tun.c | 15 |
14 files changed, 248 insertions, 64 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 532153db1f9c..d0aade04e49a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1917,14 +1917,16 @@ err_detach: bond_detach_slave(bond, new_slave); if (bond->primary_slave == new_slave) bond->primary_slave = NULL; - write_unlock_bh(&bond->lock); if (bond->curr_active_slave == new_slave) { + bond_change_active_slave(bond, NULL); + write_unlock_bh(&bond->lock); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); - bond_change_active_slave(bond, NULL); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); + } else { + write_unlock_bh(&bond->lock); } slave_disable_netpoll(new_slave); diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index 2fb279a63c50..155db68e13ba 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -863,6 +863,7 @@ static int __init cfspi_init_module(void) driver_remove_file(&cfspi_spi_driver.driver, &driver_attr_up_head_align); err_create_up_head_align: + platform_driver_unregister(&cfspi_spi_driver); err_dev_register: return result; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 466b512cda4f..b8fbe266ab68 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1044,6 +1044,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 @@ -1725,7 +1726,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 && @@ -2581,6 +2582,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) { @@ -2590,11 +2593,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 54e1b149acb3..151675d66b0d 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 91a0434ce1bd..a024eec94be1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -6030,10 +6030,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); @@ -6041,19 +6042,27 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) rmb(); bnx2x_init_rx_rings(bp); bnx2x_init_tx_rings(bp); + if (IS_VF(bp)) { bnx2x_memset_stats(bp); return; } - /* 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)); + 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 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); @@ -6071,12 +6080,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, diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 9045903dcda3..234ce6f07544 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -329,6 +329,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; @@ -436,6 +437,7 @@ struct be_adapter { bool wol; u32 uc_macs; /* Count of secondary UC MAC programmed */ u16 asic_rev; + u16 qnq_vid; u32 msg_enable; int be_get_temp_freq; u16 max_mcast_mac; @@ -651,6 +653,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 9080c2775e9f..25d3290b8cac 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); @@ -1020,6 +1051,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); @@ -2457,6 +2489,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, @@ -2464,12 +2499,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; @@ -2489,8 +2522,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; } @@ -2788,6 +2822,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, @@ -2795,12 +2832,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; @@ -2831,7 +2866,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; } @@ -2964,16 +3000,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) { @@ -3016,8 +3054,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; } diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 1b01e9b32794..a855668e0cc5 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_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index ec3050b3133e..5733cde88e2c 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)); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 1c734915933f..4babc8a4a543 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -639,13 +639,8 @@ 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) + struct sk_buff *skb, u32 wrb_cnt, u32 len, bool skip_hw_vlan) { u16 vlan_tag; @@ -672,8 +667,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); } @@ -696,7 +692,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; @@ -745,7 +742,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; @@ -762,7 +759,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; @@ -777,9 +775,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, htons(ETH_P_8021Q), 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, htons(ETH_P_8021Q), 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) { @@ -790,33 +846,64 @@ 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; + struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; 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)); } + /* 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. */ if (skb->ip_summed != CHECKSUM_PARTIAL && - be_vlan_tag_chk(adapter, skb)) { - skb = be_insert_vlan_in_pkt(adapter, skb); + vlan_tx_tag_present(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; diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index fe8e9e5cfb2b..576e4b858fce 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -130,7 +130,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) @@ -413,7 +412,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, diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index c6dac38fd9cc..79c520b64fdd 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5896,6 +5896,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; @@ -5967,6 +5975,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; 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; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 66109a2ad886..f042b0373e5d 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1471,14 +1471,17 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, if (!tun) return -EBADFD; - if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) - return -EINVAL; + if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) { + ret = -EINVAL; + goto out; + } ret = tun_do_read(tun, tfile, iocb, m->msg_iov, total_len, flags & MSG_DONTWAIT); if (ret > total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; } +out: tun_put(tun); return ret; } @@ -1593,8 +1596,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) return err; if (tun->flags & TUN_TAP_MQ && - (tun->numqueues + tun->numdisabled > 1)) - return -EBUSY; + (tun->numqueues + tun->numdisabled > 1)) { + /* One or more queue has already been attached, no need + * to initialize the device again. + */ + return 0; + } } else { char *name; |