From f01b3926ee645974f549f4a6921268142047717c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sun, 8 Dec 2013 16:52:31 +0000 Subject: [PATCH 01/20] netfilter: SYNPROXY target: restrict to INPUT/FORWARD Fix a crash in synproxy_send_tcp() when using the SYNPROXY target in the PREROUTING chain caused by missing routing information. Reported-by: Nicki P. Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/ipt_SYNPROXY.c | 1 + net/ipv6/netfilter/ip6t_SYNPROXY.c | 1 + 2 files changed, 2 insertions(+) diff --git a/net/ipv4/netfilter/ipt_SYNPROXY.c b/net/ipv4/netfilter/ipt_SYNPROXY.c index f13bd91d9a56..a313c3fbeb46 100644 --- a/net/ipv4/netfilter/ipt_SYNPROXY.c +++ b/net/ipv4/netfilter/ipt_SYNPROXY.c @@ -423,6 +423,7 @@ static void synproxy_tg4_destroy(const struct xt_tgdtor_param *par) static struct xt_target synproxy_tg4_reg __read_mostly = { .name = "SYNPROXY", .family = NFPROTO_IPV4, + .hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD), .target = synproxy_tg4, .targetsize = sizeof(struct xt_synproxy_info), .checkentry = synproxy_tg4_check, diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c index f78f41aca8e9..a0d17270117c 100644 --- a/net/ipv6/netfilter/ip6t_SYNPROXY.c +++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c @@ -446,6 +446,7 @@ static void synproxy_tg6_destroy(const struct xt_tgdtor_param *par) static struct xt_target synproxy_tg6_reg __read_mostly = { .name = "SYNPROXY", .family = NFPROTO_IPV6, + .hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD), .target = synproxy_tg6, .targetsize = sizeof(struct xt_synproxy_info), .checkentry = synproxy_tg6_check, From a3adadf3018102c24754e0b53a5515c40fbaff4a Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 12 Dec 2013 08:51:59 +0100 Subject: [PATCH 02/20] netfilter: nft_reject: fix endianness in dump function The dump function in nft_reject_ipv4 was not converting a u32 field to network order before sending it to userspace, this needs to happen for consistency with other nf_tables and nfnetlink subsystems. Signed-off-by: Eric Leblond Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/nft_reject_ipv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/netfilter/nft_reject_ipv4.c b/net/ipv4/netfilter/nft_reject_ipv4.c index fff5ba1a33b7..4a5e94ac314a 100644 --- a/net/ipv4/netfilter/nft_reject_ipv4.c +++ b/net/ipv4/netfilter/nft_reject_ipv4.c @@ -72,7 +72,7 @@ static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr) { const struct nft_reject *priv = nft_expr_priv(expr); - if (nla_put_be32(skb, NFTA_REJECT_TYPE, priv->type)) + if (nla_put_be32(skb, NFTA_REJECT_TYPE, htonl(priv->type))) goto nla_put_failure; switch (priv->type) { From 9bd7d20c45157c175bfd45449e904a404506f99c Mon Sep 17 00:00:00 2001 From: wangweidong Date: Fri, 13 Dec 2013 11:00:10 +0800 Subject: [PATCH 03/20] sctp: loading sctp when load sctp_probe when I modprobe sctp_probe, it failed with "FATAL: ". I found that sctp should load before sctp_probe register jprobe. So I add a sctp_setup_jprobe for loading 'sctp' when first failed to register jprobe, just do this similar to dccp_probe. v2: add MODULE_SOFTDEP and check of request_module, as suggested by Neil Signed-off-by: Wang Weidong Acked-by: Neil Horman Signed-off-by: David S. Miller --- net/sctp/probe.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/net/sctp/probe.c b/net/sctp/probe.c index 53c452efb40b..5e68b94ee640 100644 --- a/net/sctp/probe.c +++ b/net/sctp/probe.c @@ -38,6 +38,7 @@ #include #include +MODULE_SOFTDEP("pre: sctp"); MODULE_AUTHOR("Wei Yongjun "); MODULE_DESCRIPTION("SCTP snooper"); MODULE_LICENSE("GPL"); @@ -182,6 +183,20 @@ static struct jprobe sctp_recv_probe = { .entry = jsctp_sf_eat_sack, }; +static __init int sctp_setup_jprobe(void) +{ + int ret = register_jprobe(&sctp_recv_probe); + + if (ret) { + if (request_module("sctp")) + goto out; + ret = register_jprobe(&sctp_recv_probe); + } + +out: + return ret; +} + static __init int sctpprobe_init(void) { int ret = -ENOMEM; @@ -202,7 +217,7 @@ static __init int sctpprobe_init(void) &sctpprobe_fops)) goto free_kfifo; - ret = register_jprobe(&sctp_recv_probe); + ret = sctp_setup_jprobe(); if (ret) goto remove_proc; From a1c31f1d057130cc63e72a09189410d169db7ecf Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 7 Dec 2013 03:10:35 +0400 Subject: [PATCH 04/20] can: ems_usb: fix urb leaks on failure paths There are a couple failure paths where urb leaks. Is spare code within ems_usb_start_xmit(), usb_free_urb() should be used to deallocate urb instead of usb_unanchor_urb(). In ems_usb_start() there is no usb_free_urb() if usb_submit_urb() fails. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: Sebastian Haas Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/ems_usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 5f9a7ad9b964..8aeec0b4601a 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -625,6 +625,7 @@ static int ems_usb_start(struct ems_usb *dev) usb_unanchor_urb(urb); usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf, urb->transfer_dma); + usb_free_urb(urb); break; } @@ -798,8 +799,8 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne * allowed (MAX_TX_URBS). */ if (!context) { - usb_unanchor_urb(urb); usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); + usb_free_urb(urb); netdev_warn(netdev, "couldn't find free context\n"); From 20fb4eb96fb0350d28fc4d7cbfd5506711079592 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sat, 14 Dec 2013 14:36:25 +0100 Subject: [PATCH 05/20] can: peak_usb: fix mem leak in pcan_usb_pro_init() This patch fixes a memory leak in pcan_usb_pro_init(). In patch f14e224 net: can: peak_usb: Do not do dma on the stack the struct pcan_usb_pro_fwinfo *fi and struct pcan_usb_pro_blinfo *bi were converted from stack to dynamic allocation va kmalloc(). However the corresponding kfree() was not introduced. This patch adds the missing kfree(). Cc: linux-stable # v3.10 Reported-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 8ee9d1556e6e..263dd921edc4 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -927,6 +927,9 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev) /* set LED in default state (end of init phase) */ pcan_usb_pro_set_led(dev, 0, 1); + kfree(bi); + kfree(fi); + return 0; err_out: From 50dc875f2e6e2e04aed3b3033eb0ac99192d6d02 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 13 Dec 2013 17:21:27 +0800 Subject: [PATCH 06/20] netvsc: don't flush peers notifying work during setting mtu There's a possible deadlock if we flush the peers notifying work during setting mtu: [ 22.991149] ====================================================== [ 22.991173] [ INFO: possible circular locking dependency detected ] [ 22.991198] 3.10.0-54.0.1.el7.x86_64.debug #1 Not tainted [ 22.991219] ------------------------------------------------------- [ 22.991243] ip/974 is trying to acquire lock: [ 22.991261] ((&(&net_device_ctx->dwork)->work)){+.+.+.}, at: [] flush_work+0x5/0x2e0 [ 22.991307] but task is already holding lock: [ 22.991330] (rtnl_mutex){+.+.+.}, at: [] rtnetlink_rcv+0x1b/0x40 [ 22.991367] which lock already depends on the new lock. [ 22.991398] the existing dependency chain (in reverse order) is: [ 22.991426] -> #1 (rtnl_mutex){+.+.+.}: [ 22.991449] [] __lock_acquire+0xb19/0x1260 [ 22.991477] [] lock_acquire+0xa2/0x1f0 [ 22.991501] [] mutex_lock_nested+0x89/0x4f0 [ 22.991529] [] rtnl_lock+0x17/0x20 [ 22.991552] [] netdev_notify_peers+0x12/0x30 [ 22.991579] [] netvsc_send_garp+0x22/0x30 [hv_netvsc] [ 22.991610] [] process_one_work+0x211/0x6e0 [ 22.991637] [] worker_thread+0x11b/0x3a0 [ 22.991663] [] kthread+0xed/0x100 [ 22.991686] [] ret_from_fork+0x7c/0xb0 [ 22.991715] -> #0 ((&(&net_device_ctx->dwork)->work)){+.+.+.}: [ 22.991715] [] check_prevs_add+0x967/0x970 [ 22.991715] [] __lock_acquire+0xb19/0x1260 [ 22.991715] [] lock_acquire+0xa2/0x1f0 [ 22.991715] [] flush_work+0x4e/0x2e0 [ 22.991715] [] __cancel_work_timer+0x95/0x130 [ 22.991715] [] cancel_delayed_work_sync+0x13/0x20 [ 22.991715] [] netvsc_change_mtu+0x84/0x200 [hv_netvsc] [ 22.991715] [] dev_set_mtu+0x34/0x80 [ 22.991715] [] do_setlink+0x23a/0xa00 [ 22.991715] [] rtnl_newlink+0x394/0x5e0 [ 22.991715] [] rtnetlink_rcv_msg+0x9c/0x260 [ 22.991715] [] netlink_rcv_skb+0xa9/0xc0 [ 22.991715] [] rtnetlink_rcv+0x2a/0x40 [ 22.991715] [] netlink_unicast+0xdd/0x190 [ 22.991715] [] netlink_sendmsg+0x337/0x750 [ 22.991715] [] sock_sendmsg+0x99/0xd0 [ 22.991715] [] ___sys_sendmsg+0x39e/0x3b0 [ 22.991715] [] __sys_sendmsg+0x42/0x80 [ 22.991715] [] SyS_sendmsg+0x12/0x20 [ 22.991715] [] system_call_fastpath+0x16/0x1b This is because we hold the rtnl_lock() before ndo_change_mtu() and try to flush the work in netvsc_change_mtu(), in the mean time, netdev_notify_peers() may be called from worker and also trying to hold the rtnl_lock. This will lead the flush won't succeed forever. Solve this by not canceling and flushing the work, this is safe because the transmission done by NETDEV_NOTIFY_PEERS was synchronized with the netif_tx_disable() called by netvsc_change_mtu(). Reported-by: Yaju Cao Tested-by: Yaju Cao Cc: K. Y. Srinivasan Cc: Haiyang Zhang Signed-off-by: Jason Wang Acked-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 524f713f6017..f8135725bcf6 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -327,7 +327,6 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) return -EINVAL; nvdev->start_remove = true; - cancel_delayed_work_sync(&ndevctx->dwork); cancel_work_sync(&ndevctx->work); netif_tx_disable(ndev); rndis_filter_device_remove(hdev); From e47eb5dfb296bf217e9ebee7b2f07486670b9c1b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 15 Dec 2013 10:53:46 -0800 Subject: [PATCH 07/20] udp: ipv4: do not use sk_dst_lock from softirq context Using sk_dst_lock from softirq context is not supported right now. Instead of adding BH protection everywhere, udp_sk_rx_dst_set() can instead use xchg(), as suggested by David. Reported-by: Fengguang Wu Fixes: 975022310233 ("udp: ipv4: must add synchronization in udp_sk_rx_dst_set()") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/udp.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 62c19fdd102d..f140048334ce 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1600,20 +1600,15 @@ static void flush_stack(struct sock **stack, unsigned int count, } /* For TCP sockets, sk_rx_dst is protected by socket lock - * For UDP, we use sk_dst_lock to guard against concurrent changes. + * For UDP, we use xchg() to guard against concurrent changes. */ static void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst) { struct dst_entry *old; - spin_lock(&sk->sk_dst_lock); - old = sk->sk_rx_dst; - if (likely(old != dst)) { - dst_hold(dst); - sk->sk_rx_dst = dst; - dst_release(old); - } - spin_unlock(&sk->sk_dst_lock); + dst_hold(dst); + old = xchg(&sk->sk_rx_dst, dst); + dst_release(old); } /* From d1fc50247693bf9116184c19ca16386ff14f5aed Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 13 Dec 2013 12:56:05 +0100 Subject: [PATCH 08/20] MAINTAINERS: Update the IPsec maintainer entry Add the IPsec git trees and some pure IPsec modules to the IPsec section in the MAINTAINERS file. Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller --- MAINTAINERS | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1344816c4c06..b8af16d5cf63 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5911,12 +5911,21 @@ M: Steffen Klassert M: Herbert Xu M: "David S. Miller" L: netdev@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git S: Maintained F: net/xfrm/ F: net/key/ F: net/ipv4/xfrm* +F: net/ipv4/esp4.c +F: net/ipv4/ah4.c +F: net/ipv4/ipcomp.c +F: net/ipv4/ip_vti.c F: net/ipv6/xfrm* +F: net/ipv6/esp6.c +F: net/ipv6/ah6.c +F: net/ipv6/ipcomp6.c +F: net/ipv6/ip6_vti.c F: include/uapi/linux/xfrm.h F: include/net/xfrm.h From 37ab4fa7844a044dc21fde45e2a0fc2f3c3b6490 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 13 Dec 2013 10:54:22 -0500 Subject: [PATCH 09/20] net: unix: allow bind to fail on mutex lock This is similar to the set_peek_off patch where calling bind while the socket is stuck in unix_dgram_recvmsg() will block and cause a hung task spew after a while. This is also the last place that did a straightforward mutex_lock(), so there shouldn't be any more of these patches. Signed-off-by: Sasha Levin Signed-off-by: David S. Miller --- net/unix/af_unix.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index a0ca162e5bd5..a427623ee574 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -718,7 +718,9 @@ static int unix_autobind(struct socket *sock) int err; unsigned int retries = 0; - mutex_lock(&u->readlock); + err = mutex_lock_interruptible(&u->readlock); + if (err) + return err; err = 0; if (u->addr) @@ -877,7 +879,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) goto out; addr_len = err; - mutex_lock(&u->readlock); + err = mutex_lock_interruptible(&u->readlock); + if (err) + goto out; err = -EINVAL; if (u->addr) From 188b04d580ab7acf11eb77cb564692050c10edfe Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Sat, 14 Dec 2013 04:42:13 +0100 Subject: [PATCH 10/20] ipv4: improve documentation of ip_no_pmtu_disc Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 3c12d9a7ed00..8a984e994e61 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -16,8 +16,12 @@ ip_default_ttl - INTEGER Default: 64 (as recommended by RFC1700) ip_no_pmtu_disc - BOOLEAN - Disable Path MTU Discovery. - default FALSE + Disable Path MTU Discovery. If enabled and a + fragmentation-required ICMP is received, the PMTU to this + destination will be set to min_pmtu (see below). You will need + to raise min_pmtu to the smallest interface MTU on your system + manually if you want to avoid locally generated fragments. + Default: FALSE min_pmtu - INTEGER default 552 - minimum discovered Path MTU From 53385d2d1de84f4036a0919ec46964c4e81b83f5 Mon Sep 17 00:00:00 2001 From: Bob Gilligan Date: Sun, 15 Dec 2013 13:39:56 -0800 Subject: [PATCH 11/20] neigh: Netlink notification for administrative NUD state change The neighbour code sends up an RTM_NEWNEIGH netlink notification if the NUD state of a neighbour cache entry is changed by a timer (e.g. from REACHABLE to STALE), even if the lladdr of the entry has not changed. But an administrative change to the the NUD state of a neighbour cache entry that does not change the lladdr (e.g. via "ip -4 neigh change ... nud ...") does not trigger a netlink notification. This means that netlink listeners will not hear about administrative NUD state changes such as from a resolved state to PERMANENT. This patch changes the neighbor code to generate an RTM_NEWNEIGH message when the NUD state of an entry is changed administratively. Signed-off-by: Bob Gilligan Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/neighbour.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index ca15f32821fb..36b1443f9ae4 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1161,6 +1161,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, neigh->parms->reachable_time : 0))); neigh->nud_state = new; + notify = 1; } if (lladdr != neigh->ha) { From 7022ef8b2a673db3d12a348331181f579afe9b22 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 16 Dec 2013 10:45:05 +0800 Subject: [PATCH 12/20] xen-netback: fix fragments error handling in checksum_setup_ip() Fix to return -EPROTO error if fragments detected in checksum_setup_ip(). Fixes: 1431fb31ecba ('xen-netback: fix fragment detection in checksum setup') Signed-off-by: Wei Yongjun Reviewed-by: Paul Durrant Acked-by: Ian Campbell Signed-off-by: David S. Miller --- drivers/net/xen-netback/netback.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index e884ee1fe7ed..27bbe58dcbe7 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1197,6 +1197,9 @@ static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb, err = -EPROTO; + if (fragment) + goto out; + switch (ip_hdr(skb)->protocol) { case IPPROTO_TCP: err = maybe_pull_tail(skb, From b84caae486135d588fb200973b0be8cb8a511edf Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Mon, 16 Dec 2013 15:36:56 -0500 Subject: [PATCH 13/20] qlcnic: Fix usage of netif_tx_{wake, stop} api during link change. o Driver was using netif_tx_{stop,wake}_all_queues() api during link change event. Remove these api calls to manage queue start/stop event, as core networking stack will manage this based on netif_carrier_{on,off} call. These API's were modified as part of commit id 012ec81223aa45d2b80aeafb77392fd1a19c7b10 ("qlcnic: Multi Tx queue support for 82xx Series adapter.") Signed-off-by: Shahed Shaikh Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 0149c9495347..eda6c691d897 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -687,17 +687,11 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup) if (adapter->ahw->linkup && !linkup) { netdev_info(netdev, "NIC Link is down\n"); adapter->ahw->linkup = 0; - if (netif_running(netdev)) { - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - } + netif_carrier_off(netdev); } else if (!adapter->ahw->linkup && linkup) { netdev_info(netdev, "NIC Link is up\n"); adapter->ahw->linkup = 1; - if (netif_running(netdev)) { - netif_carrier_on(netdev); - netif_wake_queue(netdev); - } + netif_carrier_on(netdev); } } From 3bf517df0d99f1cf5d369c73ab68e0afe6a3c2f9 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Mon, 16 Dec 2013 15:36:57 -0500 Subject: [PATCH 14/20] qlcnic: Fix diagnostic test for all adapters. o Driver should re-allocate all Tx queues after completing diagnostic tests. This regression was added by commit id c2c5e3a0681bb1945c0cb211a5f4baa22cb2cbb3 ("qlcnic: Enable diagnostic test for multiple Tx queues.") Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 2 ++ drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index b36c02fafcfd..6d3edf6b6a96 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -948,6 +948,7 @@ static int qlcnic_irq_test(struct net_device *netdev) struct qlcnic_hardware_context *ahw = adapter->ahw; struct qlcnic_cmd_args cmd; int ret, drv_sds_rings = adapter->drv_sds_rings; + int drv_tx_rings = adapter->drv_tx_rings; if (qlcnic_83xx_check(adapter)) return qlcnic_83xx_interrupt_test(netdev); @@ -980,6 +981,7 @@ static int qlcnic_irq_test(struct net_device *netdev) clear_diag_irq: adapter->drv_sds_rings = drv_sds_rings; + adapter->drv_tx_rings = drv_tx_rings; clear_bit(__QLCNIC_RESETTING, &adapter->state); return ret; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 05c1eef8df13..aa019c398e9b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -1940,7 +1940,6 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) qlcnic_detach(adapter); adapter->drv_sds_rings = QLCNIC_SINGLE_RING; - adapter->drv_tx_rings = QLCNIC_SINGLE_RING; adapter->ahw->diag_test = test; adapter->ahw->linkup = 0; From f9566265d7b44fea789072dcfa9a454e7e433af6 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Mon, 16 Dec 2013 15:36:58 -0500 Subject: [PATCH 15/20] qlcnic: Fix TSS/RSS ring validation logic. o TSS/RSS ring validation does not take into account that either of these ring values can be 0. This patch fixes this validation and would fail set_channel operation if any of these ring value is 0. This regression was added as part of commit id 34e8c406fda5b5a9d2e126a92bab84cd28e3b5fa ("qlcnic: refactor Tx/SDS ring calculation and validation in driver.") Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 4 ++-- drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 6 +++++- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 89208e5b25d6..fae1b7171576 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2073,8 +2073,8 @@ int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) ahw->nic_mode = QLCNIC_DEFAULT_MODE; adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver; ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; - adapter->max_sds_rings = ahw->max_rx_ques; - adapter->max_tx_rings = ahw->max_tx_ques; + adapter->max_sds_rings = QLCNIC_MAX_SDS_RINGS; + adapter->max_tx_rings = QLCNIC_MAX_TX_RINGS; } else { return -EIO; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 6d3edf6b6a96..78f5e815139e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -667,9 +667,13 @@ qlcnic_set_ringparam(struct net_device *dev, static int qlcnic_validate_ring_count(struct qlcnic_adapter *adapter, u8 rx_ring, u8 tx_ring) { + if (rx_ring == 0 || tx_ring == 0) + return -EINVAL; + if (rx_ring != 0) { if (rx_ring > adapter->max_sds_rings) { - netdev_err(adapter->netdev, "Invalid ring count, SDS ring count %d should not be greater than max %d driver sds rings.\n", + netdev_err(adapter->netdev, + "Invalid ring count, SDS ring count %d should not be greater than max %d driver sds rings.\n", rx_ring, adapter->max_sds_rings); return -EINVAL; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index aa019c398e9b..2c8cac0c6a55 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -1178,6 +1178,7 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter) } else { adapter->ahw->nic_mode = QLCNIC_DEFAULT_MODE; adapter->max_tx_rings = QLCNIC_MAX_HW_TX_RINGS; + adapter->max_sds_rings = QLCNIC_MAX_SDS_RINGS; adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; } From b17a44d8b86f48e34011b884a934231ae2928d66 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Mon, 16 Dec 2013 15:36:59 -0500 Subject: [PATCH 16/20] qlcnic: Fix TSS/RSS validation for 83xx/84xx series adapter. o Current code was not allowing the user to configure more than one Tx ring using ethtool for 83xx/84xx adapter. This regression was introduced by commit id 18afc102fdcb95d6c7d57f2967a06f2f8fe3ba4c ("qlcnic: Enable multiple Tx queue support for 83xx/84xx Series adapter.") Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 78f5e815139e..e3be2760665c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -680,21 +680,12 @@ static int qlcnic_validate_ring_count(struct qlcnic_adapter *adapter, } if (tx_ring != 0) { - if (qlcnic_82xx_check(adapter) && - (tx_ring > adapter->max_tx_rings)) { + if (tx_ring > adapter->max_tx_rings) { netdev_err(adapter->netdev, "Invalid ring count, Tx ring count %d should not be greater than max %d driver Tx rings.\n", tx_ring, adapter->max_tx_rings); return -EINVAL; } - - if (qlcnic_83xx_check(adapter) && - (tx_ring > QLCNIC_SINGLE_RING)) { - netdev_err(adapter->netdev, - "Invalid ring count, Tx ring count %d should not be greater than %d driver Tx rings.\n", - tx_ring, QLCNIC_SINGLE_RING); - return -EINVAL; - } } return 0; From 3fc38e267bfbea5e33e2222d6babc3b06c2bb642 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Mon, 16 Dec 2013 15:37:00 -0500 Subject: [PATCH 17/20] qlcnic: Fix memory allocation o Use vzalloc() instead of kzalloc() for allocation of bootloader size memory. kzalloc() may fail to allocate the size of bootloader Signed-off-by: Manish Chopra Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index fae1b7171576..cac0503bda31 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -1254,24 +1254,24 @@ static int qlcnic_83xx_copy_bootloader(struct qlcnic_adapter *adapter) if (size & 0xF) size = (size + 16) & ~0xF; - p_cache = kzalloc(size, GFP_KERNEL); + p_cache = vzalloc(size); if (p_cache == NULL) return -ENOMEM; ret = qlcnic_83xx_lockless_flash_read32(adapter, src, p_cache, size / sizeof(u32)); if (ret) { - kfree(p_cache); + vfree(p_cache); return ret; } /* 16 byte write to MS memory */ ret = qlcnic_83xx_ms_mem_write128(adapter, dest, (u32 *)p_cache, size / 16); if (ret) { - kfree(p_cache); + vfree(p_cache); return ret; } - kfree(p_cache); + vfree(p_cache); return ret; } From 30fa15f64e40c4cf037e3379e55c2323b5d992e2 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Mon, 16 Dec 2013 15:37:01 -0500 Subject: [PATCH 18/20] qlcnic: Allow firmware dump collection when auto firmware recovery is disabled o Allow driver to collect firmware dump, during a forced firmware dump operation, when auto firmware recovery is disabled. Also, during this operation, driver should not allow reset recovery to be performed. Signed-off-by: Manish Chopra Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller --- .../ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 1 + .../ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 55 ++++++++++++------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 4cae6caa6bfa..a6a33508e401 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -662,4 +662,5 @@ pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *, pci_channel_state_t); pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *); void qlcnic_83xx_io_resume(struct pci_dev *); +void qlcnic_83xx_stop_hw(struct qlcnic_adapter *); #endif diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index cac0503bda31..918e18ddf038 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -740,6 +740,7 @@ static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter) adapter->ahw->idc.err_code = -EIO; dev_err(&adapter->pdev->dev, "%s: Device in unknown state\n", __func__); + clear_bit(__QLCNIC_RESETTING, &adapter->state); return 0; } @@ -818,7 +819,6 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter) struct qlcnic_hardware_context *ahw = adapter->ahw; struct qlcnic_mailbox *mbx = ahw->mailbox; int ret = 0; - u32 owner; u32 val; /* Perform NIC configuration based ready state entry actions */ @@ -848,9 +848,9 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter) set_bit(__QLCNIC_RESETTING, &adapter->state); qlcnic_83xx_idc_enter_need_reset_state(adapter, 1); } else { - owner = qlcnic_83xx_idc_find_reset_owner_id(adapter); - if (ahw->pci_func == owner) - qlcnic_dump_fw(adapter); + netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n", + __func__); + qlcnic_83xx_idc_enter_failed_state(adapter, 1); } return -EIO; } @@ -948,13 +948,26 @@ static int qlcnic_83xx_idc_need_quiesce_state(struct qlcnic_adapter *adapter) return 0; } -static int qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter) +static void qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter) { - dev_err(&adapter->pdev->dev, "%s: please restart!!\n", __func__); - clear_bit(__QLCNIC_RESETTING, &adapter->state); - adapter->ahw->idc.err_code = -EIO; + struct qlcnic_hardware_context *ahw = adapter->ahw; + u32 val, owner; - return 0; + val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); + if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) { + owner = qlcnic_83xx_idc_find_reset_owner_id(adapter); + if (ahw->pci_func == owner) { + qlcnic_83xx_stop_hw(adapter); + qlcnic_dump_fw(adapter); + } + } + + netdev_warn(adapter->netdev, "%s: Reboot will be required to recover the adapter!!\n", + __func__); + clear_bit(__QLCNIC_RESETTING, &adapter->state); + ahw->idc.err_code = -EIO; + + return; } static int qlcnic_83xx_idc_quiesce_state(struct qlcnic_adapter *adapter) @@ -1063,12 +1076,6 @@ void qlcnic_83xx_idc_poll_dev_state(struct work_struct *work) adapter->ahw->idc.prev_state = adapter->ahw->idc.curr_state; qlcnic_83xx_periodic_tasks(adapter); - /* Do not reschedule if firmaware is in hanged state and auto - * recovery is disabled - */ - if ((adapter->flags & QLCNIC_FW_HANG) && !qlcnic_auto_fw_reset) - return; - /* Re-schedule the function */ if (test_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status)) qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state, @@ -1219,10 +1226,10 @@ void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *adapter, u32 key) } val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); - if ((val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) || - !qlcnic_auto_fw_reset) { - dev_err(&adapter->pdev->dev, - "%s:failed, device in non reset mode\n", __func__); + if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) { + netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n", + __func__); + qlcnic_83xx_idc_enter_failed_state(adapter, 0); qlcnic_83xx_unlock_driver(adapter); return; } @@ -1939,7 +1946,7 @@ static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev, p_dev->ahw->reset.seq_index = index; } -static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev) +void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev) { p_dev->ahw->reset.seq_index = 0; @@ -1994,6 +2001,14 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter) val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); if (!(val & QLC_83XX_IDC_GRACEFULL_RESET)) qlcnic_dump_fw(adapter); + + if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) { + netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n", + __func__); + qlcnic_83xx_idc_enter_failed_state(adapter, 1); + return err; + } + qlcnic_83xx_init_hw(adapter); if (qlcnic_83xx_copy_bootloader(adapter)) From e49df7947a48b04ee57ee0fa0c4110ef05024c4f Mon Sep 17 00:00:00 2001 From: Manish chopra Date: Mon, 16 Dec 2013 15:37:02 -0500 Subject: [PATCH 19/20] qlcnic: Fix mailbox processing during diagnostic test o Do not enable mailbox polling in case of legacy interrupt. Process mailbox AEN/response from the interrupt. Signed-off-by: Manish Chopra Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller --- .../ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 32 ++++--------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index b1cb0ffb15c7..ab66e7f3e01e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -447,8 +447,9 @@ irqreturn_t qlcnic_83xx_intr(int irq, void *data) qlcnic_83xx_poll_process_aen(adapter); - if (ahw->diag_test == QLCNIC_INTERRUPT_TEST) { - ahw->diag_cnt++; + if (ahw->diag_test) { + if (ahw->diag_test == QLCNIC_INTERRUPT_TEST) + ahw->diag_cnt++; qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter); return IRQ_HANDLED; } @@ -1345,11 +1346,6 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test, } if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { - /* disable and free mailbox interrupt */ - if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { - qlcnic_83xx_enable_mbx_poll(adapter); - qlcnic_83xx_free_mbx_intr(adapter); - } adapter->ahw->loopback_state = 0; adapter->ahw->hw_ops->setup_link_event(adapter, 1); } @@ -1363,33 +1359,20 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev, { struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_host_sds_ring *sds_ring; - int ring, err; + int ring; clear_bit(__QLCNIC_DEV_UP, &adapter->state); if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &adapter->recv_ctx->sds_rings[ring]; - qlcnic_83xx_disable_intr(adapter, sds_ring); - if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) - qlcnic_83xx_enable_mbx_poll(adapter); + if (adapter->flags & QLCNIC_MSIX_ENABLED) + qlcnic_83xx_disable_intr(adapter, sds_ring); } } qlcnic_fw_destroy_ctx(adapter); qlcnic_detach(adapter); - if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) { - if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { - err = qlcnic_83xx_setup_mbx_intr(adapter); - qlcnic_83xx_disable_mbx_poll(adapter); - if (err) { - dev_err(&adapter->pdev->dev, - "%s: failed to setup mbx interrupt\n", - __func__); - goto out; - } - } - } adapter->ahw->diag_test = 0; adapter->drv_sds_rings = drv_sds_rings; @@ -1399,9 +1382,6 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev, if (netif_running(netdev)) __qlcnic_up(adapter, netdev); - if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST && - !(adapter->flags & QLCNIC_MSIX_ENABLED)) - qlcnic_83xx_disable_mbx_poll(adapter); out: netif_device_attach(netdev); } From 0951c5c214e525185572204b587e3b6762d121f4 Mon Sep 17 00:00:00 2001 From: Manish chopra Date: Mon, 16 Dec 2013 15:37:03 -0500 Subject: [PATCH 20/20] qlcnic: Dump mailbox registers when mailbox command times out. Signed-off-by: Manish Chopra Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller --- .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index ab66e7f3e01e..6055d397a29e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -3734,6 +3734,19 @@ static void qlcnic_83xx_decode_mbx_rsp(struct qlcnic_adapter *adapter, return; } +static inline void qlcnic_dump_mailbox_registers(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + u32 offset; + + offset = QLCRDX(ahw, QLCNIC_DEF_INT_MASK); + dev_info(&adapter->pdev->dev, "Mbx interrupt mask=0x%x, Mbx interrupt enable=0x%x, Host mbx control=0x%x, Fw mbx control=0x%x", + readl(ahw->pci_base0 + offset), + QLCRDX(ahw, QLCNIC_MBX_INTR_ENBL), + QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL), + QLCRDX(ahw, QLCNIC_FW_MBX_CTRL)); +} + static void qlcnic_83xx_mailbox_worker(struct work_struct *work) { struct qlcnic_mailbox *mbx = container_of(work, struct qlcnic_mailbox, @@ -3778,6 +3791,8 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work) __func__, cmd->cmd_op, cmd->type, ahw->pci_func, ahw->op_mode); clear_bit(QLC_83XX_MBX_READY, &mbx->status); + qlcnic_dump_mailbox_registers(adapter); + qlcnic_83xx_get_mbx_data(adapter, cmd); qlcnic_dump_mbx(adapter, cmd); qlcnic_83xx_idc_request_reset(adapter, QLCNIC_FORCE_FW_DUMP_KEY);