9aa196e0f2
Refresh patches, following required reworking: ar71xx/patches-4.9/930-chipidea-pullup.patch layerscape/patches-4.9/302-dts-support-layercape.patch sunxi/patches-4.9/0052-stmmac-form-4-12.patch Fixes for CVEs: CVE-2018-1108 CVE-2018-1092 Tested on: ar71xx Archer C7 v2 Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> Tested-by: Koen Vandeputte <koen.vandeputte@ncentric.com> Tested-by: Arjen de Korte <build+openwrt@de-korte.org>
512 lines
16 KiB
Diff
512 lines
16 KiB
Diff
From 67a2eceebe9dcd92a1a5f3e912340c8975c84434 Mon Sep 17 00:00:00 2001
|
|
From: Yangbo Lu <yangbo.lu@nxp.com>
|
|
Date: Wed, 17 Jan 2018 14:50:41 +0800
|
|
Subject: [PATCH 02/30] core-linux: support layerscape
|
|
|
|
This is an integrated patch for layerscape core-linux support.
|
|
|
|
Signed-off-by: Madalin Bucur <madalin.bucur@freescale.com>
|
|
Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
|
|
Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
|
|
Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
|
|
Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
|
|
Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com>
|
|
Signed-off-by: Jarod Wilson <jarod@redhat.com>
|
|
Signed-off-by: Nikhil Badola <nikhil.badola@freescale.com>
|
|
Signed-off-by: stephen hemminger <stephen@networkplumber.org>
|
|
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
|
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
|
|
---
|
|
drivers/base/devres.c | 66 ++++++++++++++++++++++++++++
|
|
drivers/base/soc.c | 70 +++++++++++++++++++++++++++++
|
|
include/linux/device.h | 19 ++++++++
|
|
include/linux/fsl/svr.h | 97 +++++++++++++++++++++++++++++++++++++++++
|
|
include/linux/fsl_devices.h | 3 ++
|
|
include/linux/netdev_features.h | 2 +
|
|
include/linux/netdevice.h | 4 ++
|
|
include/linux/skbuff.h | 2 +
|
|
include/linux/sys_soc.h | 3 ++
|
|
include/uapi/linux/if_ether.h | 1 +
|
|
net/core/dev.c | 13 +++++-
|
|
net/core/skbuff.c | 29 +++++++++++-
|
|
net/sched/sch_generic.c | 7 +++
|
|
13 files changed, 313 insertions(+), 3 deletions(-)
|
|
create mode 100644 include/linux/fsl/svr.h
|
|
|
|
--- a/drivers/base/devres.c
|
|
+++ b/drivers/base/devres.c
|
|
@@ -10,6 +10,7 @@
|
|
#include <linux/device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
+#include <linux/percpu.h>
|
|
|
|
#include "base.h"
|
|
|
|
@@ -985,3 +986,68 @@ void devm_free_pages(struct device *dev,
|
|
&devres));
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_free_pages);
|
|
+
|
|
+static void devm_percpu_release(struct device *dev, void *pdata)
|
|
+{
|
|
+ void __percpu *p;
|
|
+
|
|
+ p = *(void __percpu **)pdata;
|
|
+ free_percpu(p);
|
|
+}
|
|
+
|
|
+static int devm_percpu_match(struct device *dev, void *data, void *p)
|
|
+{
|
|
+ struct devres *devr = container_of(data, struct devres, data);
|
|
+
|
|
+ return *(void **)devr->data == p;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * __devm_alloc_percpu - Resource-managed alloc_percpu
|
|
+ * @dev: Device to allocate per-cpu memory for
|
|
+ * @size: Size of per-cpu memory to allocate
|
|
+ * @align: Alignment of per-cpu memory to allocate
|
|
+ *
|
|
+ * Managed alloc_percpu. Per-cpu memory allocated with this function is
|
|
+ * automatically freed on driver detach.
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * Pointer to allocated memory on success, NULL on failure.
|
|
+ */
|
|
+void __percpu *__devm_alloc_percpu(struct device *dev, size_t size,
|
|
+ size_t align)
|
|
+{
|
|
+ void *p;
|
|
+ void __percpu *pcpu;
|
|
+
|
|
+ pcpu = __alloc_percpu(size, align);
|
|
+ if (!pcpu)
|
|
+ return NULL;
|
|
+
|
|
+ p = devres_alloc(devm_percpu_release, sizeof(void *), GFP_KERNEL);
|
|
+ if (!p) {
|
|
+ free_percpu(pcpu);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ *(void __percpu **)p = pcpu;
|
|
+
|
|
+ devres_add(dev, p);
|
|
+
|
|
+ return pcpu;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(__devm_alloc_percpu);
|
|
+
|
|
+/**
|
|
+ * devm_free_percpu - Resource-managed free_percpu
|
|
+ * @dev: Device this memory belongs to
|
|
+ * @pdata: Per-cpu memory to free
|
|
+ *
|
|
+ * Free memory allocated with devm_alloc_percpu().
|
|
+ */
|
|
+void devm_free_percpu(struct device *dev, void __percpu *pdata)
|
|
+{
|
|
+ WARN_ON(devres_destroy(dev, devm_percpu_release, devm_percpu_match,
|
|
+ (void *)pdata));
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(devm_free_percpu);
|
|
--- a/drivers/base/soc.c
|
|
+++ b/drivers/base/soc.c
|
|
@@ -13,6 +13,7 @@
|
|
#include <linux/spinlock.h>
|
|
#include <linux/sys_soc.h>
|
|
#include <linux/err.h>
|
|
+#include <linux/glob.h>
|
|
|
|
static DEFINE_IDA(soc_ida);
|
|
|
|
@@ -159,3 +160,72 @@ static int __init soc_bus_register(void)
|
|
return bus_register(&soc_bus_type);
|
|
}
|
|
core_initcall(soc_bus_register);
|
|
+
|
|
+static int soc_device_match_one(struct device *dev, void *arg)
|
|
+{
|
|
+ struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
|
+ const struct soc_device_attribute *match = arg;
|
|
+
|
|
+ if (match->machine &&
|
|
+ (!soc_dev->attr->machine ||
|
|
+ !glob_match(match->machine, soc_dev->attr->machine)))
|
|
+ return 0;
|
|
+
|
|
+ if (match->family &&
|
|
+ (!soc_dev->attr->family ||
|
|
+ !glob_match(match->family, soc_dev->attr->family)))
|
|
+ return 0;
|
|
+
|
|
+ if (match->revision &&
|
|
+ (!soc_dev->attr->revision ||
|
|
+ !glob_match(match->revision, soc_dev->attr->revision)))
|
|
+ return 0;
|
|
+
|
|
+ if (match->soc_id &&
|
|
+ (!soc_dev->attr->soc_id ||
|
|
+ !glob_match(match->soc_id, soc_dev->attr->soc_id)))
|
|
+ return 0;
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * soc_device_match - identify the SoC in the machine
|
|
+ * @matches: zero-terminated array of possible matches
|
|
+ *
|
|
+ * returns the first matching entry of the argument array, or NULL
|
|
+ * if none of them match.
|
|
+ *
|
|
+ * This function is meant as a helper in place of of_match_node()
|
|
+ * in cases where either no device tree is available or the information
|
|
+ * in a device node is insufficient to identify a particular variant
|
|
+ * by its compatible strings or other properties. For new devices,
|
|
+ * the DT binding should always provide unique compatible strings
|
|
+ * that allow the use of of_match_node() instead.
|
|
+ *
|
|
+ * The calling function can use the .data entry of the
|
|
+ * soc_device_attribute to pass a structure or function pointer for
|
|
+ * each entry.
|
|
+ */
|
|
+const struct soc_device_attribute *soc_device_match(
|
|
+ const struct soc_device_attribute *matches)
|
|
+{
|
|
+ int ret = 0;
|
|
+
|
|
+ if (!matches)
|
|
+ return NULL;
|
|
+
|
|
+ while (!ret) {
|
|
+ if (!(matches->machine || matches->family ||
|
|
+ matches->revision || matches->soc_id))
|
|
+ break;
|
|
+ ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
|
|
+ soc_device_match_one);
|
|
+ if (!ret)
|
|
+ matches++;
|
|
+ else
|
|
+ return matches;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(soc_device_match);
|
|
--- a/include/linux/device.h
|
|
+++ b/include/linux/device.h
|
|
@@ -688,6 +688,25 @@ void __iomem *devm_ioremap_resource(stru
|
|
int devm_add_action(struct device *dev, void (*action)(void *), void *data);
|
|
void devm_remove_action(struct device *dev, void (*action)(void *), void *data);
|
|
|
|
+/**
|
|
+ * devm_alloc_percpu - Resource-managed alloc_percpu
|
|
+ * @dev: Device to allocate per-cpu memory for
|
|
+ * @type: Type to allocate per-cpu memory for
|
|
+ *
|
|
+ * Managed alloc_percpu. Per-cpu memory allocated with this function is
|
|
+ * automatically freed on driver detach.
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * Pointer to allocated memory on success, NULL on failure.
|
|
+ */
|
|
+#define devm_alloc_percpu(dev, type) \
|
|
+ ((typeof(type) __percpu *)__devm_alloc_percpu((dev), sizeof(type), \
|
|
+ __alignof__(type)))
|
|
+
|
|
+void __percpu *__devm_alloc_percpu(struct device *dev, size_t size,
|
|
+ size_t align);
|
|
+void devm_free_percpu(struct device *dev, void __percpu *pdata);
|
|
+
|
|
static inline int devm_add_action_or_reset(struct device *dev,
|
|
void (*action)(void *), void *data)
|
|
{
|
|
--- /dev/null
|
|
+++ b/include/linux/fsl/svr.h
|
|
@@ -0,0 +1,97 @@
|
|
+/*
|
|
+ * MPC85xx cpu type detection
|
|
+ *
|
|
+ * Copyright 2011-2012 Freescale Semiconductor, Inc.
|
|
+ *
|
|
+ * This is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#ifndef FSL_SVR_H
|
|
+#define FSL_SVR_H
|
|
+
|
|
+#define SVR_REV(svr) ((svr) & 0xFF) /* SOC design resision */
|
|
+#define SVR_MAJ(svr) (((svr) >> 4) & 0xF) /* Major revision field*/
|
|
+#define SVR_MIN(svr) (((svr) >> 0) & 0xF) /* Minor revision field*/
|
|
+
|
|
+/* Some parts define SVR[0:23] as the SOC version */
|
|
+#define SVR_SOC_VER(svr) (((svr) >> 8) & 0xFFF7FF) /* SOC Version fields */
|
|
+
|
|
+#define SVR_8533 0x803400
|
|
+#define SVR_8535 0x803701
|
|
+#define SVR_8536 0x803700
|
|
+#define SVR_8540 0x803000
|
|
+#define SVR_8541 0x807200
|
|
+#define SVR_8543 0x803200
|
|
+#define SVR_8544 0x803401
|
|
+#define SVR_8545 0x803102
|
|
+#define SVR_8547 0x803101
|
|
+#define SVR_8548 0x803100
|
|
+#define SVR_8555 0x807100
|
|
+#define SVR_8560 0x807000
|
|
+#define SVR_8567 0x807501
|
|
+#define SVR_8568 0x807500
|
|
+#define SVR_8569 0x808000
|
|
+#define SVR_8572 0x80E000
|
|
+#define SVR_P1010 0x80F100
|
|
+#define SVR_P1011 0x80E500
|
|
+#define SVR_P1012 0x80E501
|
|
+#define SVR_P1013 0x80E700
|
|
+#define SVR_P1014 0x80F101
|
|
+#define SVR_P1017 0x80F700
|
|
+#define SVR_P1020 0x80E400
|
|
+#define SVR_P1021 0x80E401
|
|
+#define SVR_P1022 0x80E600
|
|
+#define SVR_P1023 0x80F600
|
|
+#define SVR_P1024 0x80E402
|
|
+#define SVR_P1025 0x80E403
|
|
+#define SVR_P2010 0x80E300
|
|
+#define SVR_P2020 0x80E200
|
|
+#define SVR_P2040 0x821000
|
|
+#define SVR_P2041 0x821001
|
|
+#define SVR_P3041 0x821103
|
|
+#define SVR_P4040 0x820100
|
|
+#define SVR_P4080 0x820000
|
|
+#define SVR_P5010 0x822100
|
|
+#define SVR_P5020 0x822000
|
|
+#define SVR_P5021 0X820500
|
|
+#define SVR_P5040 0x820400
|
|
+#define SVR_T4240 0x824000
|
|
+#define SVR_T4120 0x824001
|
|
+#define SVR_T4160 0x824100
|
|
+#define SVR_T4080 0x824102
|
|
+#define SVR_C291 0x850000
|
|
+#define SVR_C292 0x850020
|
|
+#define SVR_C293 0x850030
|
|
+#define SVR_B4860 0X868000
|
|
+#define SVR_G4860 0x868001
|
|
+#define SVR_G4060 0x868003
|
|
+#define SVR_B4440 0x868100
|
|
+#define SVR_G4440 0x868101
|
|
+#define SVR_B4420 0x868102
|
|
+#define SVR_B4220 0x868103
|
|
+#define SVR_T1040 0x852000
|
|
+#define SVR_T1041 0x852001
|
|
+#define SVR_T1042 0x852002
|
|
+#define SVR_T1020 0x852100
|
|
+#define SVR_T1021 0x852101
|
|
+#define SVR_T1022 0x852102
|
|
+#define SVR_T1023 0x854100
|
|
+#define SVR_T1024 0x854000
|
|
+#define SVR_T2080 0x853000
|
|
+#define SVR_T2081 0x853100
|
|
+
|
|
+#define SVR_8610 0x80A000
|
|
+#define SVR_8641 0x809000
|
|
+#define SVR_8641D 0x809001
|
|
+
|
|
+#define SVR_9130 0x860001
|
|
+#define SVR_9131 0x860000
|
|
+#define SVR_9132 0x861000
|
|
+#define SVR_9232 0x861400
|
|
+
|
|
+#define SVR_Unknown 0xFFFFFF
|
|
+
|
|
+#endif
|
|
--- a/include/linux/fsl_devices.h
|
|
+++ b/include/linux/fsl_devices.h
|
|
@@ -99,7 +99,10 @@ struct fsl_usb2_platform_data {
|
|
unsigned suspended:1;
|
|
unsigned already_suspended:1;
|
|
unsigned has_fsl_erratum_a007792:1;
|
|
+ unsigned has_fsl_erratum_14:1;
|
|
unsigned has_fsl_erratum_a005275:1;
|
|
+ unsigned has_fsl_erratum_a006918:1;
|
|
+ unsigned has_fsl_erratum_a005697:1;
|
|
unsigned check_phy_clk_valid:1;
|
|
|
|
/* register save area for suspend/resume */
|
|
--- a/include/linux/netdev_features.h
|
|
+++ b/include/linux/netdev_features.h
|
|
@@ -74,6 +74,7 @@ enum {
|
|
NETIF_F_BUSY_POLL_BIT, /* Busy poll */
|
|
|
|
NETIF_F_HW_TC_BIT, /* Offload TC infrastructure */
|
|
+ NETIF_F_HW_ACCEL_MQ_BIT, /* Hardware-accelerated multiqueue */
|
|
|
|
/*
|
|
* Add your fresh new feature above and remember to update
|
|
@@ -136,6 +137,7 @@ enum {
|
|
#define NETIF_F_HW_L2FW_DOFFLOAD __NETIF_F(HW_L2FW_DOFFLOAD)
|
|
#define NETIF_F_BUSY_POLL __NETIF_F(BUSY_POLL)
|
|
#define NETIF_F_HW_TC __NETIF_F(HW_TC)
|
|
+#define NETIF_F_HW_ACCEL_MQ __NETIF_F(HW_ACCEL_MQ)
|
|
|
|
#define for_each_netdev_feature(mask_addr, bit) \
|
|
for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT)
|
|
--- a/include/linux/netdevice.h
|
|
+++ b/include/linux/netdevice.h
|
|
@@ -1509,6 +1509,8 @@ enum netdev_priv_flags {
|
|
* @if_port: Selectable AUI, TP, ...
|
|
* @dma: DMA channel
|
|
* @mtu: Interface MTU value
|
|
+ * @min_mtu: Interface Minimum MTU value
|
|
+ * @max_mtu: Interface Maximum MTU value
|
|
* @type: Interface hardware type
|
|
* @hard_header_len: Maximum hardware header length.
|
|
* @min_header_len: Minimum hardware header length
|
|
@@ -1735,6 +1737,8 @@ struct net_device {
|
|
unsigned char dma;
|
|
|
|
unsigned int mtu;
|
|
+ unsigned int min_mtu;
|
|
+ unsigned int max_mtu;
|
|
unsigned short type;
|
|
unsigned short hard_header_len;
|
|
unsigned short min_header_len;
|
|
--- a/include/linux/skbuff.h
|
|
+++ b/include/linux/skbuff.h
|
|
@@ -903,6 +903,7 @@ void kfree_skb(struct sk_buff *skb);
|
|
void kfree_skb_list(struct sk_buff *segs);
|
|
void skb_tx_error(struct sk_buff *skb);
|
|
void consume_skb(struct sk_buff *skb);
|
|
+void skb_recycle(struct sk_buff *skb);
|
|
void __kfree_skb(struct sk_buff *skb);
|
|
extern struct kmem_cache *skbuff_head_cache;
|
|
|
|
@@ -3057,6 +3058,7 @@ static inline void skb_free_datagram_loc
|
|
}
|
|
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
|
|
int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
|
|
+void copy_skb_header(struct sk_buff *new, const struct sk_buff *old);
|
|
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
|
|
__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
|
|
int len, __wsum csum);
|
|
--- a/include/linux/sys_soc.h
|
|
+++ b/include/linux/sys_soc.h
|
|
@@ -13,6 +13,7 @@ struct soc_device_attribute {
|
|
const char *family;
|
|
const char *revision;
|
|
const char *soc_id;
|
|
+ const void *data;
|
|
};
|
|
|
|
/**
|
|
@@ -34,4 +35,6 @@ void soc_device_unregister(struct soc_de
|
|
*/
|
|
struct device *soc_device_to_device(struct soc_device *soc);
|
|
|
|
+const struct soc_device_attribute *soc_device_match(
|
|
+ const struct soc_device_attribute *matches);
|
|
#endif /* __SOC_BUS_H */
|
|
--- a/include/uapi/linux/if_ether.h
|
|
+++ b/include/uapi/linux/if_ether.h
|
|
@@ -35,6 +35,7 @@
|
|
#define ETH_DATA_LEN 1500 /* Max. octets in payload */
|
|
#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
|
|
#define ETH_FCS_LEN 4 /* Octets in the FCS */
|
|
+#define ETH_MIN_MTU 68 /* Min IPv4 MTU per RFC791 */
|
|
|
|
/*
|
|
* These are the defined Ethernet Protocol ID's.
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -6630,9 +6630,18 @@ int dev_set_mtu(struct net_device *dev,
|
|
if (new_mtu == dev->mtu)
|
|
return 0;
|
|
|
|
- /* MTU must be positive. */
|
|
- if (new_mtu < 0)
|
|
+ /* MTU must be positive, and in range */
|
|
+ if (new_mtu < 0 || new_mtu < dev->min_mtu) {
|
|
+ net_err_ratelimited("%s: Invalid MTU %d requested, hw min %d\n",
|
|
+ dev->name, new_mtu, dev->min_mtu);
|
|
return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (dev->max_mtu > 0 && new_mtu > dev->max_mtu) {
|
|
+ net_err_ratelimited("%s: Invalid MTU %d requested, hw max %d\n",
|
|
+ dev->name, new_mtu, dev->min_mtu);
|
|
+ return -EINVAL;
|
|
+ }
|
|
|
|
if (!netif_device_present(dev))
|
|
return -ENODEV;
|
|
--- a/net/core/skbuff.c
|
|
+++ b/net/core/skbuff.c
|
|
@@ -842,6 +842,32 @@ void napi_consume_skb(struct sk_buff *sk
|
|
}
|
|
EXPORT_SYMBOL(napi_consume_skb);
|
|
|
|
+/**
|
|
+ * skb_recycle - clean up an skb for reuse
|
|
+ * @skb: buffer
|
|
+ *
|
|
+ * Recycles the skb to be reused as a receive buffer. This
|
|
+ * function does any necessary reference count dropping, and
|
|
+ * cleans up the skbuff as if it just came from __alloc_skb().
|
|
+ */
|
|
+void skb_recycle(struct sk_buff *skb)
|
|
+{
|
|
+ struct skb_shared_info *shinfo;
|
|
+ u8 head_frag = skb->head_frag;
|
|
+
|
|
+ skb_release_head_state(skb);
|
|
+
|
|
+ shinfo = skb_shinfo(skb);
|
|
+ memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
|
|
+ atomic_set(&shinfo->dataref, 1);
|
|
+
|
|
+ memset(skb, 0, offsetof(struct sk_buff, tail));
|
|
+ skb->data = skb->head + NET_SKB_PAD;
|
|
+ skb->head_frag = head_frag;
|
|
+ skb_reset_tail_pointer(skb);
|
|
+}
|
|
+EXPORT_SYMBOL(skb_recycle);
|
|
+
|
|
/* Make sure a field is enclosed inside headers_start/headers_end section */
|
|
#define CHECK_SKB_FIELD(field) \
|
|
BUILD_BUG_ON(offsetof(struct sk_buff, field) < \
|
|
@@ -1073,7 +1099,7 @@ static void skb_headers_offset_update(st
|
|
skb->inner_mac_header += off;
|
|
}
|
|
|
|
-static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
|
|
+void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
|
|
{
|
|
__copy_skb_header(new, old);
|
|
|
|
@@ -1081,6 +1107,7 @@ static void copy_skb_header(struct sk_bu
|
|
skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
|
|
skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
|
|
}
|
|
+EXPORT_SYMBOL(copy_skb_header);
|
|
|
|
static inline int skb_alloc_rx_flag(const struct sk_buff *skb)
|
|
{
|
|
--- a/net/sched/sch_generic.c
|
|
+++ b/net/sched/sch_generic.c
|
|
@@ -309,6 +309,13 @@ static void dev_watchdog(unsigned long a
|
|
txq->trans_timeout++;
|
|
break;
|
|
}
|
|
+
|
|
+ /* Devices with HW_ACCEL_MQ have multiple txqs
|
|
+ * but update only the first one's transmission
|
|
+ * timestamp so avoid checking the rest.
|
|
+ */
|
|
+ if (dev->features & NETIF_F_HW_ACCEL_MQ)
|
|
+ break;
|
|
}
|
|
|
|
if (some_queue_timedout) {
|