From: Greg Kroah-Hartman Date: Fri, 22 Mar 2013 21:21:34 +0000 (-0700) Subject: 3.0-stable patches X-Git-Tag: v3.0.71~28 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=69df004a8f7cbc7b1c91f6cb1c8c230ba24b01c1;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0-stable patches added patches: inet-limit-length-of-fragment-queue-hash-table-bucket-lists.patch ipv4-fix-definition-of-fib_table_hashsz.patch netconsole-don-t-call-__netpoll_cleanup-while-atomic.patch net-ipv4-ensure-that-location-of-timestamp-option-is-stored.patch rtnetlink-mask-the-rta_type-when-range-checking.patch sctp-don-t-break-the-loop-while-meeting-the-active_path-so-as-to-find-the-matched-transport.patch sfc-convert-firmware-subtypes-to-native-byte-order-in-efx_mcdi_get_board_cfg.patch sfc-detach-net-device-when-stopping-queues-for-reconfiguration.patch sfc-disable-soft-interrupt-handling-during-efx_device_detach_sync.patch sfc-do-not-attempt-to-flush-queues-if-dma-is-disabled.patch sfc-fix-efx_rx_buf_offset-in-the-presence-of-swiotlb.patch sfc-fix-loop-condition-for-efx_filter_search-when-for_insert.patch sfc-fix-siena-mac-statistics-on-big-endian-platforms.patch sfc-fix-timekeeping-in-efx_mcdi_poll.patch sfc-fix-two-causes-of-flush-failure.patch sfc-lock-tx-queues-when-calling-netif_device_detach.patch sfc-only-use-tx-push-if-a-single-descriptor-is-to-be-written.patch sfc-properly-sync-rx-dma-buffer-when-it-is-not-the-last-in-the-page.patch --- diff --git a/queue-3.0/inet-limit-length-of-fragment-queue-hash-table-bucket-lists.patch b/queue-3.0/inet-limit-length-of-fragment-queue-hash-table-bucket-lists.patch new file mode 100644 index 00000000000..31e0a3d3eac --- /dev/null +++ b/queue-3.0/inet-limit-length-of-fragment-queue-hash-table-bucket-lists.patch @@ -0,0 +1,192 @@ +From 87943415110077993d4a087999061322692a11a3 Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Fri, 15 Mar 2013 11:32:30 +0000 +Subject: inet: limit length of fragment queue hash table bucket lists + + +From: Hannes Frederic Sowa + +[ Upstream commit 5a3da1fe9561828d0ca7eca664b16ec2b9bf0055 ] + +This patch introduces a constant limit of the fragment queue hash +table bucket list lengths. Currently the limit 128 is choosen somewhat +arbitrary and just ensures that we can fill up the fragment cache with +empty packets up to the default ip_frag_high_thresh limits. It should +just protect from list iteration eating considerable amounts of cpu. + +If we reach the maximum length in one hash bucket a warning is printed. +This is implemented on the caller side of inet_frag_find to distinguish +between the different users of inet_fragment.c. + +I dropped the out of memory warning in the ipv4 fragment lookup path, +because we already get a warning by the slab allocator. + +Cc: Eric Dumazet +Cc: Jesper Dangaard Brouer +Signed-off-by: Hannes Frederic Sowa +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/net/inet_frag.h | 9 +++++++++ + net/ipv4/inet_fragment.c | 20 +++++++++++++++++++- + net/ipv4/ip_fragment.c | 12 ++++++------ + net/ipv6/netfilter/nf_conntrack_reasm.c | 12 ++++++------ + net/ipv6/reassembly.c | 8 ++++++-- + 5 files changed, 46 insertions(+), 15 deletions(-) + +--- a/include/net/inet_frag.h ++++ b/include/net/inet_frag.h +@@ -33,6 +33,13 @@ struct inet_frag_queue { + + #define INETFRAGS_HASHSZ 64 + ++/* averaged: ++ * max_depth = default ipfrag_high_thresh / INETFRAGS_HASHSZ / ++ * rounded up (SKB_TRUELEN(0) + sizeof(struct ipq or ++ * struct frag_queue)) ++ */ ++#define INETFRAGS_MAXDEPTH 128 ++ + struct inet_frags { + struct hlist_head hash[INETFRAGS_HASHSZ]; + rwlock_t lock; +@@ -64,6 +71,8 @@ int inet_frag_evictor(struct netns_frags + struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, + struct inet_frags *f, void *key, unsigned int hash) + __releases(&f->lock); ++void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q, ++ const char *prefix); + + static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f) + { +--- a/net/ipv4/inet_fragment.c ++++ b/net/ipv4/inet_fragment.c +@@ -21,6 +21,7 @@ + #include + #include + ++#include + #include + + static void inet_frag_secret_rebuild(unsigned long dummy) +@@ -271,6 +272,7 @@ struct inet_frag_queue *inet_frag_find(s + { + struct inet_frag_queue *q; + struct hlist_node *n; ++ int depth = 0; + + hlist_for_each_entry(q, n, &f->hash[hash], list) { + if (q->net == nf && f->match(q, key)) { +@@ -278,9 +280,25 @@ struct inet_frag_queue *inet_frag_find(s + read_unlock(&f->lock); + return q; + } ++ depth++; + } + read_unlock(&f->lock); + +- return inet_frag_create(nf, f, key); ++ if (depth <= INETFRAGS_MAXDEPTH) ++ return inet_frag_create(nf, f, key); ++ else ++ return ERR_PTR(-ENOBUFS); + } + EXPORT_SYMBOL(inet_frag_find); ++ ++void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q, ++ const char *prefix) ++{ ++ static const char msg[] = "inet_frag_find: Fragment hash bucket" ++ " list length grew over limit " __stringify(INETFRAGS_MAXDEPTH) ++ ". Dropping fragment.\n"; ++ ++ if (PTR_ERR(q) == -ENOBUFS) ++ LIMIT_NETDEBUG(KERN_WARNING "%s%s", prefix, msg); ++} ++EXPORT_SYMBOL(inet_frag_maybe_warn_overflow); +--- a/net/ipv4/ip_fragment.c ++++ b/net/ipv4/ip_fragment.c +@@ -20,6 +20,8 @@ + * Patrick McHardy : LRU queue of frag heads for evictor. + */ + ++#define pr_fmt(fmt) "IPv4: " fmt ++ + #include + #include + #include +@@ -292,14 +294,12 @@ static inline struct ipq *ip_find(struct + hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); + + q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash); +- if (q == NULL) +- goto out_nomem; ++ if (IS_ERR_OR_NULL(q)) { ++ inet_frag_maybe_warn_overflow(q, pr_fmt()); ++ return NULL; ++ } + + return container_of(q, struct ipq, q); +- +-out_nomem: +- LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n"); +- return NULL; + } + + /* Is the fragment too far ahead to be part of ipq? */ +--- a/net/ipv6/netfilter/nf_conntrack_reasm.c ++++ b/net/ipv6/netfilter/nf_conntrack_reasm.c +@@ -14,6 +14,8 @@ + * 2 of the License, or (at your option) any later version. + */ + ++#define pr_fmt(fmt) "IPv6-nf: " fmt ++ + #include + #include + #include +@@ -176,14 +178,12 @@ fq_find(__be32 id, u32 user, struct in6_ + + q = inet_frag_find(&nf_init_frags, &nf_frags, &arg, hash); + local_bh_enable(); +- if (q == NULL) +- goto oom; ++ if (IS_ERR_OR_NULL(q)) { ++ inet_frag_maybe_warn_overflow(q, pr_fmt()); ++ return NULL; ++ } + + return container_of(q, struct nf_ct_frag6_queue, q); +- +-oom: +- pr_debug("Can't alloc new queue\n"); +- return NULL; + } + + +--- a/net/ipv6/reassembly.c ++++ b/net/ipv6/reassembly.c +@@ -26,6 +26,9 @@ + * YOSHIFUJI,H. @USAGI Always remove fragment header to + * calculate ICV correctly. + */ ++ ++#define pr_fmt(fmt) "IPv6: " fmt ++ + #include + #include + #include +@@ -239,9 +242,10 @@ fq_find(struct net *net, __be32 id, cons + hash = inet6_hash_frag(id, src, dst, ip6_frags.rnd); + + q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); +- if (q == NULL) ++ if (IS_ERR_OR_NULL(q)) { ++ inet_frag_maybe_warn_overflow(q, pr_fmt()); + return NULL; +- ++ } + return container_of(q, struct frag_queue, q); + } + diff --git a/queue-3.0/ipv4-fix-definition-of-fib_table_hashsz.patch b/queue-3.0/ipv4-fix-definition-of-fib_table_hashsz.patch new file mode 100644 index 00000000000..9ace03dff1c --- /dev/null +++ b/queue-3.0/ipv4-fix-definition-of-fib_table_hashsz.patch @@ -0,0 +1,61 @@ +From 6a3f604d999488847254e8e71202420e92961cdf Mon Sep 17 00:00:00 2001 +From: "Denis V. Lunev" +Date: Wed, 13 Mar 2013 00:24:15 +0000 +Subject: ipv4: fix definition of FIB_TABLE_HASHSZ + + +From: "Denis V. Lunev" + +[ Upstream commit 5b9e12dbf92b441b37136ea71dac59f05f2673a9 ] + +a long time ago by the commit + + commit 93456b6d7753def8760b423ac6b986eb9d5a4a95 + Author: Denis V. Lunev + Date: Thu Jan 10 03:23:38 2008 -0800 + + [IPV4]: Unify access to the routing tables. + +the defenition of FIB_HASH_TABLE size has obtained wrong dependency: +it should depend upon CONFIG_IP_MULTIPLE_TABLES (as was in the original +code) but it was depended from CONFIG_IP_ROUTE_MULTIPATH + +This patch returns the situation to the original state. + +The problem was spotted by Tingwei Liu. + +Signed-off-by: Denis V. Lunev +CC: Tingwei Liu +CC: Alexey Kuznetsov +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/net/ip_fib.h | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/include/net/ip_fib.h ++++ b/include/net/ip_fib.h +@@ -129,18 +129,16 @@ struct fib_result_nl { + }; + + #ifdef CONFIG_IP_ROUTE_MULTIPATH +- + #define FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel]) +- +-#define FIB_TABLE_HASHSZ 2 +- + #else /* CONFIG_IP_ROUTE_MULTIPATH */ +- + #define FIB_RES_NH(res) ((res).fi->fib_nh[0]) ++#endif /* CONFIG_IP_ROUTE_MULTIPATH */ + ++#ifdef CONFIG_IP_MULTIPLE_TABLES + #define FIB_TABLE_HASHSZ 256 +- +-#endif /* CONFIG_IP_ROUTE_MULTIPATH */ ++#else ++#define FIB_TABLE_HASHSZ 2 ++#endif + + extern __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh); + diff --git a/queue-3.0/net-ipv4-ensure-that-location-of-timestamp-option-is-stored.patch b/queue-3.0/net-ipv4-ensure-that-location-of-timestamp-option-is-stored.patch new file mode 100644 index 00000000000..8512ae316b3 --- /dev/null +++ b/queue-3.0/net-ipv4-ensure-that-location-of-timestamp-option-is-stored.patch @@ -0,0 +1,65 @@ +From fddadd642d6f754bb2b375af63b1d58dd14a4bb0 Mon Sep 17 00:00:00 2001 +From: David Ward +Date: Mon, 11 Mar 2013 10:43:39 +0000 +Subject: net/ipv4: Ensure that location of timestamp option is stored + + +From: David Ward + +[ Upstream commit 4660c7f498c07c43173142ea95145e9dac5a6d14 ] + +This is needed in order to detect if the timestamp option appears +more than once in a packet, to remove the option if the packet is +fragmented, etc. My previous change neglected to store the option +location when the router addresses were prespecified and Pointer > +Length. But now the option location is also stored when Flag is an +unrecognized value, to ensure these option handling behaviors are +still performed. + +Signed-off-by: David Ward +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/ip_options.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/net/ipv4/ip_options.c ++++ b/net/ipv4/ip_options.c +@@ -358,7 +358,6 @@ int ip_options_compile(struct net *net, + } + switch (optptr[3]&0xF) { + case IPOPT_TS_TSONLY: +- opt->ts = optptr - iph; + if (skb) + timeptr = &optptr[optptr[2]-1]; + opt->ts_needtime = 1; +@@ -369,7 +368,6 @@ int ip_options_compile(struct net *net, + pp_ptr = optptr + 2; + goto error; + } +- opt->ts = optptr - iph; + if (rt) { + memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4); + timeptr = &optptr[optptr[2]+3]; +@@ -383,7 +381,6 @@ int ip_options_compile(struct net *net, + pp_ptr = optptr + 2; + goto error; + } +- opt->ts = optptr - iph; + { + __be32 addr; + memcpy(&addr, &optptr[optptr[2]-1], 4); +@@ -416,12 +413,12 @@ int ip_options_compile(struct net *net, + pp_ptr = optptr + 3; + goto error; + } +- opt->ts = optptr - iph; + if (skb) { + optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4); + opt->is_changed = 1; + } + } ++ opt->ts = optptr - iph; + break; + case IPOPT_RA: + if (optlen < 4) { diff --git a/queue-3.0/netconsole-don-t-call-__netpoll_cleanup-while-atomic.patch b/queue-3.0/netconsole-don-t-call-__netpoll_cleanup-while-atomic.patch new file mode 100644 index 00000000000..1f347fb3bd8 --- /dev/null +++ b/queue-3.0/netconsole-don-t-call-__netpoll_cleanup-while-atomic.patch @@ -0,0 +1,63 @@ +From 7d189b63179e2260024257f8b3ec9eb664d5773f Mon Sep 17 00:00:00 2001 +From: Veaceslav Falico +Date: Mon, 11 Mar 2013 00:21:48 +0000 +Subject: netconsole: don't call __netpoll_cleanup() while atomic + + +From: Veaceslav Falico + +[ Upstream commit 3f315bef23075ea8a98a6fe4221a83b83456d970 ] + +__netpoll_cleanup() is called in netconsole_netdev_event() while holding a +spinlock. Release/acquire the spinlock before/after it and restart the +loop. Also, disable the netconsole completely, because we won't have chance +after the restart of the loop, and might end up in a situation where +nt->enabled == 1 and nt->np.dev == NULL. + +Signed-off-by: Veaceslav Falico +Acked-by: Neil Horman +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/netconsole.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -630,6 +630,7 @@ static int netconsole_netdev_event(struc + goto done; + + spin_lock_irqsave(&target_list_lock, flags); ++restart: + list_for_each_entry(nt, &target_list, list) { + netconsole_target_get(nt); + if (nt->np.dev == dev) { +@@ -642,20 +643,17 @@ static int netconsole_netdev_event(struc + case NETDEV_UNREGISTER: + /* + * rtnl_lock already held ++ * we might sleep in __netpoll_cleanup() + */ +- if (nt->np.dev) { +- spin_unlock_irqrestore( +- &target_list_lock, +- flags); +- __netpoll_cleanup(&nt->np); +- spin_lock_irqsave(&target_list_lock, +- flags); +- dev_put(nt->np.dev); +- nt->np.dev = NULL; +- } ++ spin_unlock_irqrestore(&target_list_lock, flags); ++ __netpoll_cleanup(&nt->np); ++ spin_lock_irqsave(&target_list_lock, flags); ++ dev_put(nt->np.dev); ++ nt->np.dev = NULL; + nt->enabled = 0; + stopped = true; +- break; ++ netconsole_target_put(nt); ++ goto restart; + } + } + netconsole_target_put(nt); diff --git a/queue-3.0/rtnetlink-mask-the-rta_type-when-range-checking.patch b/queue-3.0/rtnetlink-mask-the-rta_type-when-range-checking.patch new file mode 100644 index 00000000000..6ca5e33a29b --- /dev/null +++ b/queue-3.0/rtnetlink-mask-the-rta_type-when-range-checking.patch @@ -0,0 +1,34 @@ +From 11353872c868b308382cc0bda4e05c29646e23f2 Mon Sep 17 00:00:00 2001 +From: Vlad Yasevich +Date: Wed, 13 Mar 2013 04:18:58 +0000 +Subject: rtnetlink: Mask the rta_type when range checking + + +From: Vlad Yasevich + +[ Upstream commit a5b8db91442fce9c9713fcd656c3698f1adde1d6 ] + +Range/validity checks on rta_type in rtnetlink_rcv_msg() do +not account for flags that may be set. This causes the function +to return -EINVAL when flags are set on the type (for example +NLA_F_NESTED). + +Signed-off-by: Vlad Yasevich +Acked-by: Thomas Graf +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/core/rtnetlink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -2011,7 +2011,7 @@ static int rtnetlink_rcv_msg(struct sk_b + struct rtattr *attr = (void *)nlh + NLMSG_ALIGN(min_len); + + while (RTA_OK(attr, attrlen)) { +- unsigned flavor = attr->rta_type; ++ unsigned int flavor = attr->rta_type & NLA_TYPE_MASK; + if (flavor) { + if (flavor > rta_max[sz_idx]) + return -EINVAL; diff --git a/queue-3.0/sctp-don-t-break-the-loop-while-meeting-the-active_path-so-as-to-find-the-matched-transport.patch b/queue-3.0/sctp-don-t-break-the-loop-while-meeting-the-active_path-so-as-to-find-the-matched-transport.patch new file mode 100644 index 00000000000..c4fdfa8913f --- /dev/null +++ b/queue-3.0/sctp-don-t-break-the-loop-while-meeting-the-active_path-so-as-to-find-the-matched-transport.patch @@ -0,0 +1,36 @@ +From 878d9aac5ab18c9452efc4df53ae69f72ca2502b Mon Sep 17 00:00:00 2001 +From: Xufeng Zhang +Date: Thu, 7 Mar 2013 21:39:37 +0000 +Subject: sctp: don't break the loop while meeting the active_path so as to find the matched transport + + +From: Xufeng Zhang + +[ Upstream commit 2317f449af30073cfa6ec8352e4a65a89e357bdd ] + +sctp_assoc_lookup_tsn() function searchs which transport a certain TSN +was sent on, if not found in the active_path transport, then go search +all the other transports in the peer's transport_addr_list, however, we +should continue to the next entry rather than break the loop when meet +the active_path transport. + +Signed-off-by: Xufeng Zhang +Acked-by: Neil Horman +Acked-by: Vlad Yasevich +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/associola.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/sctp/associola.c ++++ b/net/sctp/associola.c +@@ -1043,7 +1043,7 @@ struct sctp_transport *sctp_assoc_lookup + transports) { + + if (transport == active) +- break; ++ continue; + list_for_each_entry(chunk, &transport->transmitted, + transmitted_list) { + if (key == chunk->subh.data_hdr->tsn) { diff --git a/queue-3.0/series b/queue-3.0/series index a0fb649f41a..2a3b0ea5211 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -1,2 +1,20 @@ revert-usb-ehci-don-t-check-dma-values-in-qh-overlays.patch sunsu-fix-panic-in-case-of-nonexistent-port-at-console-ttysy-cmdline-option.patch +net-ipv4-ensure-that-location-of-timestamp-option-is-stored.patch +netconsole-don-t-call-__netpoll_cleanup-while-atomic.patch +sctp-don-t-break-the-loop-while-meeting-the-active_path-so-as-to-find-the-matched-transport.patch +ipv4-fix-definition-of-fib_table_hashsz.patch +rtnetlink-mask-the-rta_type-when-range-checking.patch +inet-limit-length-of-fragment-queue-hash-table-bucket-lists.patch +sfc-fix-loop-condition-for-efx_filter_search-when-for_insert.patch +sfc-fix-siena-mac-statistics-on-big-endian-platforms.patch +sfc-do-not-attempt-to-flush-queues-if-dma-is-disabled.patch +sfc-convert-firmware-subtypes-to-native-byte-order-in-efx_mcdi_get_board_cfg.patch +sfc-fix-two-causes-of-flush-failure.patch +sfc-lock-tx-queues-when-calling-netif_device_detach.patch +sfc-fix-timekeeping-in-efx_mcdi_poll.patch +sfc-properly-sync-rx-dma-buffer-when-it-is-not-the-last-in-the-page.patch +sfc-fix-efx_rx_buf_offset-in-the-presence-of-swiotlb.patch +sfc-detach-net-device-when-stopping-queues-for-reconfiguration.patch +sfc-disable-soft-interrupt-handling-during-efx_device_detach_sync.patch +sfc-only-use-tx-push-if-a-single-descriptor-is-to-be-written.patch diff --git a/queue-3.0/sfc-convert-firmware-subtypes-to-native-byte-order-in-efx_mcdi_get_board_cfg.patch b/queue-3.0/sfc-convert-firmware-subtypes-to-native-byte-order-in-efx_mcdi_get_board_cfg.patch new file mode 100644 index 00000000000..5514d8b484a --- /dev/null +++ b/queue-3.0/sfc-convert-firmware-subtypes-to-native-byte-order-in-efx_mcdi_get_board_cfg.patch @@ -0,0 +1,55 @@ +From 6d7cf8ca06e28ea10f95a3f8af14e69a19df63ff Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Fri, 7 Sep 2012 00:58:10 +0100 +Subject: sfc: Convert firmware subtypes to native byte order in efx_mcdi_get_board_cfg() + + +From: Ben Hutchings + +[ Upstream commit bfeed902946a31692e7a24ed355b6d13ac37d014 ] + +On big-endian systems the MTD partition names currently have mangled +subtype numbers and are not recognised by the firmware update tool +(sfupdate). + +Signed-off-by: Ben Hutchings +[bwh: Backported to 3.0: use old macros for length of firmware subtype array] +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/mcdi.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +--- a/drivers/net/sfc/mcdi.c ++++ b/drivers/net/sfc/mcdi.c +@@ -666,9 +666,8 @@ int efx_mcdi_get_board_cfg(struct efx_ni + u16 *fw_subtype_list) + { + uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LEN]; +- size_t outlen; ++ size_t outlen, offset, i; + int port_num = efx_port_num(efx); +- int offset; + int rc; + + BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0); +@@ -688,10 +687,16 @@ int efx_mcdi_get_board_cfg(struct efx_ni + : MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST; + if (mac_address) + memcpy(mac_address, outbuf + offset, ETH_ALEN); +- if (fw_subtype_list) +- memcpy(fw_subtype_list, +- outbuf + MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST, +- MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN); ++ if (fw_subtype_list) { ++ offset = MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST; ++ for (i = 0; ++ i < MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN / 2; ++ i++) { ++ fw_subtype_list[i] = ++ le16_to_cpup((__le16 *)(outbuf + offset)); ++ offset += 2; ++ } ++ } + + return 0; + diff --git a/queue-3.0/sfc-detach-net-device-when-stopping-queues-for-reconfiguration.patch b/queue-3.0/sfc-detach-net-device-when-stopping-queues-for-reconfiguration.patch new file mode 100644 index 00000000000..0f63fda4034 --- /dev/null +++ b/queue-3.0/sfc-detach-net-device-when-stopping-queues-for-reconfiguration.patch @@ -0,0 +1,91 @@ +From 0013c4ed507a351c4f5d26afc5bf0fb3e11528aa Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Mon, 28 Jan 2013 19:01:06 +0000 +Subject: sfc: Detach net device when stopping queues for reconfiguration + + +From: Ben Hutchings + +[ Upstream commit 29c69a4882641285a854d6d03ca5adbba68c0034 ] + +We must only ever stop TX queues when they are full or the net device +is not 'ready' so far as the net core, and specifically the watchdog, +is concerned. Otherwise, the watchdog may fire *immediately* if no +packets have been added to the queue in the last 5 seconds. + +The device is ready if all the following are true: + +(a) It has a qdisc +(b) It is marked present +(c) It is running +(d) The link is reported up + +(a) and (c) are normally true, and must not be changed by a driver. +(d) is under our control, but fake link changes may disturb userland. +This leaves (b). We already mark the device absent during reset +and self-test, but we need to do the same during MTU changes and ring +reallocation. We don't need to do this when the device is brought +down because then (c) is already false. + +Signed-off-by: Ben Hutchings +[bwh: Backported to 3.0: adjust context] +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/efx.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +--- a/drivers/net/sfc/efx.c ++++ b/drivers/net/sfc/efx.c +@@ -720,6 +720,7 @@ efx_realloc_channels(struct efx_nic *efx + unsigned i; + int rc; + ++ efx_device_detach_sync(efx); + efx_stop_all(efx); + efx_fini_channels(efx); + +@@ -763,6 +764,7 @@ out: + + efx_init_channels(efx); + efx_start_all(efx); ++ netif_device_attach(efx->net_dev); + return rc; + + rollback: +@@ -1530,8 +1532,12 @@ static void efx_stop_all(struct efx_nic + /* Flush efx_mac_work(), refill_workqueue, monitor_work */ + efx_flush_all(efx); + +- /* Stop the kernel transmit interface late, so the watchdog +- * timer isn't ticking over the flush */ ++ /* Stop the kernel transmit interface. This is only valid if ++ * the device is stopped or detached; otherwise the watchdog ++ * may fire immediately. ++ */ ++ WARN_ON(netif_running(efx->net_dev) && ++ netif_device_present(efx->net_dev)); + if (efx_dev_registered(efx)) { + netif_tx_stop_all_queues(efx->net_dev); + netif_tx_lock_bh(efx->net_dev); +@@ -1801,10 +1807,11 @@ static int efx_change_mtu(struct net_dev + if (new_mtu > EFX_MAX_MTU) + return -EINVAL; + +- efx_stop_all(efx); +- + netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu); + ++ efx_device_detach_sync(efx); ++ efx_stop_all(efx); ++ + efx_fini_channels(efx); + + mutex_lock(&efx->mac_lock); +@@ -1817,6 +1824,7 @@ static int efx_change_mtu(struct net_dev + efx_init_channels(efx); + + efx_start_all(efx); ++ netif_device_attach(efx->net_dev); + return rc; + } + diff --git a/queue-3.0/sfc-disable-soft-interrupt-handling-during-efx_device_detach_sync.patch b/queue-3.0/sfc-disable-soft-interrupt-handling-during-efx_device_detach_sync.patch new file mode 100644 index 00000000000..a9e5692a888 --- /dev/null +++ b/queue-3.0/sfc-disable-soft-interrupt-handling-during-efx_device_detach_sync.patch @@ -0,0 +1,38 @@ +From db0b188983e2d83bea89206e03a30b55ee283d3e Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Tue, 5 Mar 2013 01:03:47 +0000 +Subject: sfc: Disable soft interrupt handling during efx_device_detach_sync() + + +From: Ben Hutchings + +[ Upstream commit 35205b211c8d17a8a0b5e8926cb7c73e9a7ef1ad ] + +efx_device_detach_sync() locks all TX queues before marking the device +detached and thus disabling further TX scheduling. But it can still +be interrupted by TX completions which then result in TX scheduling in +soft interrupt context. This will deadlock when it tries to acquire +a TX queue lock that efx_device_detach_sync() already acquired. + +To avoid deadlock, we must use netif_tx_{,un}lock_bh(). + +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/efx.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/sfc/efx.h ++++ b/drivers/net/sfc/efx.h +@@ -158,9 +158,9 @@ static inline void efx_device_detach_syn + * TX scheduler is stopped when we're done and before + * netif_device_present() becomes false. + */ +- netif_tx_lock(dev); ++ netif_tx_lock_bh(dev); + netif_device_detach(dev); +- netif_tx_unlock(dev); ++ netif_tx_unlock_bh(dev); + } + + #endif /* EFX_EFX_H */ diff --git a/queue-3.0/sfc-do-not-attempt-to-flush-queues-if-dma-is-disabled.patch b/queue-3.0/sfc-do-not-attempt-to-flush-queues-if-dma-is-disabled.patch new file mode 100644 index 00000000000..e7db9a0b604 --- /dev/null +++ b/queue-3.0/sfc-do-not-attempt-to-flush-queues-if-dma-is-disabled.patch @@ -0,0 +1,66 @@ +From fd216215412a7635c4ba7054eac461a8500f7475 Mon Sep 17 00:00:00 2001 +From: Stuart Hodgson +Date: Fri, 30 Mar 2012 13:04:51 +0100 +Subject: sfc: Do not attempt to flush queues if DMA is disabled + + +From: Stuart Hodgson + +[ Upstream commit 3dca9d2dc285faf1910d405b65df845cab061356 ] + +efx_nic_fatal_interrupt() disables DMA before scheduling a reset. +After this, we need not and *cannot* flush queues. + +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/efx.c | 33 +++++++++++++++++++-------------- + 1 file changed, 19 insertions(+), 14 deletions(-) + +--- a/drivers/net/sfc/efx.c ++++ b/drivers/net/sfc/efx.c +@@ -651,25 +651,30 @@ static void efx_fini_channels(struct efx + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; ++ struct pci_dev *dev = efx->pci_dev; + int rc; + + EFX_ASSERT_RESET_SERIALISED(efx); + BUG_ON(efx->port_enabled); + +- rc = efx_nic_flush_queues(efx); +- if (rc && EFX_WORKAROUND_7803(efx)) { +- /* Schedule a reset to recover from the flush failure. The +- * descriptor caches reference memory we're about to free, +- * but falcon_reconfigure_mac_wrapper() won't reconnect +- * the MACs because of the pending reset. */ +- netif_err(efx, drv, efx->net_dev, +- "Resetting to recover from flush failure\n"); +- efx_schedule_reset(efx, RESET_TYPE_ALL); +- } else if (rc) { +- netif_err(efx, drv, efx->net_dev, "failed to flush queues\n"); +- } else { +- netif_dbg(efx, drv, efx->net_dev, +- "successfully flushed all queues\n"); ++ /* Only perform flush if dma is enabled */ ++ if (dev->is_busmaster) { ++ rc = efx_nic_flush_queues(efx); ++ ++ if (rc && EFX_WORKAROUND_7803(efx)) { ++ /* Schedule a reset to recover from the flush failure. The ++ * descriptor caches reference memory we're about to free, ++ * but falcon_reconfigure_mac_wrapper() won't reconnect ++ * the MACs because of the pending reset. */ ++ netif_err(efx, drv, efx->net_dev, ++ "Resetting to recover from flush failure\n"); ++ efx_schedule_reset(efx, RESET_TYPE_ALL); ++ } else if (rc) { ++ netif_err(efx, drv, efx->net_dev, "failed to flush queues\n"); ++ } else { ++ netif_dbg(efx, drv, efx->net_dev, ++ "successfully flushed all queues\n"); ++ } + } + + efx_for_each_channel(channel, efx) { diff --git a/queue-3.0/sfc-fix-efx_rx_buf_offset-in-the-presence-of-swiotlb.patch b/queue-3.0/sfc-fix-efx_rx_buf_offset-in-the-presence-of-swiotlb.patch new file mode 100644 index 00000000000..67931aaf159 --- /dev/null +++ b/queue-3.0/sfc-fix-efx_rx_buf_offset-in-the-presence-of-swiotlb.patch @@ -0,0 +1,93 @@ +From f421edcd754f77c2f773aaae7b68067c433f3816 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Thu, 10 Jan 2013 23:51:54 +0000 +Subject: sfc: Fix efx_rx_buf_offset() in the presence of swiotlb + + +From: Ben Hutchings + +[ Upstream commits 06e63c57acbb1df7c35ebe846ae416a8b88dfafa, + b590ace09d51cd39744e0f7662c5e4a0d1b5d952 and + c73e787a8db9117d59b5180baf83203a42ecadca ] + +We assume that the mapping between DMA and virtual addresses is done +on whole pages, so we can find the page offset of an RX buffer using +the lower bits of the DMA address. However, swiotlb maps in units of +2K, breaking this assumption. + +Add an explicit page_offset field to struct efx_rx_buffer. + +Signed-off-by: Ben Hutchings +[bwh: Backported to 3.0: adjust context] +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/net_driver.h | 4 +++- + drivers/net/sfc/rx.c | 10 +++++----- + 2 files changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/net/sfc/net_driver.h ++++ b/drivers/net/sfc/net_driver.h +@@ -214,6 +214,7 @@ struct efx_tx_queue { + * If both this and page are %NULL, the buffer slot is currently free. + * @page: The associated page buffer, if any. + * If both this and skb are %NULL, the buffer slot is currently free. ++ * @page_offset: Offset within page. Valid iff @flags & %EFX_RX_BUF_PAGE. + * @len: Buffer length, in bytes. + * @is_page: Indicates if @page is valid. If false, @skb is valid. + */ +@@ -223,7 +224,8 @@ struct efx_rx_buffer { + struct sk_buff *skb; + struct page *page; + } u; +- unsigned int len; ++ u16 page_offset; ++ u16 len; + bool is_page; + }; + +--- a/drivers/net/sfc/rx.c ++++ b/drivers/net/sfc/rx.c +@@ -94,11 +94,7 @@ static unsigned int rx_refill_limit = 95 + static inline unsigned int efx_rx_buf_offset(struct efx_nic *efx, + struct efx_rx_buffer *buf) + { +- /* Offset is always within one page, so we don't need to consider +- * the page order. +- */ +- return (((__force unsigned long) buf->dma_addr & (PAGE_SIZE - 1)) + +- efx->type->rx_buffer_hash_size); ++ return buf->page_offset + efx->type->rx_buffer_hash_size; + } + static inline unsigned int efx_rx_buf_size(struct efx_nic *efx) + { +@@ -193,6 +189,7 @@ static int efx_init_rx_buffers_page(stru + struct efx_rx_buffer *rx_buf; + struct page *page; + void *page_addr; ++ unsigned int page_offset; + struct efx_rx_page_state *state; + dma_addr_t dma_addr; + unsigned index, count; +@@ -219,12 +216,14 @@ static int efx_init_rx_buffers_page(stru + + page_addr += sizeof(struct efx_rx_page_state); + dma_addr += sizeof(struct efx_rx_page_state); ++ page_offset = sizeof(struct efx_rx_page_state); + + split: + index = rx_queue->added_count & rx_queue->ptr_mask; + rx_buf = efx_rx_buffer(rx_queue, index); + rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN; + rx_buf->u.page = page; ++ rx_buf->page_offset = page_offset + EFX_PAGE_IP_ALIGN; + rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN; + rx_buf->is_page = true; + ++rx_queue->added_count; +@@ -236,6 +235,7 @@ static int efx_init_rx_buffers_page(stru + get_page(page); + dma_addr += (PAGE_SIZE >> 1); + page_addr += (PAGE_SIZE >> 1); ++ page_offset += (PAGE_SIZE >> 1); + ++count; + goto split; + } diff --git a/queue-3.0/sfc-fix-loop-condition-for-efx_filter_search-when-for_insert.patch b/queue-3.0/sfc-fix-loop-condition-for-efx_filter_search-when-for_insert.patch new file mode 100644 index 00000000000..646b0d5f155 --- /dev/null +++ b/queue-3.0/sfc-fix-loop-condition-for-efx_filter_search-when-for_insert.patch @@ -0,0 +1,84 @@ +From 454d85d509053208d0a38e75626e362f55944930 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Fri, 24 Jun 2011 20:26:44 +0100 +Subject: sfc: Fix loop condition for efx_filter_search() when !for_insert + + +From: Ben Hutchings + +[ Upstream commit 4017dbdc14af1903dc9fcba4d08b89c02325069d ] + +efx_filter_remove_filter() fails to remove inserted filters in some cases. + +For example: + + 1. Two filters A and B have specifications that result in an initial + hash collision. + 2. A is inserted first, followed by B. + 3. An attempt to remove B first succeeds, but if A is removed first + a subsequent attempt to remove B fails. + +When searching for an existing filter (!for_insert), +efx_filter_search() must always continue to the maximum search depth +for the given type rather than stopping at the first unused entry. + +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/filter.c | 39 +++++++++++++++++++++++---------------- + 1 file changed, 23 insertions(+), 16 deletions(-) + +--- a/drivers/net/sfc/filter.c ++++ b/drivers/net/sfc/filter.c +@@ -335,28 +335,35 @@ static int efx_filter_search(struct efx_ + bool for_insert, int *depth_required) + { + unsigned hash, incr, filter_idx, depth, depth_max; +- struct efx_filter_spec *cmp; + + hash = efx_filter_hash(key); + incr = efx_filter_increment(key); +- depth_max = (spec->priority <= EFX_FILTER_PRI_HINT ? +- FILTER_CTL_SRCH_HINT_MAX : FILTER_CTL_SRCH_MAX); + +- for (depth = 1, filter_idx = hash & (table->size - 1); +- depth <= depth_max && test_bit(filter_idx, table->used_bitmap); +- ++depth) { +- cmp = &table->spec[filter_idx]; +- if (efx_filter_equal(spec, cmp)) +- goto found; ++ filter_idx = hash & (table->size - 1); ++ depth = 1; ++ depth_max = (for_insert ? ++ (spec->priority <= EFX_FILTER_PRI_HINT ? ++ FILTER_CTL_SRCH_HINT_MAX : FILTER_CTL_SRCH_MAX) : ++ table->search_depth[spec->type]); ++ ++ for (;;) { ++ /* Return success if entry is used and matches this spec ++ * or entry is unused and we are trying to insert. ++ */ ++ if (test_bit(filter_idx, table->used_bitmap) ? ++ efx_filter_equal(spec, &table->spec[filter_idx]) : ++ for_insert) { ++ *depth_required = depth; ++ return filter_idx; ++ } ++ ++ /* Return failure if we reached the maximum search depth */ ++ if (depth == depth_max) ++ return for_insert ? -EBUSY : -ENOENT; ++ + filter_idx = (filter_idx + incr) & (table->size - 1); ++ ++depth; + } +- if (!for_insert) +- return -ENOENT; +- if (depth > depth_max) +- return -EBUSY; +-found: +- *depth_required = depth; +- return filter_idx; + } + + /* Construct/deconstruct external filter IDs */ diff --git a/queue-3.0/sfc-fix-siena-mac-statistics-on-big-endian-platforms.patch b/queue-3.0/sfc-fix-siena-mac-statistics-on-big-endian-platforms.patch new file mode 100644 index 00000000000..8057cc1e40a --- /dev/null +++ b/queue-3.0/sfc-fix-siena-mac-statistics-on-big-endian-platforms.patch @@ -0,0 +1,65 @@ +From aac26712035cb1db1409ad52a9e2c00c4452a39e Mon Sep 17 00:00:00 2001 +From: Steve Hodgson +Date: Wed, 22 Jun 2011 12:11:33 +0100 +Subject: sfc: Fix Siena mac statistics on big endian platforms + + +From: Steve Hodgson + +[ Upstream commit a659b2a94d87add999229ecd9f2f56817d5d737b ] + +[bwh: Use __force in the one place it's needed] +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/siena.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/net/sfc/siena.c ++++ b/drivers/net/sfc/siena.c +@@ -372,14 +372,13 @@ static void siena_remove_nic(struct efx_ + efx->nic_data = NULL; + } + +-#define STATS_GENERATION_INVALID ((u64)(-1)) ++#define STATS_GENERATION_INVALID ((__force __le64)(-1)) + + static int siena_try_update_nic_stats(struct efx_nic *efx) + { +- u64 *dma_stats; ++ __le64 *dma_stats; + struct efx_mac_stats *mac_stats; +- u64 generation_start; +- u64 generation_end; ++ __le64 generation_start, generation_end; + + mac_stats = &efx->mac_stats; + dma_stats = (u64 *)efx->stats_buffer.addr; +@@ -390,7 +389,7 @@ static int siena_try_update_nic_stats(st + rmb(); + + #define MAC_STAT(M, D) \ +- mac_stats->M = dma_stats[MC_CMD_MAC_ ## D] ++ mac_stats->M = le64_to_cpu(dma_stats[MC_CMD_MAC_ ## D]) + + MAC_STAT(tx_bytes, TX_BYTES); + MAC_STAT(tx_bad_bytes, TX_BAD_BYTES); +@@ -460,7 +459,8 @@ static int siena_try_update_nic_stats(st + MAC_STAT(rx_internal_error, RX_INTERNAL_ERROR_PKTS); + mac_stats->rx_good_lt64 = 0; + +- efx->n_rx_nodesc_drop_cnt = dma_stats[MC_CMD_MAC_RX_NODESC_DROPS]; ++ efx->n_rx_nodesc_drop_cnt = ++ le64_to_cpu(dma_stats[MC_CMD_MAC_RX_NODESC_DROPS]); + + #undef MAC_STAT + +@@ -489,7 +489,7 @@ static void siena_update_nic_stats(struc + + static void siena_start_nic_stats(struct efx_nic *efx) + { +- u64 *dma_stats = (u64 *)efx->stats_buffer.addr; ++ __le64 *dma_stats = efx->stats_buffer.addr; + + dma_stats[MC_CMD_MAC_GENERATION_END] = STATS_GENERATION_INVALID; + diff --git a/queue-3.0/sfc-fix-timekeeping-in-efx_mcdi_poll.patch b/queue-3.0/sfc-fix-timekeeping-in-efx_mcdi_poll.patch new file mode 100644 index 00000000000..8b5c25a942e --- /dev/null +++ b/queue-3.0/sfc-fix-timekeeping-in-efx_mcdi_poll.patch @@ -0,0 +1,89 @@ +From 4b98c03ffda282768c7dd09c35783fce1f8cd050 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sat, 1 Dec 2012 02:21:17 +0000 +Subject: sfc: Fix timekeeping in efx_mcdi_poll() + + +From: Ben Hutchings + +[ Upstream commit ebf98e797b4e26ad52ace1511a0b503ee60a6cd4 ] + +efx_mcdi_poll() uses get_seconds() to read the current time and to +implement a polling timeout. The use of this function was chosen +partly because it could easily be replaced in a co-sim environment +with a macro that read the simulated time. + +Unfortunately the real get_seconds() returns the system time (real +time) which is subject to adjustment by e.g. ntpd. If the system time +is adjusted forward during a polled MCDI operation, the effective +timeout can be shorter than the intended 10 seconds, resulting in a +spurious failure. It is also possible for a backward adjustment to +delay detection of a areal failure. + +Use jiffies instead, and change MCDI_RPC_TIMEOUT to be denominated in +jiffies. Also correct rounding of the timeout: check time > finish +(or rather time_after(time, finish)) and not time >= finish. + +Signed-off-by: Ben Hutchings +[bwh: Backported to 3.0: adjust context] +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/mcdi.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/net/sfc/mcdi.c ++++ b/drivers/net/sfc/mcdi.c +@@ -30,7 +30,7 @@ + #define REBOOT_FLAG_PORT0 0x3f8 + #define REBOOT_FLAG_PORT1 0x3fc + +-#define MCDI_RPC_TIMEOUT 10 /*seconds */ ++#define MCDI_RPC_TIMEOUT (10 * HZ) + + #define MCDI_PDU(efx) \ + (efx_port_num(efx) ? CMD_PDU_PORT1 : CMD_PDU_PORT0) +@@ -120,7 +120,7 @@ static void efx_mcdi_copyout(struct efx_ + static int efx_mcdi_poll(struct efx_nic *efx) + { + struct efx_mcdi_iface *mcdi = efx_mcdi(efx); +- unsigned int time, finish; ++ unsigned long time, finish; + unsigned int respseq, respcmd, error; + unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned int rc, spins; +@@ -136,7 +136,7 @@ static int efx_mcdi_poll(struct efx_nic + * and poll once a jiffy (approximately) + */ + spins = TICK_USEC; +- finish = get_seconds() + MCDI_RPC_TIMEOUT; ++ finish = jiffies + MCDI_RPC_TIMEOUT; + + while (1) { + if (spins != 0) { +@@ -146,7 +146,7 @@ static int efx_mcdi_poll(struct efx_nic + schedule_timeout_uninterruptible(1); + } + +- time = get_seconds(); ++ time = jiffies; + + rmb(); + efx_readd(efx, ®, pdu); +@@ -158,7 +158,7 @@ static int efx_mcdi_poll(struct efx_nic + EFX_DWORD_FIELD(reg, MCDI_HEADER_RESPONSE)) + break; + +- if (time >= finish) ++ if (time_after(time, finish)) + return -ETIMEDOUT; + } + +@@ -250,7 +250,7 @@ static int efx_mcdi_await_completion(str + if (wait_event_timeout( + mcdi->wq, + atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED, +- msecs_to_jiffies(MCDI_RPC_TIMEOUT * 1000)) == 0) ++ MCDI_RPC_TIMEOUT) == 0) + return -ETIMEDOUT; + + /* Check if efx_mcdi_set_mode() switched us back to polled completions. diff --git a/queue-3.0/sfc-fix-two-causes-of-flush-failure.patch b/queue-3.0/sfc-fix-two-causes-of-flush-failure.patch new file mode 100644 index 00000000000..ae2e4c309d8 --- /dev/null +++ b/queue-3.0/sfc-fix-two-causes-of-flush-failure.patch @@ -0,0 +1,211 @@ +From ef691ef73fa43298c5499ff6eaec8256115edaf0 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Mon, 23 May 2011 12:18:45 +0100 +Subject: sfc: Fix two causes of flush failure + + +From: Ben Hutchings + +[ Upstream commits a606f4325dca6950996abbae452d33f2af095f39, + d5e8cc6c946e0857826dcfbb3585068858445bfe, + 525d9e824018cd7cc8d8d44832ddcd363abfe6e1 ] + +The TX DMA engine issues upstream read requests when there is room in +the TX FIFO for the completion. However, the fetches for the rest of +the packet might be delayed by any back pressure. Since a flush must +wait for an EOP, the entire flush may be delayed by back pressure. + +Mitigate this by disabling flow control before the flushes are +started. Since PF and VF flushes run in parallel introduce +fc_disable, a reference count of the number of flushes outstanding. + +The same principle could be applied to Falcon, but that +would bring with it its own testing. + +We sometimes hit a "failed to flush" timeout on some TX queues, but the +flushes have completed and the flush completion events seem to go missing. +In this case, we can check the TX_DESC_PTR_TBL register and drain the +queues if the flushes had finished. + +Signed-off-by: Ben Hutchings +[bwh: Backported to 3.0: + - Call efx_nic_type::finish_flush() on both success and failure paths + - Check the TX_DESC_PTR_TBL registers in the polling loop + - Declare efx_mcdi_set_mac() extern] +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/falcon.c | 2 ++ + drivers/net/sfc/mcdi.h | 1 + + drivers/net/sfc/mcdi_mac.c | 4 +++- + drivers/net/sfc/net_driver.h | 6 ++++++ + drivers/net/sfc/nic.c | 21 ++++++++++++++++++--- + drivers/net/sfc/nic.h | 2 ++ + drivers/net/sfc/siena.c | 15 ++++++++++++++- + 7 files changed, 46 insertions(+), 5 deletions(-) + +--- a/drivers/net/sfc/falcon.c ++++ b/drivers/net/sfc/falcon.c +@@ -1714,6 +1714,7 @@ const struct efx_nic_type falcon_a1_nic_ + .remove_port = falcon_remove_port, + .handle_global_event = falcon_handle_global_event, + .prepare_flush = falcon_prepare_flush, ++ .finish_flush = efx_port_dummy_op_void, + .update_stats = falcon_update_nic_stats, + .start_stats = falcon_start_nic_stats, + .stop_stats = falcon_stop_nic_stats, +@@ -1755,6 +1756,7 @@ const struct efx_nic_type falcon_b0_nic_ + .remove_port = falcon_remove_port, + .handle_global_event = falcon_handle_global_event, + .prepare_flush = falcon_prepare_flush, ++ .finish_flush = efx_port_dummy_op_void, + .update_stats = falcon_update_nic_stats, + .start_stats = falcon_start_nic_stats, + .stop_stats = falcon_stop_nic_stats, +--- a/drivers/net/sfc/mcdi.h ++++ b/drivers/net/sfc/mcdi.h +@@ -126,5 +126,6 @@ extern int efx_mcdi_wol_filter_set_magic + extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out); + extern int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id); + extern int efx_mcdi_wol_filter_reset(struct efx_nic *efx); ++extern int efx_mcdi_set_mac(struct efx_nic *efx); + + #endif /* EFX_MCDI_H */ +--- a/drivers/net/sfc/mcdi_mac.c ++++ b/drivers/net/sfc/mcdi_mac.c +@@ -13,7 +13,7 @@ + #include "mcdi.h" + #include "mcdi_pcol.h" + +-static int efx_mcdi_set_mac(struct efx_nic *efx) ++int efx_mcdi_set_mac(struct efx_nic *efx) + { + u32 reject, fcntl; + u8 cmdbytes[MC_CMD_SET_MAC_IN_LEN]; +@@ -45,6 +45,8 @@ static int efx_mcdi_set_mac(struct efx_n + } + if (efx->wanted_fc & EFX_FC_AUTO) + fcntl = MC_CMD_FCNTL_AUTO; ++ if (efx->fc_disable) ++ fcntl = MC_CMD_FCNTL_OFF; + + MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_FCNTL, fcntl); + +--- a/drivers/net/sfc/net_driver.h ++++ b/drivers/net/sfc/net_driver.h +@@ -690,6 +690,9 @@ struct efx_filter_state; + * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. + * @multicast_hash: Multicast hash table + * @wanted_fc: Wanted flow control flags ++ * @fc_disable: When non-zero flow control is disabled. Typically used to ++ * ensure that network back pressure doesn't delay dma queue flushes. ++ * Serialised by the rtnl lock. + * @mac_work: Work item for changing MAC promiscuity and multicast hash + * @loopback_mode: Loopback status + * @loopback_modes: Supported loopback mode bitmask +@@ -783,6 +786,7 @@ struct efx_nic { + bool promiscuous; + union efx_multicast_hash multicast_hash; + u8 wanted_fc; ++ unsigned fc_disable; + + atomic_t rx_reset; + enum efx_loopback_mode loopback_mode; +@@ -834,6 +838,7 @@ static inline unsigned int efx_port_num( + * @remove_port: Free resources allocated by probe_port() + * @handle_global_event: Handle a "global" event (may be %NULL) + * @prepare_flush: Prepare the hardware for flushing the DMA queues ++ * @finish_flush: Clean up after flushing the DMA queues + * @update_stats: Update statistics not provided by event handling + * @start_stats: Start the regular fetching of statistics + * @stop_stats: Stop the regular fetching of statistics +@@ -879,6 +884,7 @@ struct efx_nic_type { + void (*remove_port)(struct efx_nic *efx); + bool (*handle_global_event)(struct efx_channel *channel, efx_qword_t *); + void (*prepare_flush)(struct efx_nic *efx); ++ void (*finish_flush)(struct efx_nic *efx); + void (*update_stats)(struct efx_nic *efx); + void (*start_stats)(struct efx_nic *efx); + void (*stop_stats)(struct efx_nic *efx); +--- a/drivers/net/sfc/nic.c ++++ b/drivers/net/sfc/nic.c +@@ -1260,13 +1260,27 @@ int efx_nic_flush_queues(struct efx_nic + } + efx_for_each_possible_channel_tx_queue(tx_queue, channel) { + if (tx_queue->initialised && +- tx_queue->flushed != FLUSH_DONE) +- ++tx_pending; ++ tx_queue->flushed != FLUSH_DONE) { ++ efx_oword_t txd_ptr_tbl; ++ ++ efx_reado_table(efx, &txd_ptr_tbl, ++ FR_BZ_TX_DESC_PTR_TBL, ++ tx_queue->queue); ++ if (EFX_OWORD_FIELD(txd_ptr_tbl, ++ FRF_AZ_TX_DESCQ_FLUSH) || ++ EFX_OWORD_FIELD(txd_ptr_tbl, ++ FRF_AZ_TX_DESCQ_EN)) ++ ++tx_pending; ++ else ++ tx_queue->flushed = FLUSH_DONE; ++ } + } + } + +- if (rx_pending == 0 && tx_pending == 0) ++ if (rx_pending == 0 && tx_pending == 0) { ++ efx->type->finish_flush(efx); + return 0; ++ } + + msleep(EFX_FLUSH_INTERVAL); + efx_poll_flush_events(efx); +@@ -1292,6 +1306,7 @@ int efx_nic_flush_queues(struct efx_nic + } + } + ++ efx->type->finish_flush(efx); + return -ETIMEDOUT; + } + +--- a/drivers/net/sfc/nic.h ++++ b/drivers/net/sfc/nic.h +@@ -211,6 +211,8 @@ extern void falcon_irq_ack_a1(struct efx + + /* Global Resources */ + extern int efx_nic_flush_queues(struct efx_nic *efx); ++extern void siena_prepare_flush(struct efx_nic *efx); ++extern void siena_finish_flush(struct efx_nic *efx); + extern void falcon_start_nic_stats(struct efx_nic *efx); + extern void falcon_stop_nic_stats(struct efx_nic *efx); + extern void falcon_setup_xaui(struct efx_nic *efx); +--- a/drivers/net/sfc/siena.c ++++ b/drivers/net/sfc/siena.c +@@ -135,6 +135,18 @@ static void siena_remove_port(struct efx + efx_nic_free_buffer(efx, &efx->stats_buffer); + } + ++void siena_prepare_flush(struct efx_nic *efx) ++{ ++ if (efx->fc_disable++ == 0) ++ efx_mcdi_set_mac(efx); ++} ++ ++void siena_finish_flush(struct efx_nic *efx) ++{ ++ if (--efx->fc_disable == 0) ++ efx_mcdi_set_mac(efx); ++} ++ + static const struct efx_nic_register_test siena_register_tests[] = { + { FR_AZ_ADR_REGION, + EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) }, +@@ -590,7 +602,8 @@ const struct efx_nic_type siena_a0_nic_t + .reset = siena_reset_hw, + .probe_port = siena_probe_port, + .remove_port = siena_remove_port, +- .prepare_flush = efx_port_dummy_op_void, ++ .prepare_flush = siena_prepare_flush, ++ .finish_flush = siena_finish_flush, + .update_stats = siena_update_nic_stats, + .start_stats = siena_start_nic_stats, + .stop_stats = siena_stop_nic_stats, diff --git a/queue-3.0/sfc-lock-tx-queues-when-calling-netif_device_detach.patch b/queue-3.0/sfc-lock-tx-queues-when-calling-netif_device_detach.patch new file mode 100644 index 00000000000..2e185b8d299 --- /dev/null +++ b/queue-3.0/sfc-lock-tx-queues-when-calling-netif_device_detach.patch @@ -0,0 +1,73 @@ +From 10da6986dd9307f9e0bdfa68204ae00650936bbb Mon Sep 17 00:00:00 2001 +From: Daniel Pieczko +Date: Wed, 17 Oct 2012 13:21:23 +0100 +Subject: sfc: lock TX queues when calling netif_device_detach() + + +From: Daniel Pieczko + +[ Upstream commit c2f3b8e3a44b6fe9e36704e30157ebe1a88c08b1 ] + +The assertion of netif_device_present() at the top of +efx_hard_start_xmit() may fail if we don't do this. + +Signed-off-by: Ben Hutchings +[bwh: Backported to 3.0: adjust context] +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/efx.c | 4 ++-- + drivers/net/sfc/efx.h | 13 +++++++++++++ + drivers/net/sfc/selftest.c | 2 +- + 3 files changed, 16 insertions(+), 3 deletions(-) + +--- a/drivers/net/sfc/efx.c ++++ b/drivers/net/sfc/efx.c +@@ -2106,7 +2106,7 @@ int efx_reset(struct efx_nic *efx, enum + netif_info(efx, drv, efx->net_dev, "resetting (%s)\n", + RESET_TYPE(method)); + +- netif_device_detach(efx->net_dev); ++ efx_device_detach_sync(efx); + efx_reset_down(efx, method); + + rc = efx->type->reset(efx, method); +@@ -2565,7 +2565,7 @@ static int efx_pm_freeze(struct device * + + efx->state = STATE_FINI; + +- netif_device_detach(efx->net_dev); ++ efx_device_detach_sync(efx); + + efx_stop_all(efx); + efx_fini_channels(efx); +--- a/drivers/net/sfc/efx.h ++++ b/drivers/net/sfc/efx.h +@@ -150,4 +150,17 @@ extern void efx_link_status_changed(stru + extern void efx_link_set_advertising(struct efx_nic *efx, u32); + extern void efx_link_set_wanted_fc(struct efx_nic *efx, u8); + ++static inline void efx_device_detach_sync(struct efx_nic *efx) ++{ ++ struct net_device *dev = efx->net_dev; ++ ++ /* Lock/freeze all TX queues so that we can be sure the ++ * TX scheduler is stopped when we're done and before ++ * netif_device_present() becomes false. ++ */ ++ netif_tx_lock(dev); ++ netif_device_detach(dev); ++ netif_tx_unlock(dev); ++} ++ + #endif /* EFX_EFX_H */ +--- a/drivers/net/sfc/selftest.c ++++ b/drivers/net/sfc/selftest.c +@@ -698,7 +698,7 @@ int efx_selftest(struct efx_nic *efx, st + /* Detach the device so the kernel doesn't transmit during the + * loopback test and the watchdog timeout doesn't fire. + */ +- netif_device_detach(efx->net_dev); ++ efx_device_detach_sync(efx); + + mutex_lock(&efx->mac_lock); + if (efx->loopback_modes) { diff --git a/queue-3.0/sfc-only-use-tx-push-if-a-single-descriptor-is-to-be-written.patch b/queue-3.0/sfc-only-use-tx-push-if-a-single-descriptor-is-to-be-written.patch new file mode 100644 index 00000000000..3f10f947fee --- /dev/null +++ b/queue-3.0/sfc-only-use-tx-push-if-a-single-descriptor-is-to-be-written.patch @@ -0,0 +1,37 @@ +From fde2b4efe81bc60bfe85638284817fb4e9a0ad59 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Wed, 27 Feb 2013 16:50:38 +0000 +Subject: sfc: Only use TX push if a single descriptor is to be written + + +From: Ben Hutchings + +[ Upstream commit fae8563b25f73dc584a07bcda7a82750ff4f7672 ] + +Using TX push when notifying the NIC of multiple new descriptors in +the ring will very occasionally cause the TX DMA engine to re-use an +old descriptor. This can result in a duplicated or partly duplicated +packet (new headers with old data), or an IOMMU page fault. This does +not happen when the pushed descriptor is the only one written. + +TX push also provides little latency benefit when a packet requires +more than one descriptor. + +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/nic.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/sfc/nic.c ++++ b/drivers/net/sfc/nic.c +@@ -370,7 +370,8 @@ efx_may_push_tx_desc(struct efx_tx_queue + return false; + + tx_queue->empty_read_count = 0; +- return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0; ++ return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0 ++ && tx_queue->write_count - write_count == 1; + } + + /* For each entry inserted into the software descriptor ring, create a diff --git a/queue-3.0/sfc-properly-sync-rx-dma-buffer-when-it-is-not-the-last-in-the-page.patch b/queue-3.0/sfc-properly-sync-rx-dma-buffer-when-it-is-not-the-last-in-the-page.patch new file mode 100644 index 00000000000..d9dd494f278 --- /dev/null +++ b/queue-3.0/sfc-properly-sync-rx-dma-buffer-when-it-is-not-the-last-in-the-page.patch @@ -0,0 +1,71 @@ +From 58f74c7701b81362e5eb2552f6e37cfa1e9a2437 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Thu, 20 Dec 2012 18:48:20 +0000 +Subject: sfc: Properly sync RX DMA buffer when it is not the last in the page + + +From: Ben Hutchings + +[ Upstream commit 3a68f19d7afb80f548d016effbc6ed52643a8085 ] + +We may currently allocate two RX DMA buffers to a page, and only unmap +the page when the second is completed. We do not sync the first RX +buffer to be completed; this can result in packet loss or corruption +if the last RX buffer completed in a NAPI poll is the first in a page +and is not DMA-coherent. (In the middle of a NAPI poll, we will +handle the following RX completion and unmap the page *before* looking +at the content of the first buffer.) + +Signed-off-by: Ben Hutchings +[bwh: Backported to 3.0: adjust context] +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/sfc/rx.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +--- a/drivers/net/sfc/rx.c ++++ b/drivers/net/sfc/rx.c +@@ -245,7 +245,8 @@ static int efx_init_rx_buffers_page(stru + } + + static void efx_unmap_rx_buffer(struct efx_nic *efx, +- struct efx_rx_buffer *rx_buf) ++ struct efx_rx_buffer *rx_buf, ++ unsigned int used_len) + { + if (rx_buf->is_page && rx_buf->u.page) { + struct efx_rx_page_state *state; +@@ -256,6 +257,10 @@ static void efx_unmap_rx_buffer(struct e + state->dma_addr, + efx_rx_buf_size(efx), + PCI_DMA_FROMDEVICE); ++ } else if (used_len) { ++ dma_sync_single_for_cpu(&efx->pci_dev->dev, ++ rx_buf->dma_addr, used_len, ++ DMA_FROM_DEVICE); + } + } else if (!rx_buf->is_page && rx_buf->u.skb) { + pci_unmap_single(efx->pci_dev, rx_buf->dma_addr, +@@ -278,7 +283,7 @@ static void efx_free_rx_buffer(struct ef + static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue, + struct efx_rx_buffer *rx_buf) + { +- efx_unmap_rx_buffer(rx_queue->efx, rx_buf); ++ efx_unmap_rx_buffer(rx_queue->efx, rx_buf, 0); + efx_free_rx_buffer(rx_queue->efx, rx_buf); + } + +@@ -549,10 +554,10 @@ void efx_rx_packet(struct efx_rx_queue * + goto out; + } + +- /* Release card resources - assumes all RX buffers consumed in-order +- * per RX queue ++ /* Release and/or sync DMA mapping - assumes all RX buffers ++ * consumed in-order per RX queue + */ +- efx_unmap_rx_buffer(efx, rx_buf); ++ efx_unmap_rx_buffer(efx, rx_buf, len); + + /* Prefetch nice and early so data will (hopefully) be in cache by + * the time we look at it.