From 17b14ca25e9cd6c5cd7605941f6120e405a84f8b Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Mon, 19 Nov 2012 15:37:46 +0100 Subject: netfilter: ipset: Fix range bug in hash:ip,port,net Due to the missing ininitalization at adding/deleting entries, when a plain_ip,port,net element was the object, multiple elements were added/deleted instead. The bug came from the missing dangling default initialization. The error-prone default initialization is corrected in all hash:* types. diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index ec3dba5..5c0b785 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c @@ -173,6 +173,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], return adtfn(set, &nip, timeout, flags); } + ip_to = ip; if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -185,8 +186,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], if (!cidr || cidr > 32) return -IPSET_ERR_INVALID_CIDR; ip_set_mask_from_to(ip, ip_to, cidr); - } else - ip_to = ip; + } hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index 0171f75..6283351 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c @@ -162,7 +162,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipport4_elem data = { }; - u32 ip, ip_to = 0, p = 0, port, port_to; + u32 ip, ip_to, p = 0, port, port_to; u32 timeout = h->timeout; bool with_ports = false; int ret; @@ -210,7 +210,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], return ip_set_eexist(ret, flags) ? 0 : ret; } - ip = ntohl(data.ip); + ip_to = ip = ntohl(data.ip); if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -223,8 +223,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], if (!cidr || cidr > 32) return -IPSET_ERR_INVALID_CIDR; ip_set_mask_from_to(ip, ip_to, cidr); - } else - ip_to = ip; + } port_to = port = ntohs(data.port); if (with_ports && tb[IPSET_ATTR_PORT_TO]) { diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 6344ef5..6a21271 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c @@ -166,7 +166,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportip4_elem data = { }; - u32 ip, ip_to = 0, p = 0, port, port_to; + u32 ip, ip_to, p = 0, port, port_to; u32 timeout = h->timeout; bool with_ports = false; int ret; @@ -218,7 +218,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], return ip_set_eexist(ret, flags) ? 0 : ret; } - ip = ntohl(data.ip); + ip_to = ip = ntohl(data.ip); if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -231,8 +231,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], if (!cidr || cidr > 32) return -IPSET_ERR_INVALID_CIDR; ip_set_mask_from_to(ip, ip_to, cidr); - } else - ip_to = ip; + } port_to = port = ntohs(data.port); if (with_ports && tb[IPSET_ATTR_PORT_TO]) { diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index cb71f9a..2d5cd4e 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c @@ -215,8 +215,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet4_elem data = { .cidr = HOST_MASK - 1 }; - u32 ip, ip_to = 0, p = 0, port, port_to; - u32 ip2_from = 0, ip2_to, ip2_last, ip2; + u32 ip, ip_to, p = 0, port, port_to; + u32 ip2_from, ip2_to, ip2_last, ip2; u32 timeout = h->timeout; bool with_ports = false; u8 cidr; @@ -286,6 +286,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], return ip_set_eexist(ret, flags) ? 0 : ret; } + ip_to = ip; if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); if (ret) @@ -306,6 +307,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], if (port > port_to) swap(port, port_to); } + + ip2_to = ip2_from; if (tb[IPSET_ATTR_IP2_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); if (ret) -- cgit v0.10.2 From 3f63c340a72f2872a9362245cb2e03f3d2bb73a6 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 19 Feb 2013 11:54:16 -0500 Subject: Bluetooth: Add support for atheros 04ca:3004 device to ath3k Yet another version of the atheros bluetooth chipset T: Bus=01 Lev=02 Prnt=02 Port=03 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=04ca ProdID=3004 Rev=00.01 S: Manufacturer=Atheros Communications S: Product=Bluetooth USB Host Controller S: SerialNumber=Alaska Day 2006 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb This resolves https://bugzilla.redhat.com/show_bug.cgi?id=844750 Reported-by: niktr@mail.ru Signed-off-by: Josh Boyer Signed-off-by: Gustavo Padovan diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 33c9a44..b9908dd 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -76,6 +76,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x311D) }, { USB_DEVICE(0x13d3, 0x3375) }, + { USB_DEVICE(0x04CA, 0x3004) }, { USB_DEVICE(0x04CA, 0x3005) }, { USB_DEVICE(0x04CA, 0x3006) }, { USB_DEVICE(0x04CA, 0x3008) }, @@ -108,6 +109,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 7e351e3..59cde8e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -134,6 +134,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, -- cgit v0.10.2 From bbfa57c0f2243a7c31fd248d22e9861a2802cad5 Mon Sep 17 00:00:00 2001 From: Sebastian Riemer Date: Thu, 21 Feb 2013 13:28:09 +1100 Subject: md: protect against crash upon fsync on ro array If an fsync occurs on a read-only array, we need to send a completion for the IO and may not increment the active IO count. Otherwise, we hit a bug trace and can't stop the MD array anymore. By advice of Christoph Hellwig we return success upon a flush request but we return -EROFS for other writes. We detect flush requests by checking if the bio has zero sectors. This patch is suitable to any -stable kernel to which it applies. Cc: Christoph Hellwig Cc: Ben Hutchings Cc: NeilBrown Cc: stable@vger.kernel.org Signed-off-by: Sebastian Riemer Reported-by: Ben Hutchings Acked-by: Paul Menzel Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index 3db3d1b..1e634a6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -307,6 +307,10 @@ static void md_make_request(struct request_queue *q, struct bio *bio) bio_io_error(bio); return; } + if (mddev->ro == 1 && unlikely(rw == WRITE)) { + bio_endio(bio, bio_sectors(bio) == 0 ? 0 : -EROFS); + return; + } smp_rmb(); /* Ensure implications of 'active' are visible */ rcu_read_lock(); if (mddev->suspended) { -- cgit v0.10.2 From cf1c4a094f46ace5bf00078e2db73491ddf018fe Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Tue, 19 Feb 2013 11:35:59 -0800 Subject: netfilter: ipset: timeout values corrupted on set resize If a resize is triggered on a set with timeouts enabled, the timeout values will get corrupted when copying them to the new set. This occured b/c the wrong timeout value is supplied to type_pf_elem_tadd(). This also adds simple debug statement similar to the one in type_pf_resize(). Signed-off-by: Josh Hunt Signed-off-by: Jozsef Kadlecsik diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h index ef9acd3..01d25e6 100644 --- a/include/linux/netfilter/ipset/ip_set_ahash.h +++ b/include/linux/netfilter/ipset/ip_set_ahash.h @@ -854,6 +854,8 @@ type_pf_tresize(struct ip_set *set, bool retried) retry: ret = 0; htable_bits++; + pr_debug("attempt to resize set %s from %u to %u, t %p\n", + set->name, orig->htable_bits, htable_bits, orig); if (!htable_bits) { /* In case we have plenty of memory :-) */ pr_warning("Cannot increase the hashsize of set %s further\n", @@ -873,7 +875,7 @@ retry: data = ahash_tdata(n, j); m = hbucket(t, HKEY(data, h->initval, htable_bits)); ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), 0, - type_pf_data_timeout(data)); + ip_set_timeout_get(type_pf_data_timeout(data))); if (ret < 0) { read_unlock_bh(&set->lock); ahash_destroy(t); -- cgit v0.10.2 From dd82088dab3646ed28e4aa43d1a5b5d5ffc2afba Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Thu, 21 Feb 2013 11:12:40 +0100 Subject: netfilter: ipset: "Directory not empty" error message When an entry flagged with "nomatch" was tested by ipset, it returned the error message "Kernel error received: Directory not empty" instead of " is NOT in set " (reported by John Brendler). The internal error code was not properly transformed before returning to userspace, fixed. Signed-off-by: Jozsef Kadlecsik diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 6d6d8f2..38ca630 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1470,7 +1470,8 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb, if (ret == -EAGAIN) ret = 1; - return ret < 0 ? ret : ret > 0 ? 0 : -IPSET_ERR_EXIST; + return (ret < 0 && ret != -ENOTEMPTY) ? ret : + ret > 0 ? 0 : -IPSET_ERR_EXIST; } /* Get headed data of a set */ -- cgit v0.10.2 From e5ab012c3271990e8457055c25cafddc1ae8aa6b Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 20 Feb 2013 16:15:36 +0100 Subject: nohz: Make tick_nohz_irq_exit() irq safe As it stands, irq_exit() may or may not be called with irqs disabled, depending on __ARCH_IRQ_EXIT_IRQS_DISABLED that the arch can define. It makes tick_nohz_irq_exit() unsafe. For example two interrupts can race in tick_nohz_stop_sched_tick(): the inner most one computes the expiring time on top of the timer list, then it's interrupted right before reprogramming the clock. The new interrupt enqueues a new timer list timer, it reprogram the clock to take it into account and it exits. The CPUs resumes the inner most interrupt and performs the clock reprogramming without considering the new timer list timer. This regression has been introduced by: 280f06774afedf849f0b34248ed6aff57d0f6908 ("nohz: Separate out irq exit and idle loop dyntick logic") Let's fix it right now with the appropriate protections. A saner long term solution will be to remove __ARCH_IRQ_EXIT_IRQS_DISABLED and mandate that irq_exit() is called with interrupts disabled. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Linus Torvalds Cc: #v3.2+ Link: http://lkml.kernel.org/r/1361373336-11337-1-git-send-email-fweisbec@gmail.com Signed-off-by: Thomas Gleixner diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 314b9ee..520592a 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -565,14 +565,19 @@ void tick_nohz_idle_enter(void) */ void tick_nohz_irq_exit(void) { + unsigned long flags; struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); if (!ts->inidle) return; - /* Cancel the timer because CPU already waken up from the C-states*/ + local_irq_save(flags); + + /* Cancel the timer because CPU already waken up from the C-states */ menu_hrtimer_cancel(); __tick_nohz_idle_enter(ts); + + local_irq_restore(flags); } /** -- cgit v0.10.2 From 74eed0163d0def3fce27228d9ccf3d36e207b286 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 20 Feb 2013 22:00:48 +0100 Subject: irq: Ensure irq_exit() code runs with interrupts disabled We had already a few problems with code called from irq_exit() when interrupted from a nesting interrupt. This can happen on architectures which do not define __ARCH_IRQ_EXIT_IRQS_DISABLED. __ARCH_IRQ_EXIT_IRQS_DISABLED should go away and we want to make it mandatory to call irq_exit() with interrupts disabled. As a temporary protection disable interrupts for those architectures which do not define __ARCH_IRQ_EXIT_IRQS_DISABLED and add a WARN_ONCE when an architecture which defines __ARCH_IRQ_EXIT_IRQS_DISABLED calls irq_exit() with interrupts enabled. Signed-off-by: Thomas Gleixner Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Paul E. McKenney Cc: Linus Torvalds Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1302202155320.22263@ionos diff --git a/kernel/softirq.c b/kernel/softirq.c index f5cc25f..f2a9346 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -341,6 +341,14 @@ static inline void invoke_softirq(void) */ void irq_exit(void) { +#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED + unsigned long flags; + + local_irq_save(flags); +#else + WARN_ON_ONCE(!irqs_disabled()); +#endif + account_irq_exit_time(current); trace_hardirq_exit(); sub_preempt_count(IRQ_EXIT_OFFSET); @@ -354,6 +362,9 @@ void irq_exit(void) #endif rcu_irq_exit(); sched_preempt_enable_no_resched(); +#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED + local_irq_restore(flags); +#endif } /* -- cgit v0.10.2 From facd8b80c67a3cf64a467c4a2ac5fb31f2e6745b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 21 Feb 2013 18:17:42 +0100 Subject: irq: Sanitize invoke_softirq With the irq protection in irq_exit, we can remove the #ifdeffery and the bh_disable/enable dance in invoke_softirq() Signed-off-by: Thomas Gleixner Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Paul E. McKenney Cc: Linus Torvalds Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1302202155320.22263@ionos diff --git a/kernel/softirq.c b/kernel/softirq.c index f2a9346..24a921b 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -322,18 +322,10 @@ void irq_enter(void) static inline void invoke_softirq(void) { - if (!force_irqthreads) { -#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED + if (!force_irqthreads) __do_softirq(); -#else - do_softirq(); -#endif - } else { - __local_bh_disable((unsigned long)__builtin_return_address(0), - SOFTIRQ_OFFSET); + else wakeup_softirqd(); - __local_bh_enable(SOFTIRQ_OFFSET); - } } /* -- cgit v0.10.2 From af7bdbafe3812af406ce07631effd2b96aae2dba Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 21 Feb 2013 18:21:30 +0100 Subject: Revert "nohz: Make tick_nohz_irq_exit() irq safe" This reverts commit 351429b2e62b6545bb10c756686393f29ba268a1. The extra local_irq_save() is not longer needed as the call site now always calls with interrupts disabled. Signed-off-by: Thomas Gleixner Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Paul E. McKenney Cc: Linus Torvalds diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 520592a..314b9ee 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -565,19 +565,14 @@ void tick_nohz_idle_enter(void) */ void tick_nohz_irq_exit(void) { - unsigned long flags; struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); if (!ts->inidle) return; - local_irq_save(flags); - - /* Cancel the timer because CPU already waken up from the C-states */ + /* Cancel the timer because CPU already waken up from the C-states*/ menu_hrtimer_cancel(); __tick_nohz_idle_enter(ts); - - local_irq_restore(flags); } /** -- cgit v0.10.2 From 4d4c4e24cf48400a24d33feffc7cca4f4e8cabe1 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 22 Feb 2013 00:05:07 +0100 Subject: irq: Remove IRQ_EXIT_OFFSET workaround The IRQ_EXIT_OFFSET trick was used to make sure the irq doesn't get preempted after we substract the HARDIRQ_OFFSET until we are entirely done with any code in irq_exit(). This workaround was necessary because some archs may call irq_exit() with irqs enabled and there is still some code in the end of this function that is not covered by the HARDIRQ_OFFSET but want to stay non-preemptible. Now that irq are always disabled in irq_exit(), the whole code is guaranteed not to be preempted. We can thus remove this hack. Signed-off-by: Frederic Weisbecker Cc: Linus Torvalds Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Paul E. McKenney diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 29eb805..c1d6555 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -118,10 +118,8 @@ #ifdef CONFIG_PREEMPT_COUNT # define preemptible() (preempt_count() == 0 && !irqs_disabled()) -# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else # define preemptible() 0 -# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET #endif #if defined(CONFIG_SMP) || defined(CONFIG_GENERIC_HARDIRQS) diff --git a/kernel/softirq.c b/kernel/softirq.c index 24a921b..f42ff97 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -343,7 +343,7 @@ void irq_exit(void) account_irq_exit_time(current); trace_hardirq_exit(); - sub_preempt_count(IRQ_EXIT_OFFSET); + sub_preempt_count(HARDIRQ_OFFSET); if (!in_interrupt() && local_softirq_pending()) invoke_softirq(); @@ -353,7 +353,6 @@ void irq_exit(void) tick_nohz_irq_exit(); #endif rcu_irq_exit(); - sched_preempt_enable_no_resched(); #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED local_irq_restore(flags); #endif -- cgit v0.10.2 From c8dc9c654794a765ca61baed07f84ed8aaa7ca8c Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Thu, 21 Feb 2013 13:28:09 +1100 Subject: md: raid1,10: Handle REQ_WRITE_SAME flag in write bios Set mddev queue's max_write_same_sectors to its chunk_sector value (before disk_stack_limits merges the underlying disk limits.) With that in place, be sure to handle writes coming down from the block layer that have the REQ_WRITE_SAME flag set. That flag needs to be copied into any newly cloned write bio. Signed-off-by: Joe Lawrence Acked-by: "Martin K. Petersen" Signed-off-by: NeilBrown diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index d5bddfc..6e5d5a5 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1000,6 +1000,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA)); const unsigned long do_discard = (bio->bi_rw & (REQ_DISCARD | REQ_SECURE)); + const unsigned long do_same = (bio->bi_rw & REQ_WRITE_SAME); struct md_rdev *blocked_rdev; struct blk_plug_cb *cb; struct raid1_plug_cb *plug = NULL; @@ -1301,7 +1302,8 @@ read_again: conf->mirrors[i].rdev->data_offset); mbio->bi_bdev = conf->mirrors[i].rdev->bdev; mbio->bi_end_io = raid1_end_write_request; - mbio->bi_rw = WRITE | do_flush_fua | do_sync | do_discard; + mbio->bi_rw = + WRITE | do_flush_fua | do_sync | do_discard | do_same; mbio->bi_private = r1_bio; atomic_inc(&r1_bio->remaining); @@ -2818,6 +2820,9 @@ static int run(struct mddev *mddev) if (IS_ERR(conf)) return PTR_ERR(conf); + if (mddev->queue) + blk_queue_max_write_same_sectors(mddev->queue, + mddev->chunk_sectors); rdev_for_each(rdev, mddev) { if (!mddev->gendisk) continue; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 64d4824..1a74c12 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1105,6 +1105,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) const unsigned long do_fua = (bio->bi_rw & REQ_FUA); const unsigned long do_discard = (bio->bi_rw & (REQ_DISCARD | REQ_SECURE)); + const unsigned long do_same = (bio->bi_rw & REQ_WRITE_SAME); unsigned long flags; struct md_rdev *blocked_rdev; struct blk_plug_cb *cb; @@ -1460,7 +1461,8 @@ retry_write: rdev)); mbio->bi_bdev = rdev->bdev; mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; + mbio->bi_rw = + WRITE | do_sync | do_fua | do_discard | do_same; mbio->bi_private = r10_bio; atomic_inc(&r10_bio->remaining); @@ -1502,7 +1504,8 @@ retry_write: r10_bio, rdev)); mbio->bi_bdev = rdev->bdev; mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; + mbio->bi_rw = + WRITE | do_sync | do_fua | do_discard | do_same; mbio->bi_private = r10_bio; atomic_inc(&r10_bio->remaining); @@ -3569,6 +3572,8 @@ static int run(struct mddev *mddev) if (mddev->queue) { blk_queue_max_discard_sectors(mddev->queue, mddev->chunk_sectors); + blk_queue_max_write_same_sectors(mddev->queue, + mddev->chunk_sectors); blk_queue_io_min(mddev->queue, chunk_size); if (conf->geo.raid_disks % conf->geo.near_copies) blk_queue_io_opt(mddev->queue, chunk_size * conf->geo.raid_disks); -- cgit v0.10.2 From 4c0ca26bd260dddf3b9781758cb5e2df3f74d4a3 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 21 Feb 2013 13:28:09 +1100 Subject: MD RAID10: Minor non-functional code changes Changes include assigning 'addr' from 's' instead of 'sector' to be consistent with the way the code does it just a few lines later and using '%=' vs a conditional and subtraction. Signed-off-by: Jonathan Brassow Signed-off-by: NeilBrown diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1a74c12..de174ad 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -552,14 +552,13 @@ static void __raid10_find_phys(struct geom *geo, struct r10bio *r10bio) for (n = 0; n < geo->near_copies; n++) { int d = dev; sector_t s = sector; - r10bio->devs[slot].addr = sector; r10bio->devs[slot].devnum = d; + r10bio->devs[slot].addr = s; slot++; for (f = 1; f < geo->far_copies; f++) { d += geo->near_copies; - if (d >= geo->raid_disks) - d -= geo->raid_disks; + d %= geo->raid_disks; s += geo->stride; r10bio->devs[slot].devnum = d; r10bio->devs[slot].addr = s; -- cgit v0.10.2 From 475901aff15841fb0a81e7546517407779a9b061 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 21 Feb 2013 13:28:10 +1100 Subject: MD RAID10: Improve redundancy for 'far' and 'offset' algorithms (part 1) The MD RAID10 'far' and 'offset' algorithms make copies of entire stripe widths - copying them to a different location on the same devices after shifting the stripe. An example layout of each follows below: "far" algorithm dev1 dev2 dev3 dev4 dev5 dev6 ==== ==== ==== ==== ==== ==== A B C D E F G H I J K L ... F A B C D E --> Copy of stripe0, but shifted by 1 L G H I J K ... "offset" algorithm dev1 dev2 dev3 dev4 dev5 dev6 ==== ==== ==== ==== ==== ==== A B C D E F F A B C D E --> Copy of stripe0, but shifted by 1 G H I J K L L G H I J K ... Redundancy for these algorithms is gained by shifting the copied stripes one device to the right. This patch proposes that array be divided into sets of adjacent devices and when the stripe copies are shifted, they wrap on set boundaries rather than the array size boundary. That is, for the purposes of shifting, the copies are confined to their sets within the array. The sets are 'near_copies * far_copies' in size. The above "far" algorithm example would change to: "far" algorithm dev1 dev2 dev3 dev4 dev5 dev6 ==== ==== ==== ==== ==== ==== A B C D E F G H I J K L ... B A D C F E --> Copy of stripe0, shifted 1, 2-dev sets H G J I L K Dev sets are 1-2, 3-4, 5-6 ... This has the affect of improving the redundancy of the array. We can always sustain at least one failure, but sometimes more than one can be handled. In the first examples, the pairs of devices that CANNOT fail together are: (1,2) (2,3) (3,4) (4,5) (5,6) (1, 6) [40% of possible pairs] In the example where the copies are confined to sets, the pairs of devices that cannot fail together are: (1,2) (3,4) (5,6) [20% of possible pairs] We cannot simply replace the old algorithms, so the 17th bit of the 'layout' variable is used to indicate whether we use the old or new method of computing the shift. (This is similar to the way the 16th bit indicates whether the "far" algorithm or the "offset" algorithm is being used.) This patch only handles the cases where the number of total raid disks is a multiple of 'far_copies'. A follow-on patch addresses the condition where this is not true. Signed-off-by: Jonathan Brassow Signed-off-by: NeilBrown diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index de174ad..70b58b4 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -38,21 +38,36 @@ * near_copies (stored in low byte of layout) * far_copies (stored in second byte of layout) * far_offset (stored in bit 16 of layout ) + * use_far_sets (stored in bit 17 of layout ) * - * The data to be stored is divided into chunks using chunksize. - * Each device is divided into far_copies sections. - * In each section, chunks are laid out in a style similar to raid0, but - * near_copies copies of each chunk is stored (each on a different drive). - * The starting device for each section is offset near_copies from the starting - * device of the previous section. - * Thus they are (near_copies*far_copies) of each chunk, and each is on a different - * drive. - * near_copies and far_copies must be at least one, and their product is at most - * raid_disks. + * The data to be stored is divided into chunks using chunksize. Each device + * is divided into far_copies sections. In each section, chunks are laid out + * in a style similar to raid0, but near_copies copies of each chunk is stored + * (each on a different drive). The starting device for each section is offset + * near_copies from the starting device of the previous section. Thus there + * are (near_copies * far_copies) of each chunk, and each is on a different + * drive. near_copies and far_copies must be at least one, and their product + * is at most raid_disks. * * If far_offset is true, then the far_copies are handled a bit differently. - * The copies are still in different stripes, but instead of be very far apart - * on disk, there are adjacent stripes. + * The copies are still in different stripes, but instead of being very far + * apart on disk, there are adjacent stripes. + * + * The far and offset algorithms are handled slightly differently if + * 'use_far_sets' is true. In this case, the array's devices are grouped into + * sets that are (near_copies * far_copies) in size. The far copied stripes + * are still shifted by 'near_copies' devices, but this shifting stays confined + * to the set rather than the entire array. This is done to improve the number + * of device combinations that can fail without causing the array to fail. + * Example 'far' algorithm w/o 'use_far_sets' (each letter represents a chunk + * on a device): + * A B C D A B C D E + * ... ... + * D A B C E A B C D + * Example 'far' algorithm w/ 'use_far_sets' enabled (sets illustrated w/ []'s): + * [A B] [C D] [A B] [C D E] + * |...| |...| |...| | ... | + * [B A] [D C] [B A] [E C D] */ /* @@ -551,14 +566,18 @@ static void __raid10_find_phys(struct geom *geo, struct r10bio *r10bio) /* and calculate all the others */ for (n = 0; n < geo->near_copies; n++) { int d = dev; + int set; sector_t s = sector; r10bio->devs[slot].devnum = d; r10bio->devs[slot].addr = s; slot++; for (f = 1; f < geo->far_copies; f++) { + set = d / geo->far_set_size; d += geo->near_copies; - d %= geo->raid_disks; + d %= geo->far_set_size; + d += geo->far_set_size * set; + s += geo->stride; r10bio->devs[slot].devnum = d; r10bio->devs[slot].addr = s; @@ -594,6 +613,8 @@ static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev) * or recovery, so reshape isn't happening */ struct geom *geo = &conf->geo; + int far_set_start = (dev / geo->far_set_size) * geo->far_set_size; + int far_set_size = geo->far_set_size; offset = sector & geo->chunk_mask; if (geo->far_offset) { @@ -601,13 +622,13 @@ static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev) chunk = sector >> geo->chunk_shift; fc = sector_div(chunk, geo->far_copies); dev -= fc * geo->near_copies; - if (dev < 0) - dev += geo->raid_disks; + if (dev < far_set_start) + dev += far_set_size; } else { while (sector >= geo->stride) { sector -= geo->stride; - if (dev < geo->near_copies) - dev += geo->raid_disks - geo->near_copies; + if (dev < (geo->near_copies + far_set_start)) + dev += far_set_size - geo->near_copies; else dev -= geo->near_copies; } @@ -3438,7 +3459,7 @@ static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new) disks = mddev->raid_disks + mddev->delta_disks; break; } - if (layout >> 17) + if (layout >> 18) return -1; if (chunk < (PAGE_SIZE >> 9) || !is_power_of_2(chunk)) @@ -3450,6 +3471,7 @@ static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new) geo->near_copies = nc; geo->far_copies = fc; geo->far_offset = fo; + geo->far_set_size = (layout & (1<<17)) ? disks / fc : disks; geo->chunk_mask = chunk - 1; geo->chunk_shift = ffz(~chunk); return nc*fc; diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h index 1054cf6..157d69e 100644 --- a/drivers/md/raid10.h +++ b/drivers/md/raid10.h @@ -33,6 +33,11 @@ struct r10conf { * far_offset, in which case it is * 1 stripe. */ + int far_set_size; /* The number of devices in a set, + * where a 'set' are devices that + * contain far/offset copies of + * each other. + */ int chunk_shift; /* shift from chunks to sectors */ sector_t chunk_mask; } prev, geo; -- cgit v0.10.2 From 9a3152ab024867100f2f50d124b998d05fb1c3f6 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 21 Feb 2013 13:28:10 +1100 Subject: MD RAID10: Improve redundancy for 'far' and 'offset' algorithms (part 2) MD RAID10: Improve redundancy for 'far' and 'offset' algorithms (part 2) This patch addresses raid arrays that have a number of devices that cannot be evenly divided by 'far_copies'. (E.g. 5 devices, far_copies = 2) This case must be handled differently because it causes that last set to be of a different size than the rest of the sets. We must compute a new modulo for this last set so that copied chunks are properly wrapped around. Example use_far_sets=1, far_copies=2, near_copies=1, devices=5: "far" algorithm dev1 dev2 dev3 dev4 dev5 ==== ==== ==== ==== ==== [ A B ] [ C D E ] [ G H ] [ I J K ] ... [ B A ] [ E C D ] --> nominal set of 2 and last set of 3 [ H G ] [ K I J ] []'s show far/offset sets Signed-off-by: Jonathan Brassow Signed-off-by: NeilBrown diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 70b58b4..61ed150 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -550,6 +550,13 @@ static void __raid10_find_phys(struct geom *geo, struct r10bio *r10bio) sector_t stripe; int dev; int slot = 0; + int last_far_set_start, last_far_set_size; + + last_far_set_start = (geo->raid_disks / geo->far_set_size) - 1; + last_far_set_start *= geo->far_set_size; + + last_far_set_size = geo->far_set_size; + last_far_set_size += (geo->raid_disks % geo->far_set_size); /* now calculate first sector/dev */ chunk = r10bio->sector >> geo->chunk_shift; @@ -575,9 +582,16 @@ static void __raid10_find_phys(struct geom *geo, struct r10bio *r10bio) for (f = 1; f < geo->far_copies; f++) { set = d / geo->far_set_size; d += geo->near_copies; - d %= geo->far_set_size; - d += geo->far_set_size * set; + if ((geo->raid_disks % geo->far_set_size) && + (d > last_far_set_start)) { + d -= last_far_set_start; + d %= last_far_set_size; + d += last_far_set_start; + } else { + d %= geo->far_set_size; + d += geo->far_set_size * set; + } s += geo->stride; r10bio->devs[slot].devnum = d; r10bio->devs[slot].addr = s; @@ -615,6 +629,18 @@ static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev) struct geom *geo = &conf->geo; int far_set_start = (dev / geo->far_set_size) * geo->far_set_size; int far_set_size = geo->far_set_size; + int last_far_set_start; + + if (geo->raid_disks % geo->far_set_size) { + last_far_set_start = (geo->raid_disks / geo->far_set_size) - 1; + last_far_set_start *= geo->far_set_size; + + if (dev >= last_far_set_start) { + far_set_size = geo->far_set_size; + far_set_size += (geo->raid_disks % geo->far_set_size); + far_set_start = last_far_set_start; + } + } offset = sector & geo->chunk_mask; if (geo->far_offset) { -- cgit v0.10.2 From fe5d2f4a15967bbe907e7b3e31e49dae7af7cc6b Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 21 Feb 2013 13:28:10 +1100 Subject: DM RAID: Add support for MD's RAID10 "far" and "offset" algorithms DM RAID: Add support for MD's RAID10 "far" and "offset" algorithms Until now, dm-raid.c only supported the "near" algorthm of MD's RAID10 implementation. This patch adds support for the "far" and "offset" algorithms, but only with the improved redundancy that is brought with the introduction of the 'use_far_sets' bit, which shifts copied stripes according to smaller sets vs the entire array. That is, the 17th bit of the 'layout' variable that defines the RAID10 implementation will always be set. (More information on how the 'layout' variable selects the RAID10 algorithm can be found in the opening comments of drivers/md/raid10.c.) Signed-off-by: Jonathan Brassow Signed-off-by: NeilBrown diff --git a/Documentation/device-mapper/dm-raid.txt b/Documentation/device-mapper/dm-raid.txt index 56fb62b..b428556 100644 --- a/Documentation/device-mapper/dm-raid.txt +++ b/Documentation/device-mapper/dm-raid.txt @@ -30,6 +30,7 @@ The target is named "raid" and it accepts the following parameters: raid10 Various RAID10 inspired algorithms chosen by additional params - RAID10: Striped Mirrors (aka 'Striping on top of mirrors') - RAID1E: Integrated Adjacent Stripe Mirroring + - RAID1E: Integrated Offset Stripe Mirroring - and other similar RAID10 variants Reference: Chapter 4 of @@ -64,15 +65,15 @@ The target is named "raid" and it accepts the following parameters: synchronisation state for each region. [raid10_copies <# copies>] - [raid10_format near] + [raid10_format ] These two options are used to alter the default layout of a RAID10 configuration. The number of copies is can be - specified, but the default is 2. There are other variations - to how the copies are laid down - the default and only current - option is "near". Near copies are what most people think of - with respect to mirroring. If these options are left - unspecified, or 'raid10_copies 2' and/or 'raid10_format near' - are given, then the layouts for 2, 3 and 4 devices are: + specified, but the default is 2. There are also three + variations to how the copies are laid down - the default + is "near". Near copies are what most people think of with + respect to mirroring. If these options are left unspecified, + or 'raid10_copies 2' and/or 'raid10_format near' are given, + then the layouts for 2, 3 and 4 devices are: 2 drives 3 drives 4 drives -------- ---------- -------------- A1 A1 A1 A1 A2 A1 A1 A2 A2 @@ -85,6 +86,33 @@ The target is named "raid" and it accepts the following parameters: 3-device layout is what might be called a 'RAID1E - Integrated Adjacent Stripe Mirroring'. + If 'raid10_copies 2' and 'raid10_format far', then the layouts + for 2, 3 and 4 devices are: + 2 drives 3 drives 4 drives + -------- -------------- -------------------- + A1 A2 A1 A2 A3 A1 A2 A3 A4 + A3 A4 A4 A5 A6 A5 A6 A7 A8 + A5 A6 A7 A8 A9 A9 A10 A11 A12 + .. .. .. .. .. .. .. .. .. + A2 A1 A3 A1 A2 A2 A1 A4 A3 + A4 A3 A6 A4 A5 A6 A5 A8 A7 + A6 A5 A9 A7 A8 A10 A9 A12 A11 + .. .. .. .. .. .. .. .. .. + + If 'raid10_copies 2' and 'raid10_format offset', then the + layouts for 2, 3 and 4 devices are: + 2 drives 3 drives 4 drives + -------- ------------ ----------------- + A1 A2 A1 A2 A3 A1 A2 A3 A4 + A2 A1 A3 A1 A2 A2 A1 A4 A3 + A3 A4 A4 A5 A6 A5 A6 A7 A8 + A4 A3 A6 A4 A5 A6 A5 A8 A7 + A5 A6 A7 A8 A9 A9 A10 A11 A12 + A6 A5 A9 A7 A8 A10 A9 A12 A11 + .. .. .. .. .. .. .. .. .. + Here we see layouts closely akin to 'RAID1E - Integrated + Offset Stripe Mirroring'. + <#raid_devs>: The number of devices composing the array. Each device consists of two entries. The first is the device containing the metadata (if any); the second is the one containing the @@ -142,3 +170,5 @@ Version History 1.3.0 Added support for RAID 10 1.3.1 Allow device replacement/rebuild for RAID 10 1.3.2 Fix/improve redundancy checking for RAID10 +1.4.0 Non-functional change. Removes arg from mapping function. +1.4.1 Add RAID10 "far" and "offset" algorithm support. diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 9e58dbd..22fd559 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -91,15 +91,44 @@ static struct raid_type { {"raid6_nc", "RAID6 (N continue)", 2, 4, 6, ALGORITHM_ROTATING_N_CONTINUE} }; +static char *raid10_md_layout_to_format(int layout) +{ + /* + * Bit 16 and 17 stand for "offset" and "use_far_sets" + * Refer to MD's raid10.c for details + */ + if ((layout & 0x10000) && (layout & 0x20000)) + return "offset"; + + if ((layout & 0xFF) > 1) + return "near"; + + return "far"; +} + static unsigned raid10_md_layout_to_copies(int layout) { - return layout & 0xFF; + if ((layout & 0xFF) > 1) + return layout & 0xFF; + return (layout >> 8) & 0xFF; } static int raid10_format_to_md_layout(char *format, unsigned copies) { - /* 1 "far" copy, and 'copies' "near" copies */ - return (1 << 8) | (copies & 0xFF); + unsigned n = 1, f = 1; + + if (!strcmp("near", format)) + n = copies; + else + f = copies; + + if (!strcmp("offset", format)) + return 0x30000 | (f << 8) | n; + + if (!strcmp("far", format)) + return 0x20000 | (f << 8) | n; + + return (f << 8) | n; } static struct raid_type *get_raid_type(char *name) @@ -352,6 +381,7 @@ static int validate_raid_redundancy(struct raid_set *rs) { unsigned i, rebuild_cnt = 0; unsigned rebuilds_per_group, copies, d; + unsigned group_size, last_group_start; for (i = 0; i < rs->md.raid_disks; i++) if (!test_bit(In_sync, &rs->dev[i].rdev.flags) || @@ -379,9 +409,6 @@ static int validate_raid_redundancy(struct raid_set *rs) * as long as the failed devices occur in different mirror * groups (i.e. different stripes). * - * Right now, we only allow for "near" copies. When other - * formats are added, we will have to check those too. - * * When checking "near" format, make sure no adjacent devices * have failed beyond what can be handled. In addition to the * simple case where the number of devices is a multiple of the @@ -391,14 +418,41 @@ static int validate_raid_redundancy(struct raid_set *rs) * A A B B C * C D D E E */ - for (i = 0; i < rs->md.raid_disks * copies; i++) { - if (!(i % copies)) + if (!strcmp("near", raid10_md_layout_to_format(rs->md.layout))) { + for (i = 0; i < rs->md.raid_disks * copies; i++) { + if (!(i % copies)) + rebuilds_per_group = 0; + d = i % rs->md.raid_disks; + if ((!rs->dev[d].rdev.sb_page || + !test_bit(In_sync, &rs->dev[d].rdev.flags)) && + (++rebuilds_per_group >= copies)) + goto too_many; + } + break; + } + + /* + * When checking "far" and "offset" formats, we need to ensure + * that the device that holds its copy is not also dead or + * being rebuilt. (Note that "far" and "offset" formats only + * support two copies right now. These formats also only ever + * use the 'use_far_sets' variant.) + * + * This check is somewhat complicated by the need to account + * for arrays that are not a multiple of (far) copies. This + * results in the need to treat the last (potentially larger) + * set differently. + */ + group_size = (rs->md.raid_disks / copies); + last_group_start = (rs->md.raid_disks / group_size) - 1; + last_group_start *= group_size; + for (i = 0; i < rs->md.raid_disks; i++) { + if (!(i % copies) && !(i > last_group_start)) rebuilds_per_group = 0; - d = i % rs->md.raid_disks; - if ((!rs->dev[d].rdev.sb_page || - !test_bit(In_sync, &rs->dev[d].rdev.flags)) && + if ((!rs->dev[i].rdev.sb_page || + !test_bit(In_sync, &rs->dev[i].rdev.flags)) && (++rebuilds_per_group >= copies)) - goto too_many; + goto too_many; } break; default: @@ -433,7 +487,7 @@ too_many: * * RAID10-only options: * [raid10_copies <# copies>] Number of copies. (Default: 2) - * [raid10_format ] Layout algorithm. (Default: near) + * [raid10_format ] Layout algorithm. (Default: near) */ static int parse_raid_params(struct raid_set *rs, char **argv, unsigned num_raid_params) @@ -520,7 +574,9 @@ static int parse_raid_params(struct raid_set *rs, char **argv, rs->ti->error = "'raid10_format' is an invalid parameter for this RAID type"; return -EINVAL; } - if (strcmp("near", argv[i])) { + if (strcmp("near", argv[i]) && + strcmp("far", argv[i]) && + strcmp("offset", argv[i])) { rs->ti->error = "Invalid 'raid10_format' value given"; return -EINVAL; } @@ -644,6 +700,15 @@ static int parse_raid_params(struct raid_set *rs, char **argv, return -EINVAL; } + /* + * If the format is not "near", we only support + * two copies at the moment. + */ + if (strcmp("near", raid10_format) && (raid10_copies > 2)) { + rs->ti->error = "Too many copies for given RAID10 format."; + return -EINVAL; + } + /* (Len * #mirrors) / #devices */ sectors_per_dev = rs->ti->len * raid10_copies; sector_div(sectors_per_dev, rs->md.raid_disks); @@ -854,17 +919,30 @@ static int super_init_validation(struct mddev *mddev, struct md_rdev *rdev) /* * Reshaping is not currently allowed */ - if ((le32_to_cpu(sb->level) != mddev->level) || - (le32_to_cpu(sb->layout) != mddev->layout) || - (le32_to_cpu(sb->stripe_sectors) != mddev->chunk_sectors)) { - DMERR("Reshaping arrays not yet supported."); + if (le32_to_cpu(sb->level) != mddev->level) { + DMERR("Reshaping arrays not yet supported. (RAID level change)"); + return -EINVAL; + } + if (le32_to_cpu(sb->layout) != mddev->layout) { + DMERR("Reshaping arrays not yet supported. (RAID layout change)"); + DMERR(" 0x%X vs 0x%X", le32_to_cpu(sb->layout), mddev->layout); + DMERR(" Old layout: %s w/ %d copies", + raid10_md_layout_to_format(le32_to_cpu(sb->layout)), + raid10_md_layout_to_copies(le32_to_cpu(sb->layout))); + DMERR(" New layout: %s w/ %d copies", + raid10_md_layout_to_format(mddev->layout), + raid10_md_layout_to_copies(mddev->layout)); + return -EINVAL; + } + if (le32_to_cpu(sb->stripe_sectors) != mddev->chunk_sectors) { + DMERR("Reshaping arrays not yet supported. (stripe sectors change)"); return -EINVAL; } /* We can only change the number of devices in RAID1 right now */ if ((rs->raid_type->level != 1) && (le32_to_cpu(sb->num_devices) != mddev->raid_disks)) { - DMERR("Reshaping arrays not yet supported."); + DMERR("Reshaping arrays not yet supported. (device count change)"); return -EINVAL; } @@ -1329,7 +1407,8 @@ static int raid_status(struct dm_target *ti, status_type_t type, raid10_md_layout_to_copies(rs->md.layout)); if (rs->print_flags & DMPF_RAID10_FORMAT) - DMEMIT(" raid10_format near"); + DMEMIT(" raid10_format %s", + raid10_md_layout_to_format(rs->md.layout)); DMEMIT(" %d", rs->md.raid_disks); for (i = 0; i < rs->md.raid_disks; i++) { @@ -1420,6 +1499,10 @@ static struct target_type raid_target = { static int __init dm_raid_init(void) { + DMINFO("Loading target version %u.%u.%u", + raid_target.version[0], + raid_target.version[1], + raid_target.version[2]); return dm_register_target(&raid_target); } -- cgit v0.10.2 From a64685399181780998281fe07309a94b25dd24c3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 21 Feb 2013 14:33:17 +1100 Subject: md: fix two bugs when attempting to resize RAID0 array. You cannot resize a RAID0 array (in terms of making the devices bigger), but the code doesn't entirely stop you. So: disable setting of the available size on each device for RAID0 and Linear devices. This must not change as doing so can change the effective layout of data. Make sure that the size that raid0_size() reports is accurate, but rounding devices sizes to chunk sizes. As the device sizes cannot change now, this isn't so important, but it is best to be safe. Without this change: mdadm --grow /dev/md0 -z max mdadm --grow /dev/md0 -Z max then read to the end of the array can cause a BUG in a RAID0 array. These bugs have been present ever since it became possible to resize any device, which is a long time. So the fix is suitable for any -stable kerenl. Cc: stable@vger.kernel.org Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index 1e634a6..f363135 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2998,6 +2998,9 @@ rdev_size_store(struct md_rdev *rdev, const char *buf, size_t len) } else if (!sectors) sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) - rdev->data_offset; + if (!my_mddev->pers->resize) + /* Cannot change size for RAID0 or Linear etc */ + return -EINVAL; } if (sectors < my_mddev->dev_sectors) return -EINVAL; /* component must fit device */ diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 24b3597..15c8d35 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -411,7 +411,8 @@ static sector_t raid0_size(struct mddev *mddev, sector_t sectors, int raid_disks "%s does not support generic reshape\n", __func__); rdev_for_each(rdev, mddev) - array_sectors += rdev->sectors; + array_sectors += (rdev->sectors & + ~(sector_t)(mddev->chunk_sectors-1)); return array_sectors; } -- cgit v0.10.2 From 58ebb34c49fcfcaa029e4b1c1453d92583900f9a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 21 Feb 2013 15:36:38 +1100 Subject: md: raid0: fix error return from create_stripe_zones. Create_stripe_zones returns an error slightly differently to raid0_run and to raid0_takeover_*. The error returned used by the second was wrong and an error would result in mddev->private being set to NULL and sooner or later a crash. So never return NULL, return ERR_PTR(err), not NULL from create_stripe_zones. This bug has been present since 2.6.35 so the fix is suitable for any kernel since then. Cc: stable@vger.kernel.org Signed-off-by: NeilBrown diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 15c8d35..d9babda 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -289,7 +289,7 @@ abort: kfree(conf->strip_zone); kfree(conf->devlist); kfree(conf); - *private_conf = NULL; + *private_conf = ERR_PTR(err); return err; } -- cgit v0.10.2 From f96c9f305c24a0d4a075e2c75aa6b417aa238687 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 21 Feb 2013 15:50:07 +1100 Subject: md/raid0: improve error message when converting RAID4-with-spares to RAID0 Mentioning "bad disk number -1" exposes irrelevant internal detail. Just say they are inactive and must be removed. Signed-off-by: NeilBrown diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index d9babda..0505452 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -175,7 +175,13 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) rdev1->new_raid_disk = j; } - if (j < 0 || j >= mddev->raid_disks) { + if (j < 0) { + printk(KERN_ERR + "md/raid0:%s: remove inactive devices before converting to RAID0\n", + mdname(mddev)); + goto abort; + } + if (j >= mddev->raid_disks) { printk(KERN_ERR "md/raid0:%s: bad disk number %d - " "aborting!\n", mdname(mddev), j); goto abort; -- cgit v0.10.2 From ee0b0244030434cdda26777bfb98962447e080cd Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 25 Feb 2013 12:38:29 +1100 Subject: md/raid1,raid10: fix deadlock with freeze_array() When raid1/raid10 needs to fix a read error, it first drains all pending requests by calling freeze_array(). This calls flush_pending_writes() if it needs to sleep, but some writes may be pending in a per-process plug rather than in the per-array request queue. When raid1{,0}_unplug() moves the request from the per-process plug to the per-array request queue (from which flush_pending_writes() can flush them), it needs to wake up freeze_array(), or freeze_array() will never flush them and so it will block forever. So add the requires wake_up() calls. This bug was introduced by commit f54a9d0e59c4bea3db733921ca9147612a6f292c for raid1 and a similar commit for RAID10, and so has been present since linux-3.6. As the bug causes a deadlock I believe this fix is suitable for -stable. Cc: stable@vger.kernel.org (3.6.y 3.7.y 3.8.y) Reported-by: Tregaron Bayly Tested-by: Tregaron Bayly Signed-off-by: NeilBrown diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 6e5d5a5..fd86b37 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -967,6 +967,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule) bio_list_merge(&conf->pending_bio_list, &plug->pending); conf->pending_count += plug->pending_cnt; spin_unlock_irq(&conf->device_lock); + wake_up(&conf->wait_barrier); md_wakeup_thread(mddev->thread); kfree(plug); return; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 61ed150..77b562d 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1119,6 +1119,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) bio_list_merge(&conf->pending_bio_list, &plug->pending); conf->pending_count += plug->pending_cnt; spin_unlock_irq(&conf->device_lock); + wake_up(&conf->wait_barrier); md_wakeup_thread(mddev->thread); kfree(plug); return; -- cgit v0.10.2 From 3a68f19d7afb80f548d016effbc6ed52643a8085 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 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 diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index d780a0d..a575491 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -236,7 +236,8 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue) } 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->flags & EFX_RX_BUF_PAGE) && rx_buf->u.page) { struct efx_rx_page_state *state; @@ -247,6 +248,10 @@ static void efx_unmap_rx_buffer(struct efx_nic *efx, state->dma_addr, efx_rx_buf_size(efx), DMA_FROM_DEVICE); + } 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->flags & EFX_RX_BUF_PAGE) && rx_buf->u.skb) { dma_unmap_single(&efx->pci_dev->dev, rx_buf->dma_addr, @@ -269,7 +274,7 @@ static void efx_free_rx_buffer(struct efx_nic *efx, 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); } @@ -535,10 +540,10 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, 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. -- cgit v0.10.2 From b590ace09d51cd39744e0f7662c5e4a0d1b5d952 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 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 diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 2d756c1..0a90abd 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -210,6 +210,7 @@ struct efx_tx_queue { * Will be %NULL if the buffer slot is currently free. * @page: The associated page buffer. Valif iff @flags & %EFX_RX_BUF_PAGE. * Will be %NULL if the buffer slot is currently free. + * @page_offset: Offset within page. Valid iff @flags & %EFX_RX_BUF_PAGE. * @len: Buffer length, in bytes. * @flags: Flags for buffer and packet state. */ @@ -219,7 +220,8 @@ struct efx_rx_buffer { struct sk_buff *skb; struct page *page; } u; - unsigned int len; + u16 page_offset; + u16 len; u16 flags; }; #define EFX_RX_BUF_PAGE 0x0001 diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index a575491..879ff58 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -90,11 +90,7 @@ static unsigned int rx_refill_threshold; 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 ((unsigned int) 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) { @@ -187,6 +183,7 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue) struct efx_nic *efx = rx_queue->efx; struct efx_rx_buffer *rx_buf; struct page *page; + unsigned int page_offset; struct efx_rx_page_state *state; dma_addr_t dma_addr; unsigned index, count; @@ -211,12 +208,14 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue) state->dma_addr = dma_addr; 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; rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN; rx_buf->flags = EFX_RX_BUF_PAGE; ++rx_queue->added_count; @@ -227,6 +226,7 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue) /* Use the second half of the page */ get_page(page); dma_addr += (PAGE_SIZE >> 1); + page_offset += (PAGE_SIZE >> 1); ++count; goto split; } -- cgit v0.10.2 From 29c69a4882641285a854d6d03ca5adbba68c0034 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 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 diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index bf57b3c..0bc0099 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -779,6 +779,7 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) tx_queue->txd.entries); } + efx_device_detach_sync(efx); efx_stop_all(efx); efx_stop_interrupts(efx, true); @@ -832,6 +833,7 @@ out: efx_start_interrupts(efx, true); efx_start_all(efx); + netif_device_attach(efx->net_dev); return rc; rollback: @@ -1641,8 +1643,12 @@ static void efx_stop_all(struct efx_nic *efx) /* 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)); netif_tx_disable(efx->net_dev); efx_stop_datapath(efx); @@ -1963,16 +1969,18 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) 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); + mutex_lock(&efx->mac_lock); net_dev->mtu = new_mtu; efx->type->reconfigure_mac(efx); mutex_unlock(&efx->mac_lock); efx_start_all(efx); + netif_device_attach(efx->net_dev); return 0; } -- cgit v0.10.2 From 46c498c2cdee5efe44f617bcd4f388179be36115 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 26 Feb 2013 18:44:33 +0100 Subject: stop_machine: Mark per cpu stopper enabled early commit 14e568e78 (stop_machine: Use smpboot threads) introduced the following regression: Before this commit the stopper enabled bit was set in the online notifier. CPU0 CPU1 cpu_up cpu online hotplug_notifier(ONLINE) stopper(CPU1)->enabled = true; ... stop_machine() The conversion to smpboot threads moved the enablement to the wakeup path of the parked thread. The majority of users seem to have the following working order: CPU0 CPU1 cpu_up cpu online unpark_threads() wakeup(stopper[CPU1]) .... stopper thread runs stopper(CPU1)->enabled = true; stop_machine() But Konrad and Sander have observed: CPU0 CPU1 cpu_up cpu online unpark_threads() wakeup(stopper[CPU1]) .... stop_machine() stopper thread runs stopper(CPU1)->enabled = true; Now the stop machinery kicks CPU0 into the stop loop, where it gets stuck forever because the queue code saw stopper(CPU1)->enabled == false, so CPU0 waits for CPU1 to enter stomp_machine, but the CPU1 stopper work got discarded due to enabled == false. Add a pre_unpark function to the smpboot thread descriptor and call it before waking the thread. This fixes the problem at hand, but the stop_machine code should be more robust. The stopper->enabled flag smells fishy at best. Thanks to Konrad for going through a loop of debug patches and providing the information to decode this issue. Reported-and-tested-by: Konrad Rzeszutek Wilk Reported-and-tested-by: Sander Eikelenboom Cc: Srivatsa S. Bhat Cc: Rusty Russell Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1302261843240.22263@ionos Signed-off-by: Thomas Gleixner diff --git a/include/linux/smpboot.h b/include/linux/smpboot.h index c65dee0..13e9296 100644 --- a/include/linux/smpboot.h +++ b/include/linux/smpboot.h @@ -24,6 +24,9 @@ struct smpboot_thread_data; * parked (cpu offline) * @unpark: Optional unpark function, called when the thread is * unparked (cpu online) + * @pre_unpark: Optional unpark function, called before the thread is + * unparked (cpu online). This is not guaranteed to be + * called on the target cpu of the thread. Careful! * @selfparking: Thread is not parked by the park function. * @thread_comm: The base name of the thread */ @@ -37,6 +40,7 @@ struct smp_hotplug_thread { void (*cleanup)(unsigned int cpu, bool online); void (*park)(unsigned int cpu); void (*unpark)(unsigned int cpu); + void (*pre_unpark)(unsigned int cpu); bool selfparking; const char *thread_comm; }; diff --git a/kernel/smpboot.c b/kernel/smpboot.c index d4abac2..8eaed9a 100644 --- a/kernel/smpboot.c +++ b/kernel/smpboot.c @@ -209,6 +209,8 @@ static void smpboot_unpark_thread(struct smp_hotplug_thread *ht, unsigned int cp { struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); + if (ht->pre_unpark) + ht->pre_unpark(cpu); kthread_unpark(tsk); } diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 95d178c..c09f295 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -336,7 +336,7 @@ static struct smp_hotplug_thread cpu_stop_threads = { .create = cpu_stop_create, .setup = cpu_stop_unpark, .park = cpu_stop_park, - .unpark = cpu_stop_unpark, + .pre_unpark = cpu_stop_unpark, .selfparking = true, }; -- cgit v0.10.2 From 0237c11044b3670adcbe80cd6dd721285347f497 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 26 Feb 2013 04:06:20 +0000 Subject: drivers: net: ethernet: cpsw: consider number of slaves in interation Make cpsw_add_default_vlan() look at the actual number of slaves for its iteration, so boards with less than 2 slaves don't ooops at boot. Signed-off-by: Daniel Mack Cc: Mugunthan V N Cc: David S. Miller Acked-by: Mugunthan V N Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 7e93df6..01ffbc4 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -731,7 +731,7 @@ static inline void cpsw_add_default_vlan(struct cpsw_priv *priv) writel(vlan, &priv->host_port_regs->port_vlan); - for (i = 0; i < 2; i++) + for (i = 0; i < priv->data.slaves; i++) slave_write(priv->slaves + i, vlan, reg); cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port, -- cgit v0.10.2 From 6c8c4e4c24b9f6cee3d356a51e4a7f2af787a49b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 25 Feb 2013 22:26:15 +0000 Subject: bond: check if slave count is 0 in case when deciding to take slave's mac in bond_enslave(), check slave_cnt before actually using slave address. introduced by: commit 409cc1f8a41 (bond: have random dev address by default instead of zeroes) Reported-by: Greg Rose Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 11d01d6..7bd068a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1629,7 +1629,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* If this is the first slave, then we need to set the master's hardware * address to be the same as the slave's. */ - if (bond->dev_addr_from_first) + if (bond->slave_cnt == 0 && bond->dev_addr_from_first) bond_set_dev_addr(bond->dev, slave_dev); new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); -- cgit v0.10.2 From 114a6f8b52163c0232fbcd7f3808ff04dc61a9b5 Mon Sep 17 00:00:00 2001 From: Marina Makienko Date: Mon, 25 Feb 2013 22:26:50 +0000 Subject: isdn: hisax: add missing usb_free_urb Add missing usb_free_urb() on failure path in st5481_setup_usb(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Marina Makienko Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 017c67e..ead0a4f 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -294,13 +294,13 @@ int st5481_setup_usb(struct st5481_adapter *adapter) // Allocate URBs and buffers for interrupt endpoint urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { - return -ENOMEM; + goto err1; } intr->urb = urb; buf = kmalloc(INT_PKT_SIZE, GFP_KERNEL); if (!buf) { - return -ENOMEM; + goto err2; } endpoint = &altsetting->endpoint[EP_INT-1]; @@ -313,6 +313,14 @@ int st5481_setup_usb(struct st5481_adapter *adapter) endpoint->desc.bInterval); return 0; +err2: + usb_free_urb(intr->urb); + intr->urb = NULL; +err1: + usb_free_urb(ctrl->urb); + ctrl->urb = NULL; + + return -ENOMEM; } /* -- cgit v0.10.2 From e70ab977991964a5a7ad1182799451d067e62669 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 25 Feb 2013 21:32:25 +0000 Subject: proc connector: reject unprivileged listener bumps While PROC_CN_MCAST_LISTEN/IGNORE is entirely advisory, it was possible for an unprivileged user to turn off notifications for all listeners by sending PROC_CN_MCAST_IGNORE. Instead, require the same privileges as required for a multicast bind. Signed-off-by: Kees Cook Cc: Evgeniy Polyakov Cc: Matt Helsley Cc: stable@vger.kernel.org Acked-by: Evgeniy Polyakov Acked-by: Matt Helsley Signed-off-by: David S. Miller diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index fce2000..1110478 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -313,6 +313,12 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg, (task_active_pid_ns(current) != &init_pid_ns)) return; + /* Can only change if privileged. */ + if (!capable(CAP_NET_ADMIN)) { + err = EPERM; + goto out; + } + mc_op = (enum proc_cn_mcast_op *)msg->data; switch (*mc_op) { case PROC_CN_MCAST_LISTEN: @@ -325,6 +331,8 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg, err = EINVAL; break; } + +out: cn_proc_ack(err, msg->seq, msg->ack); } -- cgit v0.10.2 From 90c7881ecee1f08e0a49172cf61371cf2509ee4a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 26 Feb 2013 19:15:02 +0000 Subject: irda: small read beyond end of array in debug code charset comes from skb->data. It's a number in the 0-255 range. If we have debugging turned on then this could cause a read beyond the end of the array. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/net/irda/iriap.c b/net/irda/iriap.c index e71e85b..29340a9 100644 --- a/net/irda/iriap.c +++ b/net/irda/iriap.c @@ -495,8 +495,11 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self, /* case CS_ISO_8859_9: */ /* case CS_UNICODE: */ default: - IRDA_DEBUG(0, "%s(), charset %s, not supported\n", - __func__, ias_charset_types[charset]); + IRDA_DEBUG(0, "%s(), charset [%d] %s, not supported\n", + __func__, charset, + charset < ARRAY_SIZE(ias_charset_types) ? + ias_charset_types[charset] : + "(unknown)"); /* Aborting, close connection! */ iriap_disconnect_request(self); -- cgit v0.10.2 From e2593fcde1d906b26b81b38755749f7427f3439f Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Wed, 27 Feb 2013 00:04:59 +0000 Subject: bnx2x: fix UDP checksum for 57710/57711. Since commit 86564c3f "bnx2x: Remove many sparse warnings" UDP csum offload is broken for 57710/57711. Fix return value. Signed-off-by: Dmitry Kravkov CC: Ariel Elior CC: Yuval Mintz Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index ecac04a3..a923bc4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3142,7 +3142,7 @@ static inline __le16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix) tsum = ~csum_fold(csum_add((__force __wsum) csum, csum_partial(t_header, -fix, 0))); - return bswab16(csum); + return bswab16(tsum); } static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb) -- cgit v0.10.2 From 1f84eab4ad73bcb7d779cba65291fe62909e373f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 27 Feb 2013 03:08:58 +0000 Subject: net: cdc_ncm: tag Huawei devices (e.g. E5331) with FLAG_WWAN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tag all Huawei NCM devices as WWAN modems, as we don't know of any which are not. This is necessary for userspace clients to know that the device requires further setup on e.g. an AT-capable serial ports before connectivity is available. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 4a8c25a..61b74a2 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1213,6 +1213,14 @@ static const struct usb_device_id cdc_devs[] = { .driver_info = (unsigned long) &wwan_info, }, + /* tag Huawei devices as wwan */ + { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, + USB_CLASS_COMM, + USB_CDC_SUBCLASS_NCM, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&wwan_info, + }, + /* Huawei NCM devices disguised as vendor specific */ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x16), .driver_info = (unsigned long)&wwan_info, -- cgit v0.10.2 From 45af3fb4a018ef84bf1c9f2dfbd887a41242e77f Mon Sep 17 00:00:00 2001 From: Glen Turner Date: Wed, 27 Feb 2013 04:32:36 +0000 Subject: usb/net/asix_devices: Add USBNET HG20F9 ethernet dongle This USB ethernet adapter was purchased in anodyne packaging from the computer store adjacent to linux.conf.au 2013 in Canberra (Australia). A web search shows other recent purchasers in Lancaster (UK) and Seattle (USA). Just like an emergent virus, our age of e-commerce and airmail allows underdocumented hardware to spread around the world instantly using the vector of ridiculously low prices. Paige Thompson, infected via eBay, discovered that the HG20F9 is a copy of the Asix 88772B; many viruses copy the RNA of other viruses. See Paige's work at . This patch uses her discovery to update the restructured Asix driver in the current kernel. Just as some viruses inhabit seemingly-healthy cells, the HG20F9 uses the Vendor ID 0x066b assigned to Linksys Inc. For the present there is no clash of Product ID 0x20f9. Signed-off-by: Glen Turner Signed-off-by: David S. Miller diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 2205dbc..7097534 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -924,6 +924,29 @@ static const struct driver_info ax88178_info = { .tx_fixup = asix_tx_fixup, }; +/* + * USBLINK 20F9 "USB 2.0 LAN" USB ethernet adapter, typically found in + * no-name packaging. + * USB device strings are: + * 1: Manufacturer: USBLINK + * 2: Product: HG20F9 USB2.0 + * 3: Serial: 000003 + * Appears to be compatible with Asix 88772B. + */ +static const struct driver_info hg20f9_info = { + .description = "HG20F9 USB 2.0 Ethernet", + .bind = ax88772_bind, + .unbind = ax88772_unbind, + .status = asix_status, + .link_reset = ax88772_link_reset, + .reset = ax88772_reset, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | + FLAG_MULTI_PACKET, + .rx_fixup = asix_rx_fixup_common, + .tx_fixup = asix_tx_fixup, + .data = FLAG_EEPROM_MAC, +}; + extern const struct driver_info ax88172a_info; static const struct usb_device_id products [] = { @@ -1063,6 +1086,14 @@ static const struct usb_device_id products [] = { /* ASIX 88172a demo board */ USB_DEVICE(0x0b95, 0x172a), .driver_info = (unsigned long) &ax88172a_info, +}, { + /* + * USBLINK HG20F9 "USB 2.0 LAN" + * Appears to have gazumped Linksys's manufacturer ID but + * doesn't (yet) conflict with any known Linksys product. + */ + USB_DEVICE(0x066b, 0x20f9), + .driver_info = (unsigned long) &hg20f9_info, }, { }, // END }; -- cgit v0.10.2 From a3d63cadbad97671d740a9698acc2c95d1ca6e79 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 22 Feb 2013 21:09:17 +0100 Subject: ath9k: fix RSSI dummy marker value RSSI is being stored internally as s8 in several places. The indication of an unset RSSI value, ATH_RSSI_DUMMY_MARKER, was supposed to have been set to 127, but ended up being set to 0x127 because of a code cleanup mistake. This could lead to invalid signal strength values in a few places. Signed-off-by: Felix Fietkau Cc: stable@vger.kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 5f845be..050ca4a 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -27,7 +27,7 @@ #define WME_MAX_BA WME_BA_BMP_SIZE #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) -#define ATH_RSSI_DUMMY_MARKER 0x127 +#define ATH_RSSI_DUMMY_MARKER 127 #define ATH_RSSI_LPF_LEN 10 #define RSSI_LPF_THRESHOLD -20 #define ATH_RSSI_EP_MULTIPLIER (1<<7) -- cgit v0.10.2 From 838f427955dcfd16858b0108ce29029da0d56a4e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 22 Feb 2013 21:37:25 +0100 Subject: ath9k_htc: fix signal strength handling issues The ath9k commit 2ef167557c0a26c88162ecffb017bfcc51eb7b29 (ath9k: fix signal strength reporting issues) fixed an issue where the reported per-frame signal strength reported to mac80211 was being overwritten with an internal average. The same issue is also present in ath9k_htc. In addition to preventing the driver from overwriting the value, this commit also ensures that the internal average (which is used for ANI) only tracks beacons of the AP that we're connected to. Signed-off-by: Felix Fietkau Cc: stable@vger.kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 96bfb18..d3b099d 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index b6a5a08..8788621 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -1067,15 +1067,19 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, last_rssi = priv->rx.last_rssi; - if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi, - ATH_RSSI_EP_MULTIPLIER); + if (ieee80211_is_beacon(hdr->frame_control) && + !is_zero_ether_addr(common->curbssid) && + ether_addr_equal(hdr->addr3, common->curbssid)) { + s8 rssi = rxbuf->rxstatus.rs_rssi; - if (rxbuf->rxstatus.rs_rssi < 0) - rxbuf->rxstatus.rs_rssi = 0; + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) + rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); - if (ieee80211_is_beacon(fc)) - priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi; + if (rssi < 0) + rssi = 0; + + priv->ah->stats.avgbrssi = rssi; + } rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp); rx_status->band = hw->conf.channel->band; -- cgit v0.10.2 From f45dd363bee071a62e32398a0ae4a0214b8029eb Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 23 Feb 2013 23:30:22 +0100 Subject: bcma: init spin lock This spin lock was not initialized. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c index 221f8bb..25de387 100644 --- a/drivers/bcma/driver_pci_host.c +++ b/drivers/bcma/driver_pci_host.c @@ -405,6 +405,8 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) return; } + spin_lock_init(&pc_host->cfgspace_lock); + pc->host_controller = pc_host; pc_host->pci_controller.io_resource = &pc_host->io_resource; pc_host->pci_controller.mem_resource = &pc_host->mem_resource; -- cgit v0.10.2 From 3412f2f086ea7531378fabe756bd4a1109994ae6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 25 Feb 2013 20:51:07 +0100 Subject: ath9k_hw: improve reset reliability after errors On many different chips, important aspects of the MAC state are not fully cleared by a warm reset. This can show up as tx/rx hangs, those annoying "DMA failed to stop in 10 ms..." messages or other quirks. On AR933x, the chip can occasionally get stuck in a way that only a driver unload/reload or a reboot would bring it back to life. With this patch, a full reset is issued when bringing the chip out of FULL-SLEEP state (after idle), or if either Rx or Tx was not shut down properly. This makes the DMA related error messages disappear completely in my tests on AR933x, and the chip does not get stuck anymore. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 42cf3c7..7b485e4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1463,7 +1463,9 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah, reset_type = ATH9K_RESET_POWER_ON; else reset_type = ATH9K_RESET_COLD; - } + } else if (ah->chip_fullsleep || REG_READ(ah, AR_Q_TXE) || + (REG_READ(ah, AR_CR) & AR_CR_RXE)) + reset_type = ATH9K_RESET_COLD; if (!ath9k_hw_set_reset_reg(ah, reset_type)) return false; -- cgit v0.10.2 From 3e7a4ff7c5b6423ddb644df9c41b8b6d2fb79d30 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 25 Feb 2013 16:01:34 -0800 Subject: mwifiex: correct sleep delay counter Maximum delay for waking up card is 50 ms. Because of typo in counter, this delay goes to 500ms. This patch fixes the bug. Cc: # 3.2+ Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 35c7972..5c395e2 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -302,7 +302,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) i++; usleep_range(10, 20); /* 50ms max wait */ - if (i == 50000) + if (i == 5000) break; } -- cgit v0.10.2 From 6ef9e2f6d12ce9e2120916804d2ddd46b954a70b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 26 Feb 2013 16:09:55 +0100 Subject: rt2x00: error in configurations with mesh support disabled If CONFIG_MAC80211_MESH is not set, cfg80211 will now allow advertising interface combinations with NL80211_IFTYPE_MESH_POINT present. Add appropriate ifdefs to avoid running into errors. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 1031db6..189744d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1236,8 +1236,10 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev) */ if_limit = &rt2x00dev->if_limits_ap; if_limit->max = rt2x00dev->ops->max_ap_intf; - if_limit->types = BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_MESH_POINT); + if_limit->types = BIT(NL80211_IFTYPE_AP); +#ifdef CONFIG_MAC80211_MESH + if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT); +#endif /* * Build up AP interface combinations structure. @@ -1309,7 +1311,9 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | +#endif BIT(NL80211_IFTYPE_WDS); rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; -- cgit v0.10.2 From 466026989f112e0546ca39ab00a759af82dbe83a Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 26 Feb 2013 12:58:35 -0800 Subject: libertas: fix crash for SD8688 For SD8688, FUNC_INIT command is queued before fw_ready flag is set. This causes the following crash as lbs_thread blocks any command if fw_ready is not set. [ 209.338953] [] (__schedule+0x610/0x764) from [] (__lbs_cmd+0xb8/0x130 [libertas]) [ 209.348340] [] (__lbs_cmd+0xb8/0x130 [libertas]) from [] (if_sdio_finish_power_on+0xec/0x1b0 [libertas_sdio]) [ 209.360136] [] (if_sdio_finish_power_on+0xec/0x1b0 [libertas_sdio]) from [] (if_sdio_power_on+0x18c/0x20c [libertas_sdio]) [ 209.373052] [] (if_sdio_power_on+0x18c/0x20c [libertas_sdio]) from [] (if_sdio_probe+0x200/0x31c [libertas_sdio]) [ 209.385316] [] (if_sdio_probe+0x200/0x31c [libertas_sdio]) from [] (sdio_bus_probe+0x94/0xfc [mmc_core]) [ 209.396748] [] (sdio_bus_probe+0x94/0xfc [mmc_core]) from [] (driver_probe_device+0x12c/0x348) [ 209.407214] [] (driver_probe_device+0x12c/0x348) from [] (__driver_attach+0x78/0x9c) [ 209.416798] [] (__driver_attach+0x78/0x9c) from [] (bus_for_each_dev+0x50/0x88) [ 209.425946] [] (bus_for_each_dev+0x50/0x88) from [] (bus_add_driver+0x108/0x268) [ 209.435180] [] (bus_add_driver+0x108/0x268) from [] (driver_register+0xa4/0x134) [ 209.444426] [] (driver_register+0xa4/0x134) from [] (if_sdio_init_module+0x1c/0x3c [libertas_sdio]) [ 209.455339] [] (if_sdio_init_module+0x1c/0x3c [libertas_sdio]) from [] (do_one_initcall+0x98/0x174) [ 209.466236] [] (do_one_initcall+0x98/0x174) from [] (load_module+0x1c5c/0x1f80) [ 209.475390] [] (load_module+0x1c5c/0x1f80) from [] (sys_init_module+0x104/0x128) [ 209.484632] [] (sys_init_module+0x104/0x128) from [] (ret_fast_syscall+0x0/0x38) Fix it by setting fw_ready flag prior to queuing FUNC_INIT command. Cc: # 3.5+ Reported-by: Lubomir Rintel Tested-by: Lubomir Rintel Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 739309e..4557833 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -825,6 +825,11 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card) sdio_release_host(func); + /* Set fw_ready before queuing any commands so that + * lbs_thread won't block from sending them to firmware. + */ + priv->fw_ready = 1; + /* * FUNC_INIT is required for SD8688 WLAN/BT multiple functions */ @@ -839,7 +844,6 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card) netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n"); } - priv->fw_ready = 1; wake_up(&card->pwron_waitq); if (!card->started) { -- cgit v0.10.2 From 726bc6b092da4c093eb74d13c07184b18c1af0f1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 27 Feb 2013 10:57:31 +0000 Subject: net/sctp: Validate parameter size for SCTP_GET_ASSOC_STATS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building sctp may fail with: In function ‘copy_from_user’, inlined from ‘sctp_getsockopt_assoc_stats’ at net/sctp/socket.c:5656:20: arch/x86/include/asm/uaccess_32.h:211:26: error: call to ‘copy_from_user_overflow’ declared with attribute error: copy_from_user() buffer size is not provably correct if built with W=1 due to a missing parameter size validation before the call to copy_from_user. Signed-off-by: Guenter Roeck Acked-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/net/sctp/socket.c b/net/sctp/socket.c index cedd9bf..9ef5c73 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5653,6 +5653,9 @@ static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, if (len < sizeof(sctp_assoc_t)) return -EINVAL; + /* Allow the struct to grow and fill in as much as possible */ + len = min_t(size_t, len, sizeof(sas)); + if (copy_from_user(&sas, optval, len)) return -EFAULT; @@ -5686,9 +5689,6 @@ static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, /* Mark beginning of a new observation period */ asoc->stats.max_obs_rto = asoc->rto_min; - /* Allow the struct to grow and fill in as much as possible */ - len = min_t(size_t, len, sizeof(sas)); - if (put_user(len, optlen)) return -EFAULT; -- cgit v0.10.2 From 51acbcec6c42b24482bac18e42befc822524535d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 28 Feb 2013 09:08:34 +1100 Subject: md: remove CONFIG_MULTICORE_RAID456 This doesn't seem to actually help and we have an alternate multi-threading approach waiting in the wings, so just get rid of this config option and associated code. As a bonus, we remove one use of CONFIG_EXPERIMENTAL Cc: Dan Williams Cc: Kees Cook Signed-off-by: NeilBrown diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 91a02ee..9a10313 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -154,17 +154,6 @@ config MD_RAID456 If unsure, say Y. -config MULTICORE_RAID456 - bool "RAID-4/RAID-5/RAID-6 Multicore processing (EXPERIMENTAL)" - depends on MD_RAID456 - depends on SMP - depends on EXPERIMENTAL - ---help--- - Enable the raid456 module to dispatch per-stripe raid operations to a - thread pool. - - If unsure, say N. - config MD_MULTIPATH tristate "Multipath I/O support" depends on BLK_DEV_MD diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 19d77a0..35031c8 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1406,7 +1406,7 @@ static void ops_run_check_pq(struct stripe_head *sh, struct raid5_percpu *percpu &sh->ops.zero_sum_result, percpu->spare_page, &submit); } -static void __raid_run_ops(struct stripe_head *sh, unsigned long ops_request) +static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) { int overlap_clear = 0, i, disks = sh->disks; struct dma_async_tx_descriptor *tx = NULL; @@ -1471,36 +1471,6 @@ static void __raid_run_ops(struct stripe_head *sh, unsigned long ops_request) put_cpu(); } -#ifdef CONFIG_MULTICORE_RAID456 -static void async_run_ops(void *param, async_cookie_t cookie) -{ - struct stripe_head *sh = param; - unsigned long ops_request = sh->ops.request; - - clear_bit_unlock(STRIPE_OPS_REQ_PENDING, &sh->state); - wake_up(&sh->ops.wait_for_ops); - - __raid_run_ops(sh, ops_request); - release_stripe(sh); -} - -static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) -{ - /* since handle_stripe can be called outside of raid5d context - * we need to ensure sh->ops.request is de-staged before another - * request arrives - */ - wait_event(sh->ops.wait_for_ops, - !test_and_set_bit_lock(STRIPE_OPS_REQ_PENDING, &sh->state)); - sh->ops.request = ops_request; - - atomic_inc(&sh->count); - async_schedule(async_run_ops, sh); -} -#else -#define raid_run_ops __raid_run_ops -#endif - static int grow_one_stripe(struct r5conf *conf) { struct stripe_head *sh; @@ -1509,9 +1479,6 @@ static int grow_one_stripe(struct r5conf *conf) return 0; sh->raid_conf = conf; - #ifdef CONFIG_MULTICORE_RAID456 - init_waitqueue_head(&sh->ops.wait_for_ops); - #endif spin_lock_init(&sh->stripe_lock); @@ -1630,9 +1597,6 @@ static int resize_stripes(struct r5conf *conf, int newsize) break; nsh->raid_conf = conf; - #ifdef CONFIG_MULTICORE_RAID456 - init_waitqueue_head(&nsh->ops.wait_for_ops); - #endif spin_lock_init(&nsh->stripe_lock); list_add(&nsh->lru, &newstripes); -- cgit v0.10.2 From f3378b48705154b9089affb2d2e939622aea68f1 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 28 Feb 2013 11:59:03 +1100 Subject: md: expedite metadata update when switching read-auto -> active If something has failed while the array was read-auto, then when we switch to 'active' we need to update the metadata. This will happen anyway but it is good to expedite it, and also to ensure any failed device has been released by the underlying device before we try to action the ioctl which caused us to switch to 'active' mode. Reported-by: Joe Lawrence Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index f363135..fcb878f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6532,7 +6532,17 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, mddev->ro = 0; sysfs_notify_dirent_safe(mddev->sysfs_state); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); - md_wakeup_thread(mddev->thread); + /* mddev_unlock will wake thread */ + /* If a device failed while we were read-only, we + * need to make sure the metadata is updated now. + */ + if (test_bit(MD_CHANGE_DEVS, &mddev->flags)) { + mddev_unlock(mddev); + wait_event(mddev->sb_wait, + !test_bit(MD_CHANGE_DEVS, &mddev->flags) && + !test_bit(MD_CHANGE_PENDING, &mddev->flags)); + mddev_lock(mddev); + } } else { err = -EROFS; goto abort_unlock; -- cgit v0.10.2 From 4cd5d1115c2f752ca94a0eb461b36d88fb37ed1e Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 28 Feb 2013 20:00:43 +0100 Subject: irq: Don't re-enable interrupts at the end of irq_exit Commit 74eed0163d0def3fce27228d9ccf3d36e207b286 "irq: Ensure irq_exit() code runs with interrupts disabled" restore interrupts flags in the end of irq_exit() for archs that don't define __ARCH_IRQ_EXIT_IRQS_DISABLED. However always returning from irq_exit() with interrupts disabled should not be a problem for these archs. Prior to this commit this was already happening anytime we processed pending softirqs anyway. Suggested-by: Linus Torvalds Signed-off-by: Frederic Weisbecker Cc: Linus Torvalds Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Paul E. McKenney diff --git a/kernel/softirq.c b/kernel/softirq.c index f42ff97..dce38fa 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -334,9 +334,7 @@ static inline void invoke_softirq(void) void irq_exit(void) { #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED - unsigned long flags; - - local_irq_save(flags); + local_irq_disable(); #else WARN_ON_ONCE(!irqs_disabled()); #endif @@ -353,9 +351,6 @@ void irq_exit(void) tick_nohz_irq_exit(); #endif rcu_irq_exit(); -#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED - local_irq_restore(flags); -#endif } /* -- cgit v0.10.2 From 70fc69bc5a54d9776ace7c99d46eb533f8fb6e89 Mon Sep 17 00:00:00 2001 From: "Lee A. Roberts" Date: Thu, 28 Feb 2013 04:37:27 +0000 Subject: sctp: fix association hangs due to off-by-one errors in sctp_tsnmap_grow() In sctp_tsnmap_mark(), correct off-by-one error when calculating size value for sctp_tsnmap_grow(). In sctp_tsnmap_grow(), correct off-by-one error when copying and resizing the tsnmap. If max_tsn_seen is in the LSB of the word, this bit can be lost, causing the corresponding packet to be transmitted again and to be entered as a duplicate into the SCTP reassembly/ordering queues. Change parameter name from "gap" (zero-based index) to "size" (one-based) to enhance code readability. Signed-off-by: Lee A. Roberts Acked-by: Vlad Yasevich Acked-by: Neil Horman diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c index 5f25e0c..396c451 100644 --- a/net/sctp/tsnmap.c +++ b/net/sctp/tsnmap.c @@ -51,7 +51,7 @@ static void sctp_tsnmap_update(struct sctp_tsnmap *map); static void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off, __u16 len, __u16 *start, __u16 *end); -static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 gap); +static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size); /* Initialize a block of memory as a tsnmap. */ struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len, @@ -124,7 +124,7 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn, gap = tsn - map->base_tsn; - if (gap >= map->len && !sctp_tsnmap_grow(map, gap)) + if (gap >= map->len && !sctp_tsnmap_grow(map, gap + 1)) return -ENOMEM; if (!sctp_tsnmap_has_gap(map) && gap == 0) { @@ -360,23 +360,24 @@ __u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map, return ngaps; } -static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 gap) +static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size) { unsigned long *new; unsigned long inc; u16 len; - if (gap >= SCTP_TSN_MAP_SIZE) + if (size > SCTP_TSN_MAP_SIZE) return 0; - inc = ALIGN((gap - map->len),BITS_PER_LONG) + SCTP_TSN_MAP_INCREMENT; + inc = ALIGN((size - map->len), BITS_PER_LONG) + SCTP_TSN_MAP_INCREMENT; len = min_t(u16, map->len + inc, SCTP_TSN_MAP_SIZE); new = kzalloc(len>>3, GFP_ATOMIC); if (!new) return 0; - bitmap_copy(new, map->tsn_map, map->max_tsn_seen - map->base_tsn); + bitmap_copy(new, map->tsn_map, + map->max_tsn_seen - map->cumulative_tsn_ack_point); kfree(map->tsn_map); map->tsn_map = new; map->len = len; -- cgit v0.10.2 From e67f85ecd83de66d4f25f2e0f90bb0d01a52ddd8 Mon Sep 17 00:00:00 2001 From: "Lee A. Roberts" Date: Thu, 28 Feb 2013 04:37:28 +0000 Subject: sctp: fix association hangs due to reneging packets below the cumulative TSN ACK point In sctp_ulpq_renege_list(), do not renege packets below the cumulative TSN ACK point. Signed-off-by: Lee A. Roberts Acked-by: Vlad Yasevich Acked-by: Neil Horman diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index ada1746..63afddc 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -969,11 +969,16 @@ static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq, tsnmap = &ulpq->asoc->peer.tsn_map; - while ((skb = __skb_dequeue_tail(list)) != NULL) { - freed += skb_headlen(skb); + while ((skb = skb_peek_tail(list)) != NULL) { event = sctp_skb2event(skb); tsn = event->tsn; + /* Don't renege below the Cumulative TSN ACK Point. */ + if (TSN_lte(tsn, sctp_tsnmap_get_ctsn(tsnmap))) + break; + + __skb_unlink(skb, list); + freed += skb_headlen(skb); sctp_ulpevent_free(event); sctp_tsnmap_renege(tsnmap, tsn); if (freed >= needed) -- cgit v0.10.2 From 95ac7b859f508b1b3e6adf7dce307864e4384a69 Mon Sep 17 00:00:00 2001 From: "Lee A. Roberts" Date: Thu, 28 Feb 2013 04:37:29 +0000 Subject: sctp: fix association hangs due to errors when reneging events from the ordering queue In sctp_ulpq_renege_list(), events being reneged from the ordering queue may correspond to multiple TSNs. Identify all affected packets; sum freed space and renege from the tsnmap. Signed-off-by: Lee A. Roberts Acked-by: Vlad Yasevich Acked-by: Neil Horman diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 63afddc..f221fbb 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -962,8 +962,8 @@ static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq, struct sk_buff_head *list, __u16 needed) { __u16 freed = 0; - __u32 tsn; - struct sk_buff *skb; + __u32 tsn, last_tsn; + struct sk_buff *skb, *flist, *last; struct sctp_ulpevent *event; struct sctp_tsnmap *tsnmap; @@ -977,10 +977,28 @@ static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq, if (TSN_lte(tsn, sctp_tsnmap_get_ctsn(tsnmap))) break; - __skb_unlink(skb, list); + /* Events in ordering queue may have multiple fragments + * corresponding to additional TSNs. Sum the total + * freed space; find the last TSN. + */ freed += skb_headlen(skb); + flist = skb_shinfo(skb)->frag_list; + for (last = flist; flist; flist = flist->next) { + last = flist; + freed += skb_headlen(last); + } + if (last) + last_tsn = sctp_skb2event(last)->tsn; + else + last_tsn = tsn; + + /* Unlink the event, then renege all applicable TSNs. */ + __skb_unlink(skb, list); sctp_ulpevent_free(event); - sctp_tsnmap_renege(tsnmap, tsn); + while (TSN_lte(tsn, last_tsn)) { + sctp_tsnmap_renege(tsnmap, tsn); + tsn++; + } if (freed >= needed) return freed; } -- cgit v0.10.2 From d003b41b801124b96337973b01eada6a83673d23 Mon Sep 17 00:00:00 2001 From: "Lee A. Roberts" Date: Thu, 28 Feb 2013 04:37:30 +0000 Subject: sctp: fix association hangs due to partial delivery errors In sctp_ulpq_tail_data(), use return values 0,1 to indicate whether a complete event (with MSG_EOR set) was delivered. A return value of -ENOMEM continues to indicate an out-of-memory condition was encountered. In sctp_ulpq_retrieve_partial() and sctp_ulpq_retrieve_first(), correct message reassembly logic for SCTP partial delivery. Change logic to ensure that as much data as possible is sent with the initial partial delivery and that following partial deliveries contain all available data. In sctp_ulpq_partial_delivery(), attempt partial delivery only if the data on the head of the reassembly queue is at or before the cumulative TSN ACK point. In sctp_ulpq_renege(), use the modified return values from sctp_ulpq_tail_data() to choose whether to attempt partial delivery or to attempt to drain the reassembly queue as a means to reduce memory pressure. Remove call to sctp_tsnmap_mark(), as this is handled correctly in call to sctp_ulpq_tail_data(). Signed-off-by: Lee A. Roberts Acked-by: Vlad Yasevich Acked-by: Neil Horman diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index f221fbb..0fd5b3d 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -106,6 +106,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, { struct sk_buff_head temp; struct sctp_ulpevent *event; + int event_eor = 0; /* Create an event from the incoming chunk. */ event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp); @@ -127,10 +128,12 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, /* Send event to the ULP. 'event' is the sctp_ulpevent for * very first SKB on the 'temp' list. */ - if (event) + if (event) { + event_eor = (event->msg_flags & MSG_EOR) ? 1 : 0; sctp_ulpq_tail_event(ulpq, event); + } - return 0; + return event_eor; } /* Add a new event for propagation to the ULP. */ @@ -540,14 +543,19 @@ static struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq) ctsn = cevent->tsn; switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { + case SCTP_DATA_FIRST_FRAG: + if (!first_frag) + return NULL; + goto done; case SCTP_DATA_MIDDLE_FRAG: if (!first_frag) { first_frag = pos; next_tsn = ctsn + 1; last_frag = pos; - } else if (next_tsn == ctsn) + } else if (next_tsn == ctsn) { next_tsn++; - else + last_frag = pos; + } else goto done; break; case SCTP_DATA_LAST_FRAG: @@ -651,6 +659,14 @@ static struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq) } else goto done; break; + + case SCTP_DATA_LAST_FRAG: + if (!first_frag) + return NULL; + else + goto done; + break; + default: return NULL; } @@ -1025,16 +1041,28 @@ void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event; struct sctp_association *asoc; struct sctp_sock *sp; + __u32 ctsn; + struct sk_buff *skb; asoc = ulpq->asoc; sp = sctp_sk(asoc->base.sk); /* If the association is already in Partial Delivery mode - * we have noting to do. + * we have nothing to do. */ if (ulpq->pd_mode) return; + /* Data must be at or below the Cumulative TSN ACK Point to + * start partial delivery. + */ + skb = skb_peek(&asoc->ulpq.reasm); + if (skb != NULL) { + ctsn = sctp_skb2event(skb)->tsn; + if (!TSN_lte(ctsn, sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map))) + return; + } + /* If the user enabled fragment interleave socket option, * multiple associations can enter partial delivery. * Otherwise, we can only enter partial delivery if the @@ -1077,12 +1105,16 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, } /* If able to free enough room, accept this chunk. */ if (chunk && (freed >= needed)) { - __u32 tsn; - tsn = ntohl(chunk->subh.data_hdr->tsn); - sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport); - sctp_ulpq_tail_data(ulpq, chunk, gfp); - - sctp_ulpq_partial_delivery(ulpq, gfp); + int retval; + retval = sctp_ulpq_tail_data(ulpq, chunk, gfp); + /* + * Enter partial delivery if chunk has not been + * delivered; otherwise, drain the reassembly queue. + */ + if (retval <= 0) + sctp_ulpq_partial_delivery(ulpq, gfp); + else if (retval == 1) + sctp_ulpq_reasm_drain(ulpq); } sk_mem_reclaim(asoc->base.sk); -- cgit v0.10.2 From 79ffef1fe213851f44bfccf037170a140e929f85 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 Feb 2013 07:05:03 +0000 Subject: tcp: avoid wakeups for pure ACK TCP prequeue mechanism purpose is to let incoming packets being processed by the thread currently blocked in tcp_recvmsg(), instead of behalf of the softirq handler, to better adapt flow control on receiver host capacity to schedule the consumer. But in typical request/answer workloads, we send request, then block to receive the answer. And before the actual answer, TCP stack receives the ACK packets acknowledging the request. Processing pure ACK on behalf of the thread blocked in tcp_recvmsg() is a waste of resources, as thread has to immediately sleep again because it got no payload. This patch avoids the extra context switches and scheduler overhead. Before patch : a:~# echo 0 >/proc/sys/net/ipv4/tcp_low_latency a:~# perf stat ./super_netperf 300 -t TCP_RR -l 10 -H 7.7.7.84 -- -r 8k,8k 231676 Performance counter stats for './super_netperf 300 -t TCP_RR -l 10 -H 7.7.7.84 -- -r 8k,8k': 116251.501765 task-clock # 11.369 CPUs utilized 5,025,463 context-switches # 0.043 M/sec 1,074,511 CPU-migrations # 0.009 M/sec 216,923 page-faults # 0.002 M/sec 311,636,972,396 cycles # 2.681 GHz 260,507,138,069 stalled-cycles-frontend # 83.59% frontend cycles idle 155,590,092,840 stalled-cycles-backend # 49.93% backend cycles idle 100,101,255,411 instructions # 0.32 insns per cycle # 2.60 stalled cycles per insn 16,535,930,999 branches # 142.243 M/sec 646,483,591 branch-misses # 3.91% of all branches 10.225482774 seconds time elapsed After patch : a:~# echo 0 >/proc/sys/net/ipv4/tcp_low_latency a:~# perf stat ./super_netperf 300 -t TCP_RR -l 10 -H 7.7.7.84 -- -r 8k,8k 233297 Performance counter stats for './super_netperf 300 -t TCP_RR -l 10 -H 7.7.7.84 -- -r 8k,8k': 91084.870855 task-clock # 8.887 CPUs utilized 2,485,916 context-switches # 0.027 M/sec 815,520 CPU-migrations # 0.009 M/sec 216,932 page-faults # 0.002 M/sec 245,195,022,629 cycles # 2.692 GHz 202,635,777,041 stalled-cycles-frontend # 82.64% frontend cycles idle 124,280,372,407 stalled-cycles-backend # 50.69% backend cycles idle 83,457,289,618 instructions # 0.34 insns per cycle # 2.43 stalled cycles per insn 13,431,472,361 branches # 147.461 M/sec 504,470,665 branch-misses # 3.76% of all branches 10.249594448 seconds time elapsed Signed-off-by: Eric Dumazet Cc: Neal Cardwell Cc: Tom Herbert Cc: Yuchung Cheng Cc: Andi Kleen Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index 23f2e98..cf0694d 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1045,6 +1045,10 @@ static inline bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) if (sysctl_tcp_low_latency || !tp->ucopy.task) return false; + if (skb->len <= tcp_hdrlen(skb) && + skb_queue_len(&tp->ucopy.prequeue) == 0) + return false; + __skb_queue_tail(&tp->ucopy.prequeue, skb); tp->ucopy.memory += skb->truesize; if (tp->ucopy.memory > sk->sk_rcvbuf) { -- cgit v0.10.2 From faf1e7857a1b87cd8baf48c3e962142e21ad417c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Wed, 27 Feb 2013 13:01:57 +0000 Subject: r8169: honor jumbo settings when chipset is requested to start. Some hardware start settings implicitely assume an usual 1500 bytes mtu that can't be guaranteed because changes of mtu may be requested both before and after the hardware is started. Reported-by: Tomi Orava Signed-off-by: Francois Romieu Cc: Hayes Wang Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 8900398..28fb50a 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -4765,8 +4765,10 @@ static void rtl_hw_start_8168bb(struct rtl8169_private *tp) RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); - rtl_tx_performance_tweak(pdev, - (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN); + if (tp->dev->mtu <= ETH_DATA_LEN) { + rtl_tx_performance_tweak(pdev, (0x5 << MAX_READ_REQUEST_SHIFT) | + PCI_EXP_DEVCTL_NOSNOOP_EN); + } } static void rtl_hw_start_8168bef(struct rtl8169_private *tp) @@ -4789,7 +4791,8 @@ static void __rtl_hw_start_8168cp(struct rtl8169_private *tp) RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + if (tp->dev->mtu <= ETH_DATA_LEN) + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); rtl_disable_clock_request(pdev); @@ -4822,7 +4825,8 @@ static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp) RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + if (tp->dev->mtu <= ETH_DATA_LEN) + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); } @@ -4841,7 +4845,8 @@ static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp) RTL_W8(MaxTxPacketSize, TxPacketMax); - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + if (tp->dev->mtu <= ETH_DATA_LEN) + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); } @@ -4901,7 +4906,8 @@ static void rtl_hw_start_8168d(struct rtl8169_private *tp) RTL_W8(MaxTxPacketSize, TxPacketMax); - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + if (tp->dev->mtu <= ETH_DATA_LEN) + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); } @@ -4913,7 +4919,8 @@ static void rtl_hw_start_8168dp(struct rtl8169_private *tp) rtl_csi_access_enable_1(tp); - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + if (tp->dev->mtu <= ETH_DATA_LEN) + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); RTL_W8(MaxTxPacketSize, TxPacketMax); @@ -4972,7 +4979,8 @@ static void rtl_hw_start_8168e_1(struct rtl8169_private *tp) rtl_ephy_init(tp, e_info_8168e_1, ARRAY_SIZE(e_info_8168e_1)); - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + if (tp->dev->mtu <= ETH_DATA_LEN) + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); RTL_W8(MaxTxPacketSize, TxPacketMax); @@ -4998,7 +5006,8 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp) rtl_ephy_init(tp, e_info_8168e_2, ARRAY_SIZE(e_info_8168e_2)); - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + if (tp->dev->mtu <= ETH_DATA_LEN) + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); -- cgit v0.10.2 From 8ce7684533013d0a0dfbd627ed0430ecb0c82213 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 27 Feb 2013 13:06:44 +0000 Subject: bnx2x: Fix port identification for the 84834 Fix the "ethtool -p" for boards with BCM84834, by using LED4 of the PHY to toggle the link LED while keeping interrupt disabled to avoid NIG attentions, and at the end restore NIG to previous state. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 1663e0b..4719ab1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -10422,6 +10422,28 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED1_MASK, 0x0); + if (phy->type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) { + /* Disable MI_INT interrupt before setting LED4 + * source to constant off. + */ + if (REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + + params->port*4) & + NIG_MASK_MI_INT) { + params->link_flags |= + LINK_FLAGS_INT_DISABLED; + + bnx2x_bits_dis( + bp, + NIG_REG_MASK_INTERRUPT_PORT0 + + params->port*4, + NIG_MASK_MI_INT); + } + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_SIGNAL_MASK, + 0x0); + } } break; case LED_MODE_ON: @@ -10468,6 +10490,28 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED1_MASK, 0x20); + if (phy->type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) { + /* Disable MI_INT interrupt before setting LED4 + * source to constant on. + */ + if (REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + + params->port*4) & + NIG_MASK_MI_INT) { + params->link_flags |= + LINK_FLAGS_INT_DISABLED; + + bnx2x_bits_dis( + bp, + NIG_REG_MASK_INTERRUPT_PORT0 + + params->port*4, + NIG_MASK_MI_INT); + } + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_SIGNAL_MASK, + 0x20); + } } break; @@ -10532,6 +10576,22 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LINK_SIGNAL, val); + if (phy->type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) { + /* Restore LED4 source to external link, + * and re-enable interrupts. + */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_SIGNAL_MASK, + 0x40); + if (params->link_flags & + LINK_FLAGS_INT_DISABLED) { + bnx2x_link_int_enable(params); + params->link_flags &= + ~LINK_FLAGS_INT_DISABLED; + } + } } break; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h index d25c7d7..be5c195 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h @@ -307,7 +307,8 @@ struct link_params { struct bnx2x *bp; u16 req_fc_auto_adv; /* Should be set to TX / BOTH when req_flow_ctrl is set to AUTO */ - u16 rsrv1; + u16 link_flags; +#define LINK_FLAGS_INT_DISABLED (1<<0) u32 lfa_base; }; -- cgit v0.10.2 From be94bea753a4d5ac0982df07aaeaf0cb1f7554dd Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 27 Feb 2013 13:06:45 +0000 Subject: bnx2x: Fix KR2 link Fix KR2 link down problem after reboot when link speed is reconfigured via ethtool. Since 1G/10G support link speed were missing by default, 1G/10G link speed were not advertised. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 9a674b1..edfa67a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -281,6 +281,8 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->lp_advertising |= ADVERTISED_2500baseX_Full; if (status & LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE) cmd->lp_advertising |= ADVERTISED_10000baseT_Full; + if (status & LINK_STATUS_LINK_PARTNER_20GXFD_CAPABLE) + cmd->lp_advertising |= ADVERTISED_20000baseKR2_Full; } cmd->maxtxpkt = 0; @@ -463,6 +465,10 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ADVERTISED_10000baseKR_Full)) bp->link_params.speed_cap_mask[cfg_idx] |= PORT_HW_CFG_SPEED_CAPABILITY_D0_10G; + + if (cmd->advertising & ADVERTISED_20000baseKR2_Full) + bp->link_params.speed_cap_mask[cfg_idx] |= + PORT_HW_CFG_SPEED_CAPABILITY_D0_20G; } } else { /* forced speed */ /* advertise the requested speed and duplex if supported */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 4719ab1..bf69c53 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -11851,6 +11851,8 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port, phy->media_type = ETH_PHY_KR; phy->flags |= FLAGS_WC_DUAL_MODE; phy->supported &= (SUPPORTED_20000baseKR2_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE | SUPPORTED_Pause | -- cgit v0.10.2 From d521de04a73abb5e662c12eafa8c839aaaa6ae4f Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 27 Feb 2013 13:06:46 +0000 Subject: bnx2x: Fix KR2 work-around condition Fix condition typo for running KR2 work-around though it doesn't have real effect since the typo bits matched by chance. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index bf69c53..31c5787 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -13499,7 +13499,7 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars) struct bnx2x_phy *phy = ¶ms->phy[INT_PHY]; bnx2x_set_aer_mmd(params, phy); if ((phy->supported & SUPPORTED_20000baseKR2_Full) && - (phy->speed_cap_mask & SPEED_20000)) + (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)) bnx2x_check_kr2_wa(params, vars, phy); bnx2x_check_over_curr(params, vars); if (vars->rx_tx_asic_rst) -- cgit v0.10.2 From b2a431915d19893f047e0dd149d0c1b9d2a0b960 Mon Sep 17 00:00:00 2001 From: Petr Malat Date: Thu, 28 Feb 2013 01:01:52 +0000 Subject: phy: Fix phy_device_free memory leak Fix memory leak in phy_device_free() for the case when phy_device* returned by phy_device_create() is not registered in the system. Bug description: phy_device_create() sets name of kobject using dev_set_name(), which allocates memory using kvasprintf(), but this memory isn't freed if the underlying device isn't registered properly, because kobject_cleanup() is not called in that case. This can happen (and actually is happening on our machines) if phy_device_register(), called by mdiobus_scan(), fails. Patch description: Embedded struct device is initialized in phy_device_create() and it counterpart phy_device_free() just drops one reference to the device, which leads to proper deinitialization including releasing the kobject name memory. Signed-off-by: Petr Malat Signed-off-by: David S. Miller diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 9930f99..3657b4a 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -44,13 +44,13 @@ MODULE_LICENSE("GPL"); void phy_device_free(struct phy_device *phydev) { - kfree(phydev); + put_device(&phydev->dev); } EXPORT_SYMBOL(phy_device_free); static void phy_device_release(struct device *dev) { - phy_device_free(to_phy_device(dev)); + kfree(to_phy_device(dev)); } static struct phy_driver genphy_driver; @@ -201,6 +201,8 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, there's no driver _already_ loaded. */ request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id)); + device_initialize(&dev->dev); + return dev; } EXPORT_SYMBOL(phy_device_create); @@ -363,9 +365,9 @@ int phy_device_register(struct phy_device *phydev) /* Run all of the fixups for this PHY */ phy_scan_fixups(phydev); - err = device_register(&phydev->dev); + err = device_add(&phydev->dev); if (err) { - pr_err("phy %d failed to register\n", phydev->addr); + pr_err("PHY %d failed to add\n", phydev->addr); goto out; } -- cgit v0.10.2 From 02e711276d444343656c25b91b42996c62726712 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 28 Feb 2013 07:16:54 +0000 Subject: bgmac: omit the fcs Do not include the frame check sequence when adding the skb to netif_receive_skb(). This causes problems when this interface was bridged to a wifi ap and a big package should be forwarded from this Ethernet driver through a bride to the wifi client. Signed-off-by: Hauke Mehrtens Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index bf985c0..bce30e7 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -301,12 +301,16 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n", ring->start); } else { + /* Omit CRC. */ + len -= ETH_FCS_LEN; + new_skb = netdev_alloc_skb_ip_align(bgmac->net_dev, len); if (new_skb) { skb_put(new_skb, len); skb_copy_from_linear_data_offset(skb, BGMAC_RX_FRAME_OFFSET, new_skb->data, len); + skb_checksum_none_assert(skb); new_skb->protocol = eth_type_trans(new_skb, bgmac->net_dev); netif_receive_skb(new_skb); -- cgit v0.10.2 From 32fcafbcd1c9f6c7013016a22a5369b4acb93577 Mon Sep 17 00:00:00 2001 From: Vlastimil Kosar Date: Thu, 28 Feb 2013 08:45:22 +0000 Subject: net/phy: micrel: Disable asymmetric pause for KSZ9021 Phyter KSZ9021 has hardware bug. If asymmetric pause is enabled, then it is necessary to disconnect and then reconnect the ethernet cable to get the phyter working. The solution is to disable the asymmetric pause. Signed-off-by: Vlastimil Kosar Signed-off-by: David S. Miller diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2993444..abf7b61 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -257,8 +257,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id = PHY_ID_KSZ9021, .phy_id_mask = 0x000ffffe, .name = "Micrel KSZ9021 Gigabit PHY", - .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause - | SUPPORTED_Asym_Pause), + .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, -- cgit v0.10.2 From 8b82547e33e85fc24d4d172a93c796de1fefa81a Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 1 Mar 2013 05:02:02 +0000 Subject: l2tp: Restore socket refcount when sendmsg succeeds The sendmsg() syscall handler for PPPoL2TP doesn't decrease the socket reference counter after successful transmissions. Any successful sendmsg() call from userspace will then increase the reference counter forever, thus preventing the kernel's session and tunnel data from being freed later on. The problem only happens when writing directly on L2TP sockets. PPP sockets attached to L2TP are unaffected as the PPP subsystem uses pppol2tp_xmit() which symmetrically increase/decrease reference counters. This patch adds the missing call to sock_put() before returning from pppol2tp_sendmsg(). Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 3f4e3af..6a53371 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -355,6 +355,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh l2tp_xmit_skb(session, skb, session->hdr_len); sock_put(ps->tunnel_sock); + sock_put(sk); return error; -- cgit v0.10.2 From d8c6f4b9b7848bca8babfc0ae43a50c8ab22fbb9 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 1 Mar 2013 07:44:08 +0000 Subject: ipv[4|6]: correct dropwatch false positive in local_deliver_finish I had a report recently of a user trying to use dropwatch to localise some frame loss, and they were getting false positives. Turned out they were using a user space SCTP stack that used raw sockets to grab frames. When we don't have a registered protocol for a given packet, we record it as a drop, even if a raw socket receieves the frame. We should only record the drop in the event a raw socket doesnt exist to receive the frames Tested by the reported successfully Signed-off-by: Neil Horman Reported-by: William Reich Tested-by: William Reich CC: "David S. Miller" CC: William Reich CC: eric.dumazet@gmail.com Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 87abd3e..2bdf802 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -228,9 +228,11 @@ static int ip_local_deliver_finish(struct sk_buff *skb) icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); } - } else + kfree_skb(skb); + } else { IP_INC_STATS_BH(net, IPSTATS_MIB_INDELIVERS); - kfree_skb(skb); + consume_skb(skb); + } } } out: diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 5b10414..b1876e5 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -241,9 +241,11 @@ resubmit: icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_UNK_NEXTHDR, nhoff); } - } else + kfree_skb(skb); + } else { IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); - kfree_skb(skb); + consume_skb(skb); + } } rcu_read_unlock(); return 0; -- cgit v0.10.2 From 81ce0dbc119fa31af21d02febde1cf923022d4d6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 28 Feb 2013 19:27:43 +0000 Subject: sctp: use the passed in gfp flags instead GFP_KERNEL This patch doesn't change how the code works because in the current kernel gfp is always GFP_KERNEL. But gfp was obviously intended instead of GFP_KERNEL. Signed-off-by: Dan Carpenter Acked-by: Neil Horman Signed-off-by: David S. Miller diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 73aad3d..9a680c0 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -155,7 +155,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, /* SCTP-AUTH extensions*/ INIT_LIST_HEAD(&ep->endpoint_shared_keys); - null_key = sctp_auth_shkey_create(0, GFP_KERNEL); + null_key = sctp_auth_shkey_create(0, gfp); if (!null_key) goto nomem; -- cgit v0.10.2 From bcabdef12da49878789464ad7239e97d83ea5ef5 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 15 Feb 2013 14:46:14 +0900 Subject: gpiolib: check descriptors validity before use Some functions dereferenced their GPIO descriptor argument without checking its validity first, potentially leading to an oops when given an invalid argument. This patch also makes gpio_get_value() more resilient when given an invalid GPIO, returning 0 instead of silently crashing. Signed-off-by: Alexandre Courbot Cc: Ryan Mallon Signed-off-by: Grant Likely diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index fff9786..1a8a7a8 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -174,7 +174,7 @@ static int gpio_ensure_requested(struct gpio_desc *desc) /* caller holds gpio_lock *OR* gpio is marked as requested */ static struct gpio_chip *gpiod_to_chip(struct gpio_desc *desc) { - return desc->chip; + return desc ? desc->chip : NULL; } struct gpio_chip *gpio_to_chip(unsigned gpio) @@ -654,6 +654,11 @@ static ssize_t export_store(struct class *class, goto done; desc = gpio_to_desc(gpio); + /* reject invalid GPIOs */ + if (!desc) { + pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); + return -EINVAL; + } /* No extra locking here; FLAG_SYSFS just signifies that the * request and export were done by on behalf of userspace, so @@ -690,12 +695,14 @@ static ssize_t unexport_store(struct class *class, if (status < 0) goto done; - status = -EINVAL; - desc = gpio_to_desc(gpio); /* reject bogus commands (gpio_unexport ignores them) */ - if (!desc) - goto done; + if (!desc) { + pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); + return -EINVAL; + } + + status = -EINVAL; /* No extra locking here; FLAG_SYSFS just signifies that the * request and export were done by on behalf of userspace, so @@ -846,8 +853,10 @@ static int gpiod_export_link(struct device *dev, const char *name, { int status = -EINVAL; - if (!desc) - goto done; + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } mutex_lock(&sysfs_lock); @@ -865,7 +874,6 @@ static int gpiod_export_link(struct device *dev, const char *name, mutex_unlock(&sysfs_lock); -done: if (status) pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), status); @@ -896,8 +904,10 @@ static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) struct device *dev = NULL; int status = -EINVAL; - if (!desc) - goto done; + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } mutex_lock(&sysfs_lock); @@ -914,7 +924,6 @@ static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) unlock: mutex_unlock(&sysfs_lock); -done: if (status) pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), status); @@ -940,8 +949,8 @@ static void gpiod_unexport(struct gpio_desc *desc) struct device *dev = NULL; if (!desc) { - status = -EINVAL; - goto done; + pr_warn("%s: invalid GPIO\n", __func__); + return; } mutex_lock(&sysfs_lock); @@ -962,7 +971,7 @@ static void gpiod_unexport(struct gpio_desc *desc) device_unregister(dev); put_device(dev); } -done: + if (status) pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), status); @@ -1384,12 +1393,13 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) int status = -EPROBE_DEFER; unsigned long flags; - spin_lock_irqsave(&gpio_lock, flags); - if (!desc) { - status = -EINVAL; - goto done; + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; } + + spin_lock_irqsave(&gpio_lock, flags); + chip = desc->chip; if (chip == NULL) goto done; @@ -1432,8 +1442,7 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) done: if (status) pr_debug("_gpio_request: gpio-%d (%s) status %d\n", - desc ? desc_to_gpio(desc) : -1, - label ? : "?", status); + desc_to_gpio(desc), label ? : "?", status); spin_unlock_irqrestore(&gpio_lock, flags); return status; } @@ -1616,10 +1625,13 @@ static int gpiod_direction_input(struct gpio_desc *desc) int status = -EINVAL; int offset; + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + spin_lock_irqsave(&gpio_lock, flags); - if (!desc) - goto fail; chip = desc->chip; if (!chip || !chip->get || !chip->direction_input) goto fail; @@ -1655,13 +1667,9 @@ lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); - if (status) { - int gpio = -1; - if (desc) - gpio = desc_to_gpio(desc); - pr_debug("%s: gpio-%d status %d\n", - __func__, gpio, status); - } + if (status) + pr_debug("%s: gpio-%d status %d\n", __func__, + desc_to_gpio(desc), status); return status; } @@ -1678,6 +1686,11 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) int status = -EINVAL; int offset; + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + /* Open drain pin should not be driven to 1 */ if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) return gpiod_direction_input(desc); @@ -1688,8 +1701,6 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) spin_lock_irqsave(&gpio_lock, flags); - if (!desc) - goto fail; chip = desc->chip; if (!chip || !chip->set || !chip->direction_output) goto fail; @@ -1725,13 +1736,9 @@ lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); - if (status) { - int gpio = -1; - if (desc) - gpio = desc_to_gpio(desc); - pr_debug("%s: gpio-%d status %d\n", - __func__, gpio, status); - } + if (status) + pr_debug("%s: gpio-%d status %d\n", __func__, + desc_to_gpio(desc), status); return status; } @@ -1753,10 +1760,13 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) int status = -EINVAL; int offset; + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + spin_lock_irqsave(&gpio_lock, flags); - if (!desc) - goto fail; chip = desc->chip; if (!chip || !chip->set || !chip->set_debounce) goto fail; @@ -1776,13 +1786,9 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) fail: spin_unlock_irqrestore(&gpio_lock, flags); - if (status) { - int gpio = -1; - if (desc) - gpio = desc_to_gpio(desc); - pr_debug("%s: gpio-%d status %d\n", - __func__, gpio, status); - } + if (status) + pr_debug("%s: gpio-%d status %d\n", __func__, + desc_to_gpio(desc), status); return status; } @@ -1830,6 +1836,8 @@ static int gpiod_get_value(struct gpio_desc *desc) int value; int offset; + if (!desc) + return 0; chip = desc->chip; offset = gpio_chip_hwgpio(desc); /* Should be using gpio_get_value_cansleep() */ @@ -1912,6 +1920,8 @@ static void gpiod_set_value(struct gpio_desc *desc, int value) { struct gpio_chip *chip; + if (!desc) + return; chip = desc->chip; /* Should be using gpio_set_value_cansleep() */ WARN_ON(chip->can_sleep); @@ -1940,6 +1950,8 @@ EXPORT_SYMBOL_GPL(__gpio_set_value); */ static int gpiod_cansleep(struct gpio_desc *desc) { + if (!desc) + return 0; /* only call this on GPIOs that are valid! */ return desc->chip->can_sleep; } @@ -1964,6 +1976,8 @@ static int gpiod_to_irq(struct gpio_desc *desc) struct gpio_chip *chip; int offset; + if (!desc) + return -EINVAL; chip = desc->chip; offset = gpio_chip_hwgpio(desc); return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO; @@ -1987,6 +2001,8 @@ static int gpiod_get_value_cansleep(struct gpio_desc *desc) int offset; might_sleep_if(extra_checks); + if (!desc) + return 0; chip = desc->chip; offset = gpio_chip_hwgpio(desc); value = chip->get ? chip->get(chip, offset) : 0; @@ -2005,6 +2021,8 @@ static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) struct gpio_chip *chip; might_sleep_if(extra_checks); + if (!desc) + return; chip = desc->chip; trace_gpio_value(desc_to_gpio(desc), 0, value); if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) -- cgit v0.10.2 From def634338d3ffb32fbe9b0a2d70cc24ef909cd4f Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 15 Feb 2013 14:46:15 +0900 Subject: gpiolib: use const parameters when possible Constify descriptor parameter of gpiod_* functions for those that should obviously not modify it. This includes value or direction get, cansleep, and IRQ number query. Signed-off-by: Alexandre Courbot Signed-off-by: Grant Likely diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1a8a7a8..a33bfc2 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -88,13 +88,14 @@ static int gpiod_request(struct gpio_desc *desc, const char *label); static void gpiod_free(struct gpio_desc *desc); static int gpiod_direction_input(struct gpio_desc *desc); static int gpiod_direction_output(struct gpio_desc *desc, int value); +static int gpiod_get_direction(const struct gpio_desc *desc); static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); -static int gpiod_get_value_cansleep(struct gpio_desc *desc); +static int gpiod_get_value_cansleep(const struct gpio_desc *desc); static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); -static int gpiod_get_value(struct gpio_desc *desc); +static int gpiod_get_value(const struct gpio_desc *desc); static void gpiod_set_value(struct gpio_desc *desc, int value); -static int gpiod_cansleep(struct gpio_desc *desc); -static int gpiod_to_irq(struct gpio_desc *desc); +static int gpiod_cansleep(const struct gpio_desc *desc); +static int gpiod_to_irq(const struct gpio_desc *desc); static int gpiod_export(struct gpio_desc *desc, bool direction_may_change); static int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc); @@ -172,7 +173,7 @@ static int gpio_ensure_requested(struct gpio_desc *desc) } /* caller holds gpio_lock *OR* gpio is marked as requested */ -static struct gpio_chip *gpiod_to_chip(struct gpio_desc *desc) +static struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) { return desc ? desc->chip : NULL; } @@ -207,7 +208,7 @@ static int gpiochip_find_base(int ngpio) } /* caller ensures gpio is valid and requested, chip->get_direction may sleep */ -static int gpiod_get_direction(struct gpio_desc *desc) +static int gpiod_get_direction(const struct gpio_desc *desc) { struct gpio_chip *chip; unsigned offset; @@ -223,11 +224,13 @@ static int gpiod_get_direction(struct gpio_desc *desc) if (status > 0) { /* GPIOF_DIR_IN, or other positive */ status = 1; - clear_bit(FLAG_IS_OUT, &desc->flags); + /* FLAG_IS_OUT is just a cache of the result of get_direction(), + * so it does not affect constness per se */ + clear_bit(FLAG_IS_OUT, &((struct gpio_desc *)desc)->flags); } if (status == 0) { /* GPIOF_DIR_OUT */ - set_bit(FLAG_IS_OUT, &desc->flags); + set_bit(FLAG_IS_OUT, &((struct gpio_desc *)desc)->flags); } return status; } @@ -263,7 +266,7 @@ static DEFINE_MUTEX(sysfs_lock); static ssize_t gpio_direction_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct gpio_desc *desc = dev_get_drvdata(dev); + const struct gpio_desc *desc = dev_get_drvdata(dev); ssize_t status; mutex_lock(&sysfs_lock); @@ -1830,7 +1833,7 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce); * It returns the zero or nonzero value provided by the associated * gpio_chip.get() method; or zero if no such method is provided. */ -static int gpiod_get_value(struct gpio_desc *desc) +static int gpiod_get_value(const struct gpio_desc *desc) { struct gpio_chip *chip; int value; @@ -1948,7 +1951,7 @@ EXPORT_SYMBOL_GPL(__gpio_set_value); * This is used directly or indirectly to implement gpio_cansleep(). It * returns nonzero if access reading or writing the GPIO value can sleep. */ -static int gpiod_cansleep(struct gpio_desc *desc) +static int gpiod_cansleep(const struct gpio_desc *desc) { if (!desc) return 0; @@ -1971,7 +1974,7 @@ EXPORT_SYMBOL_GPL(__gpio_cansleep); * It returns the number of the IRQ signaled by this (input) GPIO, * or a negative errno. */ -static int gpiod_to_irq(struct gpio_desc *desc) +static int gpiod_to_irq(const struct gpio_desc *desc) { struct gpio_chip *chip; int offset; @@ -1994,7 +1997,7 @@ EXPORT_SYMBOL_GPL(__gpio_to_irq); * Common examples include ones connected to I2C or SPI chips. */ -static int gpiod_get_value_cansleep(struct gpio_desc *desc) +static int gpiod_get_value_cansleep(const struct gpio_desc *desc) { struct gpio_chip *chip; int value; -- cgit v0.10.2 From 24d7628fe8b10bb3770a11ddf71719613832a298 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 15 Feb 2013 14:46:16 +0900 Subject: gpiolib: move comment to right function This comment applies to gpio_to_chip(), not gpiod_to_chip(). Signed-off-by: Alexandre Courbot Signed-off-by: Grant Likely diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a33bfc2..c2534d6 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -172,12 +172,12 @@ static int gpio_ensure_requested(struct gpio_desc *desc) return 0; } -/* caller holds gpio_lock *OR* gpio is marked as requested */ static struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) { return desc ? desc->chip : NULL; } +/* caller holds gpio_lock *OR* gpio is marked as requested */ struct gpio_chip *gpio_to_chip(unsigned gpio) { return gpiod_to_chip(gpio_to_desc(gpio)); -- cgit v0.10.2 From e97f9b5277afeabb54892ebc6f68500098467ba1 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 27 Feb 2013 17:25:15 +0200 Subject: gpio/gpio-ich: fix ichx_gpio_check_available() return what callers expect ichx_gpio_check_available() returns either 0 or -ENXIO depending on whether the given GPIO is available or not. However, callers of this function treat the return value as boolean: ... if (!ichx_gpio_check_available(gpio, nr)) return -ENXIO; which erroneusly fails when the GPIO is available and not vice versa. Fix this by making the function return boolean as expected by the callers. Signed-off-by: Mika Westerberg Signed-off-by: Grant Likely diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 6f2306d..f9dbd50 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -128,9 +128,9 @@ static int ichx_read_bit(int reg, unsigned nr) return data & (1 << bit) ? 1 : 0; } -static int ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) +static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) { - return (ichx_priv.use_gpio & (1 << (nr / 32))) ? 0 : -ENXIO; + return ichx_priv.use_gpio & (1 << (nr / 32)); } static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) -- cgit v0.10.2 From e2ca90c276e1fc410d7cd3c1a4eee245ec902a20 Mon Sep 17 00:00:00 2001 From: Freddy Xin Date: Sat, 2 Mar 2013 00:41:11 +0000 Subject: ax88179_178a: ASIX AX88179_178A USB 3.0/2.0 to gigabit ethernet adapter driver This is a resubmission. Added kfree() in ax88179_get_eeprom to prevent memory leakage. Modified "__le16 rxctl" to "u16 rxctl" in "struct ax88179_data" and removed pointless casts. Removed asix_init and asix_exit functions and added "module_usb_driver(ax88179_178a_driver)". Fixed endianness issue on big endian systems and verified this driver on iBook G4. Removed steps that change net->features in ax88179_set_features function. Added "const" to ethtool_ops structure and fixed the coding style of AX88179_BULKIN_SIZE array. Fixed the issue that the default MTU is not 1500. Added ax88179_change_mtu function and enabled the hardware jumbo frame function to support an MTU higher than 1500. Fixed indentation and empty line coding style errors. The _nopm version usb functions were added to access register in suspend and resume functions. Serveral variables allocted dynamically were removed and replaced by stack variables. ax88179_get_eeprom were modified from asix_get_eeprom in asix_common. This patch adds a driver for ASIX's AX88179 family of USB 3.0/2.0 to gigabit ethernet adapters. It's based on the AX88xxx driver but the usb commands used to access registers for AX88179 are completely different. This driver had been verified on x86 system with AX88179/AX88178A and Sitcomm LN-032 USB dongles. Signed-off-by: Freddy Xin Signed-off-by: David S. Miller diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index da92ed3..3b6e9b8 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -156,6 +156,24 @@ config USB_NET_AX8817X This driver creates an interface named "ethX", where X depends on what other networking devices you have in use. +config USB_NET_AX88179_178A + tristate "ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet" + depends on USB_USBNET + select CRC32 + select PHYLIB + default y + help + This option adds support for ASIX AX88179 based USB 3.0/2.0 + to Gigabit Ethernet adapters. + + This driver should work with at least the following devices: + * ASIX AX88179 + * ASIX AX88178A + * Sitcomm LN-032 + + This driver creates an interface named "ethX", where X depends on + what other networking devices you have in use. + config USB_NET_CDCETHER tristate "CDC Ethernet support (smart devices such as cable modems)" depends on USB_USBNET diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index 4786913..119b06c 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_RTL8150) += rtl8150.o obj-$(CONFIG_USB_HSO) += hso.o obj-$(CONFIG_USB_NET_AX8817X) += asix.o asix-y := asix_devices.o asix_common.o ax88172a.o +obj-$(CONFIG_USB_NET_AX88179_178A) += ax88179_178a.o obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o obj-$(CONFIG_USB_NET_DM9601) += dm9601.o diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c new file mode 100644 index 0000000..71c27d8 --- /dev/null +++ b/drivers/net/usb/ax88179_178a.c @@ -0,0 +1,1448 @@ +/* + * ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet Devices + * + * Copyright (C) 2011-2013 ASIX + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include + +#define AX88179_PHY_ID 0x03 +#define AX_EEPROM_LEN 0x100 +#define AX88179_EEPROM_MAGIC 0x17900b95 +#define AX_MCAST_FLTSIZE 8 +#define AX_MAX_MCAST 64 +#define AX_INT_PPLS_LINK ((u32)BIT(16)) +#define AX_RXHDR_L4_TYPE_MASK 0x1c +#define AX_RXHDR_L4_TYPE_UDP 4 +#define AX_RXHDR_L4_TYPE_TCP 16 +#define AX_RXHDR_L3CSUM_ERR 2 +#define AX_RXHDR_L4CSUM_ERR 1 +#define AX_RXHDR_CRC_ERR ((u32)BIT(31)) +#define AX_RXHDR_DROP_ERR ((u32)BIT(30)) +#define AX_ACCESS_MAC 0x01 +#define AX_ACCESS_PHY 0x02 +#define AX_ACCESS_EEPROM 0x04 +#define AX_ACCESS_EFUS 0x05 +#define AX_PAUSE_WATERLVL_HIGH 0x54 +#define AX_PAUSE_WATERLVL_LOW 0x55 + +#define PHYSICAL_LINK_STATUS 0x02 + #define AX_USB_SS 0x04 + #define AX_USB_HS 0x02 + +#define GENERAL_STATUS 0x03 +/* Check AX88179 version. UA1:Bit2 = 0, UA2:Bit2 = 1 */ + #define AX_SECLD 0x04 + +#define AX_SROM_ADDR 0x07 +#define AX_SROM_CMD 0x0a + #define EEP_RD 0x04 + #define EEP_BUSY 0x10 + +#define AX_SROM_DATA_LOW 0x08 +#define AX_SROM_DATA_HIGH 0x09 + +#define AX_RX_CTL 0x0b + #define AX_RX_CTL_DROPCRCERR 0x0100 + #define AX_RX_CTL_IPE 0x0200 + #define AX_RX_CTL_START 0x0080 + #define AX_RX_CTL_AP 0x0020 + #define AX_RX_CTL_AM 0x0010 + #define AX_RX_CTL_AB 0x0008 + #define AX_RX_CTL_AMALL 0x0002 + #define AX_RX_CTL_PRO 0x0001 + #define AX_RX_CTL_STOP 0x0000 + +#define AX_NODE_ID 0x10 +#define AX_MULFLTARY 0x16 + +#define AX_MEDIUM_STATUS_MODE 0x22 + #define AX_MEDIUM_GIGAMODE 0x01 + #define AX_MEDIUM_FULL_DUPLEX 0x02 + #define AX_MEDIUM_ALWAYS_ONE 0x04 + #define AX_MEDIUM_EN_125MHZ 0x08 + #define AX_MEDIUM_RXFLOW_CTRLEN 0x10 + #define AX_MEDIUM_TXFLOW_CTRLEN 0x20 + #define AX_MEDIUM_RECEIVE_EN 0x100 + #define AX_MEDIUM_PS 0x200 + #define AX_MEDIUM_JUMBO_EN 0x8040 + +#define AX_MONITOR_MOD 0x24 + #define AX_MONITOR_MODE_RWLC 0x02 + #define AX_MONITOR_MODE_RWMP 0x04 + #define AX_MONITOR_MODE_PMEPOL 0x20 + #define AX_MONITOR_MODE_PMETYPE 0x40 + +#define AX_GPIO_CTRL 0x25 + #define AX_GPIO_CTRL_GPIO3EN 0x80 + #define AX_GPIO_CTRL_GPIO2EN 0x40 + #define AX_GPIO_CTRL_GPIO1EN 0x20 + +#define AX_PHYPWR_RSTCTL 0x26 + #define AX_PHYPWR_RSTCTL_BZ 0x0010 + #define AX_PHYPWR_RSTCTL_IPRL 0x0020 + #define AX_PHYPWR_RSTCTL_AT 0x1000 + +#define AX_RX_BULKIN_QCTRL 0x2e +#define AX_CLK_SELECT 0x33 + #define AX_CLK_SELECT_BCS 0x01 + #define AX_CLK_SELECT_ACS 0x02 + #define AX_CLK_SELECT_ULR 0x08 + +#define AX_RXCOE_CTL 0x34 + #define AX_RXCOE_IP 0x01 + #define AX_RXCOE_TCP 0x02 + #define AX_RXCOE_UDP 0x04 + #define AX_RXCOE_TCPV6 0x20 + #define AX_RXCOE_UDPV6 0x40 + +#define AX_TXCOE_CTL 0x35 + #define AX_TXCOE_IP 0x01 + #define AX_TXCOE_TCP 0x02 + #define AX_TXCOE_UDP 0x04 + #define AX_TXCOE_TCPV6 0x20 + #define AX_TXCOE_UDPV6 0x40 + +#define AX_LEDCTRL 0x73 + +#define GMII_PHY_PHYSR 0x11 + #define GMII_PHY_PHYSR_SMASK 0xc000 + #define GMII_PHY_PHYSR_GIGA 0x8000 + #define GMII_PHY_PHYSR_100 0x4000 + #define GMII_PHY_PHYSR_FULL 0x2000 + #define GMII_PHY_PHYSR_LINK 0x400 + +#define GMII_LED_ACT 0x1a + #define GMII_LED_ACTIVE_MASK 0xff8f + #define GMII_LED0_ACTIVE BIT(4) + #define GMII_LED1_ACTIVE BIT(5) + #define GMII_LED2_ACTIVE BIT(6) + +#define GMII_LED_LINK 0x1c + #define GMII_LED_LINK_MASK 0xf888 + #define GMII_LED0_LINK_10 BIT(0) + #define GMII_LED0_LINK_100 BIT(1) + #define GMII_LED0_LINK_1000 BIT(2) + #define GMII_LED1_LINK_10 BIT(4) + #define GMII_LED1_LINK_100 BIT(5) + #define GMII_LED1_LINK_1000 BIT(6) + #define GMII_LED2_LINK_10 BIT(8) + #define GMII_LED2_LINK_100 BIT(9) + #define GMII_LED2_LINK_1000 BIT(10) + #define LED0_ACTIVE BIT(0) + #define LED0_LINK_10 BIT(1) + #define LED0_LINK_100 BIT(2) + #define LED0_LINK_1000 BIT(3) + #define LED0_FD BIT(4) + #define LED0_USB3_MASK 0x001f + #define LED1_ACTIVE BIT(5) + #define LED1_LINK_10 BIT(6) + #define LED1_LINK_100 BIT(7) + #define LED1_LINK_1000 BIT(8) + #define LED1_FD BIT(9) + #define LED1_USB3_MASK 0x03e0 + #define LED2_ACTIVE BIT(10) + #define LED2_LINK_1000 BIT(13) + #define LED2_LINK_100 BIT(12) + #define LED2_LINK_10 BIT(11) + #define LED2_FD BIT(14) + #define LED_VALID BIT(15) + #define LED2_USB3_MASK 0x7c00 + +#define GMII_PHYPAGE 0x1e +#define GMII_PHY_PAGE_SELECT 0x1f + #define GMII_PHY_PGSEL_EXT 0x0007 + #define GMII_PHY_PGSEL_PAGE0 0x0000 + +struct ax88179_data { + u16 rxctl; + u16 reserved; +}; + +struct ax88179_int_data { + __le32 intdata1; + __le32 intdata2; +}; + +static const struct { + unsigned char ctrl, timer_l, timer_h, size, ifg; +} AX88179_BULKIN_SIZE[] = { + {7, 0x4f, 0, 0x12, 0xff}, + {7, 0x20, 3, 0x16, 0xff}, + {7, 0xae, 7, 0x18, 0xff}, + {7, 0xcc, 0x4c, 0x18, 8}, +}; + +static int __ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data, int in_pm) +{ + int ret; + int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16); + + BUG_ON(!dev); + + if (!in_pm) + fn = usbnet_read_cmd; + else + fn = usbnet_read_cmd_nopm; + + ret = fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, data, size); + + if (unlikely(ret < 0)) + netdev_warn(dev->net, "Failed to read reg index 0x%04x: %d\n", + index, ret); + + return ret; +} + +static int __ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data, int in_pm) +{ + int ret; + int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16); + + BUG_ON(!dev); + + if (!in_pm) + fn = usbnet_write_cmd; + else + fn = usbnet_write_cmd_nopm; + + ret = fn(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, data, size); + + if (unlikely(ret < 0)) + netdev_warn(dev->net, "Failed to write reg index 0x%04x: %d\n", + index, ret); + + return ret; +} + +static void ax88179_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, + u16 index, u16 size, void *data) +{ + u16 buf; + + if (2 == size) { + buf = *((u16 *)data); + cpu_to_le16s(&buf); + usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, &buf, + size); + } else { + usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, data, + size); + } +} + +static int ax88179_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, + u16 index, u16 size, void *data) +{ + int ret; + + if (2 == size) { + u16 buf; + ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1); + le16_to_cpus(&buf); + *((u16 *)data) = buf; + } else if (4 == size) { + u32 buf; + ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1); + le32_to_cpus(&buf); + *((u32 *)data) = buf; + } else { + ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 1); + } + + return ret; +} + +static int ax88179_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, + u16 index, u16 size, void *data) +{ + int ret; + + if (2 == size) { + u16 buf; + buf = *((u16 *)data); + cpu_to_le16s(&buf); + ret = __ax88179_write_cmd(dev, cmd, value, index, + size, &buf, 1); + } else { + ret = __ax88179_write_cmd(dev, cmd, value, index, + size, data, 1); + } + + return ret; +} + +static int ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + int ret; + + if (2 == size) { + u16 buf; + ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0); + le16_to_cpus(&buf); + *((u16 *)data) = buf; + } else if (4 == size) { + u32 buf; + ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0); + le32_to_cpus(&buf); + *((u32 *)data) = buf; + } else { + ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 0); + } + + return ret; +} + +static int ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + int ret; + + if (2 == size) { + u16 buf; + buf = *((u16 *)data); + cpu_to_le16s(&buf); + ret = __ax88179_write_cmd(dev, cmd, value, index, + size, &buf, 0); + } else { + ret = __ax88179_write_cmd(dev, cmd, value, index, + size, data, 0); + } + + return ret; +} + +static void ax88179_status(struct usbnet *dev, struct urb *urb) +{ + struct ax88179_int_data *event; + u32 link; + + if (urb->actual_length < 8) + return; + + event = urb->transfer_buffer; + le32_to_cpus((void *)&event->intdata1); + + link = (((__force u32)event->intdata1) & AX_INT_PPLS_LINK) >> 16; + + if (netif_carrier_ok(dev->net) != link) { + if (link) + usbnet_defer_kevent(dev, EVENT_LINK_RESET); + else + netif_carrier_off(dev->net); + + netdev_info(dev->net, "ax88179 - Link status is: %d\n", link); + } +} + +static int ax88179_mdio_read(struct net_device *netdev, int phy_id, int loc) +{ + struct usbnet *dev = netdev_priv(netdev); + u16 res; + + ax88179_read_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res); + return res; +} + +static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc, + int val) +{ + struct usbnet *dev = netdev_priv(netdev); + u16 res = (u16) val; + + ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res); +} + +static int ax88179_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct usbnet *dev = usb_get_intfdata(intf); + u16 tmp16; + u8 tmp8; + + usbnet_suspend(intf, message); + + /* Disable RX path */ + ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, &tmp16); + tmp16 &= ~AX_MEDIUM_RECEIVE_EN; + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, &tmp16); + + /* Force bulk-in zero length */ + ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, + 2, 2, &tmp16); + + tmp16 |= AX_PHYPWR_RSTCTL_BZ | AX_PHYPWR_RSTCTL_IPRL; + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, + 2, 2, &tmp16); + + /* change clock */ + tmp8 = 0; + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); + + /* Configure RX control register => stop operation */ + tmp16 = AX_RX_CTL_STOP; + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16); + + return 0; +} + +/* This function is used to enable the autodetach function. */ +/* This function is determined by offset 0x43 of EEPROM */ +static int ax88179_auto_detach(struct usbnet *dev, int in_pm) +{ + u16 tmp16; + u8 tmp8; + int (*fnr)(struct usbnet *, u8, u16, u16, u16, void *); + int (*fnw)(struct usbnet *, u8, u16, u16, u16, void *); + + if (!in_pm) { + fnr = ax88179_read_cmd; + fnw = ax88179_write_cmd; + } else { + fnr = ax88179_read_cmd_nopm; + fnw = ax88179_write_cmd_nopm; + } + + if (fnr(dev, AX_ACCESS_EEPROM, 0x43, 1, 2, &tmp16) < 0) + return 0; + + if ((tmp16 == 0xFFFF) || (!(tmp16 & 0x0100))) + return 0; + + /* Enable Auto Detach bit */ + tmp8 = 0; + fnr(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); + tmp8 |= AX_CLK_SELECT_ULR; + fnw(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); + + fnr(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16); + tmp16 |= AX_PHYPWR_RSTCTL_AT; + fnw(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16); + + return 0; +} + +static int ax88179_resume(struct usb_interface *intf) +{ + struct usbnet *dev = usb_get_intfdata(intf); + u16 tmp16; + u8 tmp8; + + netif_carrier_off(dev->net); + + /* Power up ethernet PHY */ + tmp16 = 0; + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, + 2, 2, &tmp16); + udelay(1000); + + tmp16 = AX_PHYPWR_RSTCTL_IPRL; + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, + 2, 2, &tmp16); + msleep(200); + + /* Ethernet PHY Auto Detach*/ + ax88179_auto_detach(dev, 1); + + /* Enable clock */ + ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); + tmp8 |= AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); + msleep(100); + + /* Configure RX control register => start operation */ + tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | + AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16); + + return usbnet_resume(intf); +} + +static void +ax88179_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +{ + struct usbnet *dev = netdev_priv(net); + u8 opt; + + if (ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, + 1, 1, &opt) < 0) { + wolinfo->supported = 0; + wolinfo->wolopts = 0; + return; + } + + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; + wolinfo->wolopts = 0; + if (opt & AX_MONITOR_MODE_RWLC) + wolinfo->wolopts |= WAKE_PHY; + if (opt & AX_MONITOR_MODE_RWMP) + wolinfo->wolopts |= WAKE_MAGIC; +} + +static int +ax88179_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +{ + struct usbnet *dev = netdev_priv(net); + u8 opt = 0; + + if (wolinfo->wolopts & WAKE_PHY) + opt |= AX_MONITOR_MODE_RWLC; + if (wolinfo->wolopts & WAKE_MAGIC) + opt |= AX_MONITOR_MODE_RWMP; + + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, + 1, 1, &opt) < 0) + return -EINVAL; + + return 0; +} + +static int ax88179_get_eeprom_len(struct net_device *net) +{ + return AX_EEPROM_LEN; +} + +static int +ax88179_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, + u8 *data) +{ + struct usbnet *dev = netdev_priv(net); + u16 *eeprom_buff; + int first_word, last_word; + int i, ret; + + if (eeprom->len == 0) + return -EINVAL; + + eeprom->magic = AX88179_EEPROM_MAGIC; + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), + GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + /* ax88179/178A returns 2 bytes from eeprom on read */ + for (i = first_word; i <= last_word; i++) { + ret = __ax88179_read_cmd(dev, AX_ACCESS_EEPROM, i, 1, 2, + &eeprom_buff[i - first_word], + 0); + if (ret < 0) { + kfree(eeprom_buff); + return -EIO; + } + } + + memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); + kfree(eeprom_buff); + return 0; +} + +static int ax88179_get_settings(struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + return mii_ethtool_gset(&dev->mii, cmd); +} + +static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + return mii_ethtool_sset(&dev->mii, cmd); +} + + +static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd) +{ + struct usbnet *dev = netdev_priv(net); + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +static const struct ethtool_ops ax88179_ethtool_ops = { + .get_link = ethtool_op_get_link, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_wol = ax88179_get_wol, + .set_wol = ax88179_set_wol, + .get_eeprom_len = ax88179_get_eeprom_len, + .get_eeprom = ax88179_get_eeprom, + .get_settings = ax88179_get_settings, + .set_settings = ax88179_set_settings, + .nway_reset = usbnet_nway_reset, +}; + +static void ax88179_set_multicast(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + struct ax88179_data *data = (struct ax88179_data *)dev->data; + u8 *m_filter = ((u8 *)dev->data) + 12; + + data->rxctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_CTL_IPE); + + if (net->flags & IFF_PROMISC) { + data->rxctl |= AX_RX_CTL_PRO; + } else if (net->flags & IFF_ALLMULTI || + netdev_mc_count(net) > AX_MAX_MCAST) { + data->rxctl |= AX_RX_CTL_AMALL; + } else if (netdev_mc_empty(net)) { + /* just broadcast and directed */ + } else { + /* We use the 20 byte dev->data for our 8 byte filter buffer + * to avoid allocating memory that is tricky to free later + */ + u32 crc_bits; + struct netdev_hw_addr *ha; + + memset(m_filter, 0, AX_MCAST_FLTSIZE); + + netdev_for_each_mc_addr(ha, net) { + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; + *(m_filter + (crc_bits >> 3)) |= (1 << (crc_bits & 7)); + } + + ax88179_write_cmd_async(dev, AX_ACCESS_MAC, AX_MULFLTARY, + AX_MCAST_FLTSIZE, AX_MCAST_FLTSIZE, + m_filter); + + data->rxctl |= AX_RX_CTL_AM; + } + + ax88179_write_cmd_async(dev, AX_ACCESS_MAC, AX_RX_CTL, + 2, 2, &data->rxctl); +} + +static int +ax88179_set_features(struct net_device *net, netdev_features_t features) +{ + u8 tmp; + struct usbnet *dev = netdev_priv(net); + netdev_features_t changed = net->features ^ features; + + if (changed & NETIF_F_IP_CSUM) { + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); + tmp ^= AX_TXCOE_TCP | AX_TXCOE_UDP; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); + } + + if (changed & NETIF_F_IPV6_CSUM) { + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); + tmp ^= AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); + } + + if (changed & NETIF_F_RXCSUM) { + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &tmp); + tmp ^= AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | + AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &tmp); + } + + return 0; +} + +static int ax88179_change_mtu(struct net_device *net, int new_mtu) +{ + struct usbnet *dev = netdev_priv(net); + u16 tmp16; + + if (new_mtu <= 0 || new_mtu > 4088) + return -EINVAL; + + net->mtu = new_mtu; + dev->hard_mtu = net->mtu + net->hard_header_len; + + if (net->mtu > 1500) { + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, &tmp16); + tmp16 |= AX_MEDIUM_JUMBO_EN; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, &tmp16); + } else { + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, &tmp16); + tmp16 &= ~AX_MEDIUM_JUMBO_EN; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, &tmp16); + } + + return 0; +} + +static int ax88179_set_mac_addr(struct net_device *net, void *p) +{ + struct usbnet *dev = netdev_priv(net); + struct sockaddr *addr = p; + + if (netif_running(net)) + return -EBUSY; + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); + + /* Set the MAC address */ + return ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, + ETH_ALEN, net->dev_addr); +} + +static const struct net_device_ops ax88179_netdev_ops = { + .ndo_open = usbnet_open, + .ndo_stop = usbnet_stop, + .ndo_start_xmit = usbnet_start_xmit, + .ndo_tx_timeout = usbnet_tx_timeout, + .ndo_change_mtu = ax88179_change_mtu, + .ndo_set_mac_address = ax88179_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = ax88179_ioctl, + .ndo_set_rx_mode = ax88179_set_multicast, + .ndo_set_features = ax88179_set_features, +}; + +static int ax88179_check_eeprom(struct usbnet *dev) +{ + u8 i, buf, eeprom[20]; + u16 csum, delay = HZ / 10; + unsigned long jtimeout; + + /* Read EEPROM content */ + for (i = 0; i < 6; i++) { + buf = i; + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR, + 1, 1, &buf) < 0) + return -EINVAL; + + buf = EEP_RD; + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, + 1, 1, &buf) < 0) + return -EINVAL; + + jtimeout = jiffies + delay; + do { + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, + 1, 1, &buf); + + if (time_after(jiffies, jtimeout)) + return -EINVAL; + + } while (buf & EEP_BUSY); + + __ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW, + 2, 2, &eeprom[i * 2], 0); + + if ((i == 0) && (eeprom[0] == 0xFF)) + return -EINVAL; + } + + csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9]; + csum = (csum >> 8) + (csum & 0xff); + if ((csum + eeprom[10]) != 0xff) + return -EINVAL; + + return 0; +} + +static int ax88179_check_efuse(struct usbnet *dev, u16 *ledmode) +{ + u8 i; + u8 efuse[64]; + u16 csum = 0; + + if (ax88179_read_cmd(dev, AX_ACCESS_EFUS, 0, 64, 64, efuse) < 0) + return -EINVAL; + + if (*efuse == 0xFF) + return -EINVAL; + + for (i = 0; i < 64; i++) + csum = csum + efuse[i]; + + while (csum > 255) + csum = (csum & 0x00FF) + ((csum >> 8) & 0x00FF); + + if (csum != 0xFF) + return -EINVAL; + + *ledmode = (efuse[51] << 8) | efuse[52]; + + return 0; +} + +static int ax88179_convert_old_led(struct usbnet *dev, u16 *ledvalue) +{ + u16 led; + + /* Loaded the old eFuse LED Mode */ + if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM, 0x3C, 1, 2, &led) < 0) + return -EINVAL; + + led >>= 8; + switch (led) { + case 0xFF: + led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 | + LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 | + LED2_LINK_100 | LED2_LINK_1000 | LED_VALID; + break; + case 0xFE: + led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 | LED_VALID; + break; + case 0xFD: + led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 | + LED2_LINK_10 | LED_VALID; + break; + case 0xFC: + led = LED0_ACTIVE | LED1_ACTIVE | LED1_LINK_1000 | LED2_ACTIVE | + LED2_LINK_100 | LED2_LINK_10 | LED_VALID; + break; + default: + led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 | + LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 | + LED2_LINK_100 | LED2_LINK_1000 | LED_VALID; + break; + } + + *ledvalue = led; + + return 0; +} + +static int ax88179_led_setting(struct usbnet *dev) +{ + u8 ledfd, value = 0; + u16 tmp, ledact, ledlink, ledvalue = 0, delay = HZ / 10; + unsigned long jtimeout; + + /* Check AX88179 version. UA1 or UA2*/ + ax88179_read_cmd(dev, AX_ACCESS_MAC, GENERAL_STATUS, 1, 1, &value); + + if (!(value & AX_SECLD)) { /* UA1 */ + value = AX_GPIO_CTRL_GPIO3EN | AX_GPIO_CTRL_GPIO2EN | + AX_GPIO_CTRL_GPIO1EN; + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_GPIO_CTRL, + 1, 1, &value) < 0) + return -EINVAL; + } + + /* Check EEPROM */ + if (!ax88179_check_eeprom(dev)) { + value = 0x42; + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR, + 1, 1, &value) < 0) + return -EINVAL; + + value = EEP_RD; + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, + 1, 1, &value) < 0) + return -EINVAL; + + jtimeout = jiffies + delay; + do { + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, + 1, 1, &value); + + if (time_after(jiffies, jtimeout)) + return -EINVAL; + + } while (value & EEP_BUSY); + + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_HIGH, + 1, 1, &value); + ledvalue = (value << 8); + + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW, + 1, 1, &value); + ledvalue |= value; + + /* load internal ROM for defaule setting */ + if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0)) + ax88179_convert_old_led(dev, &ledvalue); + + } else if (!ax88179_check_efuse(dev, &ledvalue)) { + if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0)) + ax88179_convert_old_led(dev, &ledvalue); + } else { + ax88179_convert_old_led(dev, &ledvalue); + } + + tmp = GMII_PHY_PGSEL_EXT; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp); + + tmp = 0x2c; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHYPAGE, 2, &tmp); + + ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_LED_ACT, 2, &ledact); + + ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_LED_LINK, 2, &ledlink); + + ledact &= GMII_LED_ACTIVE_MASK; + ledlink &= GMII_LED_LINK_MASK; + + if (ledvalue & LED0_ACTIVE) + ledact |= GMII_LED0_ACTIVE; + + if (ledvalue & LED1_ACTIVE) + ledact |= GMII_LED1_ACTIVE; + + if (ledvalue & LED2_ACTIVE) + ledact |= GMII_LED2_ACTIVE; + + if (ledvalue & LED0_LINK_10) + ledlink |= GMII_LED0_LINK_10; + + if (ledvalue & LED1_LINK_10) + ledlink |= GMII_LED1_LINK_10; + + if (ledvalue & LED2_LINK_10) + ledlink |= GMII_LED2_LINK_10; + + if (ledvalue & LED0_LINK_100) + ledlink |= GMII_LED0_LINK_100; + + if (ledvalue & LED1_LINK_100) + ledlink |= GMII_LED1_LINK_100; + + if (ledvalue & LED2_LINK_100) + ledlink |= GMII_LED2_LINK_100; + + if (ledvalue & LED0_LINK_1000) + ledlink |= GMII_LED0_LINK_1000; + + if (ledvalue & LED1_LINK_1000) + ledlink |= GMII_LED1_LINK_1000; + + if (ledvalue & LED2_LINK_1000) + ledlink |= GMII_LED2_LINK_1000; + + tmp = ledact; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_LED_ACT, 2, &tmp); + + tmp = ledlink; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_LED_LINK, 2, &tmp); + + tmp = GMII_PHY_PGSEL_PAGE0; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp); + + /* LED full duplex setting */ + ledfd = 0; + if (ledvalue & LED0_FD) + ledfd |= 0x01; + else if ((ledvalue & LED0_USB3_MASK) == 0) + ledfd |= 0x02; + + if (ledvalue & LED1_FD) + ledfd |= 0x04; + else if ((ledvalue & LED1_USB3_MASK) == 0) + ledfd |= 0x08; + + if (ledvalue & LED2_FD) + ledfd |= 0x10; + else if ((ledvalue & LED2_USB3_MASK) == 0) + ledfd |= 0x20; + + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_LEDCTRL, 1, 1, &ledfd); + + return 0; +} + +static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) +{ + u8 buf[5]; + u16 *tmp16; + u8 *tmp; + struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; + + usbnet_get_endpoints(dev, intf); + + tmp16 = (u16 *)buf; + tmp = (u8 *)buf; + + memset(ax179_data, 0, sizeof(*ax179_data)); + + /* Power up ethernet PHY */ + *tmp16 = 0; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); + *tmp16 = AX_PHYPWR_RSTCTL_IPRL; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); + msleep(200); + + *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp); + msleep(100); + + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, + ETH_ALEN, dev->net->dev_addr); + memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN); + + /* RX bulk configuration */ + memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); + + dev->rx_urb_size = 1024 * 20; + + *tmp = 0x34; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp); + + *tmp = 0x52; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH, + 1, 1, tmp); + + dev->net->netdev_ops = &ax88179_netdev_ops; + dev->net->ethtool_ops = &ax88179_ethtool_ops; + dev->net->needed_headroom = 8; + + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = ax88179_mdio_read; + dev->mii.mdio_write = ax88179_mdio_write; + dev->mii.phy_id_mask = 0xff; + dev->mii.reg_num_mask = 0xff; + dev->mii.phy_id = 0x03; + dev->mii.supports_gmii = 1; + + dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + + dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + + /* Enable checksum offload */ + *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | + AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp); + + *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP | + AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp); + + /* Configure RX control register => start operation */ + *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | + AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16); + + *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL | + AX_MONITOR_MODE_RWMP; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp); + + /* Configure default medium type => giga */ + *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | + AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_ALWAYS_ONE | + AX_MEDIUM_FULL_DUPLEX | AX_MEDIUM_GIGAMODE; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, tmp16); + + ax88179_led_setting(dev); + + /* Restart autoneg */ + mii_nway_restart(&dev->mii); + + netif_carrier_off(dev->net); + + return 0; +} + +static void ax88179_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + u16 tmp16; + + /* Configure RX control register => stop operation */ + tmp16 = AX_RX_CTL_STOP; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16); + + tmp16 = 0; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp16); + + /* Power down ethernet PHY */ + tmp16 = 0; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16); +} + +static void +ax88179_rx_checksum(struct sk_buff *skb, u32 *pkt_hdr) +{ + skb->ip_summed = CHECKSUM_NONE; + + /* checksum error bit is set */ + if ((*pkt_hdr & AX_RXHDR_L3CSUM_ERR) || + (*pkt_hdr & AX_RXHDR_L4CSUM_ERR)) + return; + + /* It must be a TCP or UDP packet with a valid checksum */ + if (((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_TCP) || + ((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_UDP)) + skb->ip_summed = CHECKSUM_UNNECESSARY; +} + +static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + struct sk_buff *ax_skb; + int pkt_cnt; + u32 rx_hdr; + u16 hdr_off; + u32 *pkt_hdr; + + skb_trim(skb, skb->len - 4); + memcpy(&rx_hdr, skb_tail_pointer(skb), 4); + le32_to_cpus(&rx_hdr); + + pkt_cnt = (u16)rx_hdr; + hdr_off = (u16)(rx_hdr >> 16); + pkt_hdr = (u32 *)(skb->data + hdr_off); + + while (pkt_cnt--) { + u16 pkt_len; + + le32_to_cpus(pkt_hdr); + pkt_len = (*pkt_hdr >> 16) & 0x1fff; + + /* Check CRC or runt packet */ + if ((*pkt_hdr & AX_RXHDR_CRC_ERR) || + (*pkt_hdr & AX_RXHDR_DROP_ERR)) { + skb_pull(skb, (pkt_len + 7) & 0xFFF8); + pkt_hdr++; + continue; + } + + if (pkt_cnt == 0) { + /* Skip IP alignment psudo header */ + skb_pull(skb, 2); + skb->len = pkt_len; + skb_set_tail_pointer(skb, pkt_len); + skb->truesize = pkt_len + sizeof(struct sk_buff); + ax88179_rx_checksum(skb, pkt_hdr); + return 1; + } + + ax_skb = skb_clone(skb, GFP_ATOMIC); + if (ax_skb) { + ax_skb->len = pkt_len; + ax_skb->data = skb->data + 2; + skb_set_tail_pointer(ax_skb, pkt_len); + ax_skb->truesize = pkt_len + sizeof(struct sk_buff); + ax88179_rx_checksum(ax_skb, pkt_hdr); + usbnet_skb_return(dev, ax_skb); + } else { + return 0; + } + + skb_pull(skb, (pkt_len + 7) & 0xFFF8); + pkt_hdr++; + } + return 1; +} + +static struct sk_buff * +ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) +{ + u32 tx_hdr1, tx_hdr2; + int frame_size = dev->maxpacket; + int mss = skb_shinfo(skb)->gso_size; + int headroom; + int tailroom; + + tx_hdr1 = skb->len; + tx_hdr2 = mss; + if (((skb->len + 8) % frame_size) == 0) + tx_hdr2 |= 0x80008000; /* Enable padding */ + + skb_linearize(skb); + headroom = skb_headroom(skb); + tailroom = skb_tailroom(skb); + + if (!skb_header_cloned(skb) && + !skb_cloned(skb) && + (headroom + tailroom) >= 8) { + if (headroom < 8) { + skb->data = memmove(skb->head + 8, skb->data, skb->len); + skb_set_tail_pointer(skb, skb->len); + } + } else { + struct sk_buff *skb2; + + skb2 = skb_copy_expand(skb, 8, 0, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + skb_push(skb, 4); + cpu_to_le32s(&tx_hdr2); + skb_copy_to_linear_data(skb, &tx_hdr2, 4); + + skb_push(skb, 4); + cpu_to_le32s(&tx_hdr1); + skb_copy_to_linear_data(skb, &tx_hdr1, 4); + + return skb; +} + +static int ax88179_link_reset(struct usbnet *dev) +{ + struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; + u8 tmp[5], link_sts; + u16 mode, tmp16, delay = HZ / 10; + u32 tmp32 = 0x40000000; + unsigned long jtimeout; + + jtimeout = jiffies + delay; + while (tmp32 & 0x40000000) { + mode = 0; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &mode); + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, + &ax179_data->rxctl); + + /*link up, check the usb device control TX FIFO full or empty*/ + ax88179_read_cmd(dev, 0x81, 0x8c, 0, 4, &tmp32); + + if (time_after(jiffies, jtimeout)) + return 0; + } + + mode = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | + AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_ALWAYS_ONE; + + ax88179_read_cmd(dev, AX_ACCESS_MAC, PHYSICAL_LINK_STATUS, + 1, 1, &link_sts); + + ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PHYSR, 2, &tmp16); + + if (!(tmp16 & GMII_PHY_PHYSR_LINK)) { + return 0; + } else if (GMII_PHY_PHYSR_GIGA == (tmp16 & GMII_PHY_PHYSR_SMASK)) { + mode |= AX_MEDIUM_GIGAMODE | AX_MEDIUM_EN_125MHZ; + if (dev->net->mtu > 1500) + mode |= AX_MEDIUM_JUMBO_EN; + + if (link_sts & AX_USB_SS) + memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); + else if (link_sts & AX_USB_HS) + memcpy(tmp, &AX88179_BULKIN_SIZE[1], 5); + else + memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); + } else if (GMII_PHY_PHYSR_100 == (tmp16 & GMII_PHY_PHYSR_SMASK)) { + mode |= AX_MEDIUM_PS; + + if (link_sts & (AX_USB_SS | AX_USB_HS)) + memcpy(tmp, &AX88179_BULKIN_SIZE[2], 5); + else + memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); + } else { + memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); + } + + /* RX bulk configuration */ + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); + + dev->rx_urb_size = (1024 * (tmp[3] + 2)); + + if (tmp16 & GMII_PHY_PHYSR_FULL) + mode |= AX_MEDIUM_FULL_DUPLEX; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, &mode); + + netif_carrier_on(dev->net); + + return 0; +} + +static int ax88179_reset(struct usbnet *dev) +{ + u8 buf[5]; + u16 *tmp16; + u8 *tmp; + + tmp16 = (u16 *)buf; + tmp = (u8 *)buf; + + /* Power up ethernet PHY */ + *tmp16 = 0; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); + + *tmp16 = AX_PHYPWR_RSTCTL_IPRL; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); + msleep(200); + + *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp); + msleep(100); + + /* Ethernet PHY Auto Detach*/ + ax88179_auto_detach(dev, 0); + + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN, + dev->net->dev_addr); + memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN); + + /* RX bulk configuration */ + memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); + + dev->rx_urb_size = 1024 * 20; + + *tmp = 0x34; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp); + + *tmp = 0x52; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH, + 1, 1, tmp); + + dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + + dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + + /* Enable checksum offload */ + *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | + AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp); + + *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP | + AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp); + + /* Configure RX control register => start operation */ + *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | + AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16); + + *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL | + AX_MONITOR_MODE_RWMP; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp); + + /* Configure default medium type => giga */ + *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | + AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_ALWAYS_ONE | + AX_MEDIUM_FULL_DUPLEX | AX_MEDIUM_GIGAMODE; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, tmp16); + + ax88179_led_setting(dev); + + /* Restart autoneg */ + mii_nway_restart(&dev->mii); + + netif_carrier_off(dev->net); + + return 0; +} + +static int ax88179_stop(struct usbnet *dev) +{ + u16 tmp16; + + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, &tmp16); + tmp16 &= ~AX_MEDIUM_RECEIVE_EN; + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, &tmp16); + + return 0; +} + +static const struct driver_info ax88179_info = { + .description = "ASIX AX88179 USB 3.0 Gigibit Ethernet", + .bind = ax88179_bind, + .unbind = ax88179_unbind, + .status = ax88179_status, + .link_reset = ax88179_link_reset, + .reset = ax88179_reset, + .stop = ax88179_stop, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88179_rx_fixup, + .tx_fixup = ax88179_tx_fixup, +}; + +static const struct driver_info ax88178a_info = { + .description = "ASIX AX88178A USB 2.0 Gigibit Ethernet", + .bind = ax88179_bind, + .unbind = ax88179_unbind, + .status = ax88179_status, + .link_reset = ax88179_link_reset, + .reset = ax88179_reset, + .stop = ax88179_stop, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88179_rx_fixup, + .tx_fixup = ax88179_tx_fixup, +}; + +static const struct driver_info sitecom_info = { + .description = "Sitecom USB 3.0 to Gigabit Adapter", + .bind = ax88179_bind, + .unbind = ax88179_unbind, + .status = ax88179_status, + .link_reset = ax88179_link_reset, + .reset = ax88179_reset, + .stop = ax88179_stop, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88179_rx_fixup, + .tx_fixup = ax88179_tx_fixup, +}; + +static const struct usb_device_id products[] = { +{ + /* ASIX AX88179 10/100/1000 */ + USB_DEVICE(0x0b95, 0x1790), + .driver_info = (unsigned long)&ax88179_info, +}, { + /* ASIX AX88178A 10/100/1000 */ + USB_DEVICE(0x0b95, 0x178a), + .driver_info = (unsigned long)&ax88178a_info, +}, { + /* Sitecom USB 3.0 to Gigabit Adapter */ + USB_DEVICE(0x0df6, 0x0072), + .driver_info = (unsigned long) &sitecom_info, +}, + { }, +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver ax88179_178a_driver = { + .name = "ax88179_178a", + .id_table = products, + .probe = usbnet_probe, + .suspend = ax88179_suspend, + .resume = ax88179_resume, + .disconnect = usbnet_disconnect, + .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, +}; + +module_usb_driver(ax88179_178a_driver); + +MODULE_DESCRIPTION("ASIX AX88179/178A based USB 3.0/2.0 Gigabit Ethernet Devices"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From d6e89c0b7660bd725a0948126f9db1a327f48d76 Mon Sep 17 00:00:00 2001 From: Silviu-Mihai Popescu Date: Sat, 2 Mar 2013 09:45:19 +0000 Subject: caif_dev: fix sparse warnings for caif_flow_cb This fixed the following sparse warning: net/caif/caif_dev.c:121:6: warning: symbol 'caif_flow_cb' was not declared. Should it be static? Signed-off-by: Silviu-Mihai Popescu Signed-off-by: David S. Miller diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index 1ae1d9c..21760f0 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -118,7 +118,7 @@ static struct caif_device_entry *caif_get(struct net_device *dev) return NULL; } -void caif_flow_cb(struct sk_buff *skb) +static void caif_flow_cb(struct sk_buff *skb) { struct caif_device_entry *caifd; void (*dtor)(struct sk_buff *skb) = NULL; -- cgit v0.10.2 From 15516f123a849084c6bb8dec40f2acb2ce69d639 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Sat, 2 Mar 2013 15:53:39 +0000 Subject: MAINTAINERS: remove 3c505 This driver was removed by commit 0e245db (drivers/net: delete the 3Com 3c505/3c507 intel i825xx support). Cc: Paul Gortmaker Cc: Philip Blundell Cc: netdev@vger.kernel.org Signed-off-by: Cesar Eduardo Barros Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index 1e5c3a4..86db49e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -113,12 +113,6 @@ Maintainers List (try to look for most precise areas first) ----------------------------------- -3C505 NETWORK DRIVER -M: Philip Blundell -L: netdev@vger.kernel.org -S: Maintained -F: drivers/net/ethernet/i825xx/3c505* - 3C59X NETWORK DRIVER M: Steffen Klassert L: netdev@vger.kernel.org -- cgit v0.10.2 From 6b8a12bab337702c804deba9a1860ac042f69002 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Sat, 2 Mar 2013 15:53:43 +0000 Subject: MAINTAINERS: remove drivers/net/wan/cycx* This driver was removed by commit 6fcdf4f (wanrouter: delete now orphaned header content, files/drivers). Cc: Paul Gortmaker Cc: Arnaldo Carvalho de Melo Cc: netdev@vger.kernel.org Signed-off-by: Cesar Eduardo Barros Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index 86db49e..7ca15c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2353,12 +2353,6 @@ W: http://www.arm.linux.org.uk/ S: Maintained F: drivers/video/cyber2000fb.* -CYCLADES 2X SYNC CARD DRIVER -M: Arnaldo Carvalho de Melo -W: http://oops.ghostprotocols.net:81/blog -S: Maintained -F: drivers/net/wan/cycx* - CYCLADES ASYNC MUX DRIVER W: http://www.cyclades.com/ S: Orphan -- cgit v0.10.2 From b711c12113620081708c6ccd43768b5a2501e2ab Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Sat, 2 Mar 2013 15:53:45 +0000 Subject: MAINTAINERS: remove eexpress This driver was removed by commit f84932d (drivers/net: delete ISA intel eexpress and eepro i825xx drivers). Cc: Paul Gortmaker Cc: Philip Blundell Cc: netdev@vger.kernel.org Signed-off-by: Cesar Eduardo Barros Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index 7ca15c5..f79abf0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3046,12 +3046,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git F: drivers/video/s1d13xxxfb.c F: include/video/s1d13xxxfb.h -ETHEREXPRESS-16 NETWORK DRIVER -M: Philip Blundell -L: netdev@vger.kernel.org -S: Maintained -F: drivers/net/ethernet/i825xx/eexpress.* - ETHERNET BRIDGE M: Stephen Hemminger L: bridge@lists.linux-foundation.org -- cgit v0.10.2 From ece6b0a2b25652d684a7ced4ae680a863af041e0 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Sun, 3 Mar 2013 16:18:11 +0000 Subject: rds: limit the size allocated by rds_message_alloc() Dave Jones reported the following bug: "When fed mangled socket data, rds will trust what userspace gives it, and tries to allocate enormous amounts of memory larger than what kmalloc can satisfy." WARNING: at mm/page_alloc.c:2393 __alloc_pages_nodemask+0xa0d/0xbe0() Hardware name: GA-MA78GM-S2H Modules linked in: vmw_vsock_vmci_transport vmw_vmci vsock fuse bnep dlci bridge 8021q garp stp mrp binfmt_misc l2tp_ppp l2tp_core rfcomm s Pid: 24652, comm: trinity-child2 Not tainted 3.8.0+ #65 Call Trace: [] warn_slowpath_common+0x75/0xa0 [] warn_slowpath_null+0x1a/0x20 [] __alloc_pages_nodemask+0xa0d/0xbe0 [] ? native_sched_clock+0x26/0x90 [] ? trace_hardirqs_off_caller+0x28/0xc0 [] ? trace_hardirqs_off+0xd/0x10 [] alloc_pages_current+0xb8/0x180 [] __get_free_pages+0x2a/0x80 [] kmalloc_order_trace+0x3e/0x1a0 [] __kmalloc+0x2f5/0x3a0 [] ? local_bh_enable_ip+0x7c/0xf0 [] rds_message_alloc+0x23/0xb0 [rds] [] rds_sendmsg+0x2b1/0x990 [rds] [] ? trace_hardirqs_off+0xd/0x10 [] sock_sendmsg+0xb0/0xe0 [] ? get_lock_stats+0x22/0x70 [] ? put_lock_stats.isra.23+0xe/0x40 [] sys_sendto+0x130/0x180 [] ? trace_hardirqs_on+0xd/0x10 [] ? _raw_spin_unlock_irq+0x3b/0x60 [] ? sysret_check+0x1b/0x56 [] ? trace_hardirqs_on_caller+0x115/0x1a0 [] ? trace_hardirqs_on_thunk+0x3a/0x3f [] system_call_fastpath+0x16/0x1b ---[ end trace eed6ae990d018c8b ]--- Reported-by: Dave Jones Cc: Dave Jones Cc: David S. Miller Cc: Venkat Venkatsubra Signed-off-by: Cong Wang Acked-by: Venkat Venkatsubra Signed-off-by: David S. Miller diff --git a/net/rds/message.c b/net/rds/message.c index f0a4658..aff589c 100644 --- a/net/rds/message.c +++ b/net/rds/message.c @@ -197,6 +197,9 @@ struct rds_message *rds_message_alloc(unsigned int extra_len, gfp_t gfp) { struct rds_message *rm; + if (extra_len > KMALLOC_MAX_SIZE - sizeof(struct rds_message)) + return NULL; + rm = kzalloc(sizeof(struct rds_message) + extra_len, gfp); if (!rm) goto out; -- cgit v0.10.2 From 3f736868b47687d1336fe88185560b22bb92021e Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Sun, 3 Mar 2013 16:28:27 +0000 Subject: sctp: use KMALLOC_MAX_SIZE instead of its own MAX_KMALLOC_SIZE Don't definite its own MAX_KMALLOC_SIZE, use the one defined in mm. Cc: Vlad Yasevich Cc: Sridhar Samudrala Cc: Neil Horman Cc: David S. Miller Signed-off-by: Cong Wang Acked-by: Neil Horman Signed-off-by: David S. Miller diff --git a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c index 442ad4e..825ea94 100644 --- a/net/sctp/ssnmap.c +++ b/net/sctp/ssnmap.c @@ -41,8 +41,6 @@ #include #include -#define MAX_KMALLOC_SIZE 131072 - static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in, __u16 out); @@ -65,7 +63,7 @@ struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int size; size = sctp_ssnmap_size(in, out); - if (size <= MAX_KMALLOC_SIZE) + if (size <= KMALLOC_MAX_SIZE) retval = kmalloc(size, gfp); else retval = (struct sctp_ssnmap *) @@ -82,7 +80,7 @@ struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, return retval; fail_map: - if (size <= MAX_KMALLOC_SIZE) + if (size <= KMALLOC_MAX_SIZE) kfree(retval); else free_pages((unsigned long)retval, get_order(size)); @@ -124,7 +122,7 @@ void sctp_ssnmap_free(struct sctp_ssnmap *map) int size; size = sctp_ssnmap_size(map->in.len, map->out.len); - if (size <= MAX_KMALLOC_SIZE) + if (size <= KMALLOC_MAX_SIZE) kfree(map); else free_pages((unsigned long)map, get_order(size)); -- cgit v0.10.2 From de5fb0a053482d89262c3284b67884cd2c621adc Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sun, 3 Mar 2013 17:34:25 +0000 Subject: net: fec: put tx to napi poll function to fix dead lock up stack ndo_start_xmit already hold lock. fec_enet_start_xmit needn't spin lock. stat_xmit just update fep->cur_tx fec_enet_tx just update fep->dirty_tx Reserve a empty bdb to check full or empty cur_tx == dirty_tx means full cur_tx == dirty_tx +1 means empty So needn't is_full variable. Fix spin lock deadlock ================================= [ INFO: inconsistent lock state ] 3.8.0-rc5+ #107 Not tainted --------------------------------- inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage. ptp4l/615 [HC1[1]:SC0[0]:HE0:SE1] takes: (&(&list->lock)->rlock#3){?.-...}, at: [<8042c3c4>] skb_queue_tail+0x20/0x50 {HARDIRQ-ON-W} state was registered at: [<80067250>] mark_lock+0x154/0x4e8 [<800676f4>] mark_irqflags+0x110/0x1a4 [<80069208>] __lock_acquire+0x494/0x9c0 [<80069ce8>] lock_acquire+0x90/0xa4 [<80527ad0>] _raw_spin_lock_bh+0x44/0x54 [<804877e0>] first_packet_length+0x38/0x1f0 [<804879e4>] udp_poll+0x4c/0x5c [<804231f8>] sock_poll+0x24/0x28 [<800d27f0>] do_poll.isra.10+0x120/0x254 [<800d36e4>] do_sys_poll+0x15c/0x1e8 [<800d3828>] sys_poll+0x60/0xc8 [<8000e780>] ret_fast_syscall+0x0/0x3c *** DEADLOCK *** 1 lock held by ptp4l/615: #0: (&(&fep->hw_lock)->rlock){-.-...}, at: [<80355f9c>] fec_enet_tx+0x24/0x268 stack backtrace: Backtrace: [<800121e0>] (dump_backtrace+0x0/0x10c) from [<80516210>] (dump_stack+0x18/0x1c) r6:8063b1fc r5:bf38b2f8 r4:bf38b000 r3:bf38b000 [<805161f8>] (dump_stack+0x0/0x1c) from [<805189d0>] (print_usage_bug.part.34+0x164/0x1a4) [<8051886c>] (print_usage_bug.part.34+0x0/0x1a4) from [<80518a88>] (print_usage_bug+0x78/0x88) r8:80065664 r7:bf38b2f8 r6:00000002 r5:00000000 r4:bf38b000 [<80518a10>] (print_usage_bug+0x0/0x88) from [<80518b58>] (mark_lock_irq+0xc0/0x270) r7:bf38b000 r6:00000002 r5:bf38b2f8 r4:00000000 [<80518a98>] (mark_lock_irq+0x0/0x270) from [<80067270>] (mark_lock+0x174/0x4e8) [<800670fc>] (mark_lock+0x0/0x4e8) from [<80067744>] (mark_irqflags+0x160/0x1a4) [<800675e4>] (mark_irqflags+0x0/0x1a4) from [<80069208>] (__lock_acquire+0x494/0x9c0) r5:00000002 r4:bf38b2f8 [<80068d74>] (__lock_acquire+0x0/0x9c0) from [<80069ce8>] (lock_acquire+0x90/0xa4) [<80069c58>] (lock_acquire+0x0/0xa4) from [<805278d8>] (_raw_spin_lock_irqsave+0x4c/0x60) [<8052788c>] (_raw_spin_lock_irqsave+0x0/0x60) from [<8042c3c4>] (skb_queue_tail+0x20/0x50) r6:bfbb2180 r5:bf1d0190 r4:bf1d0184 [<8042c3a4>] (skb_queue_tail+0x0/0x50) from [<8042c4cc>] (sock_queue_err_skb+0xd8/0x188) r6:00000056 r5:bfbb2180 r4:bf1d0000 r3:00000000 [<8042c3f4>] (sock_queue_err_skb+0x0/0x188) from [<8042d15c>] (skb_tstamp_tx+0x70/0xa0) r6:bf0dddb0 r5:bf1d0000 r4:bfbb2180 r3:00000004 [<8042d0ec>] (skb_tstamp_tx+0x0/0xa0) from [<803561d0>] (fec_enet_tx+0x258/0x268) r6:c089d260 r5:00001c00 r4:bfbd0000 [<80355f78>] (fec_enet_tx+0x0/0x268) from [<803562cc>] (fec_enet_interrupt+0xec/0xf8) [<803561e0>] (fec_enet_interrupt+0x0/0xf8) from [<8007d5b0>] (handle_irq_event_percpu+0x54/0x1a0) [<8007d55c>] (handle_irq_event_percpu+0x0/0x1a0) from [<8007d740>] (handle_irq_event+0x44/0x64) [<8007d6fc>] (handle_irq_event+0x0/0x64) from [<80080690>] (handle_fasteoi_irq+0xc4/0x15c) r6:bf0dc000 r5:bf811290 r4:bf811240 r3:00000000 [<800805cc>] (handle_fasteoi_irq+0x0/0x15c) from [<8007ceec>] (generic_handle_irq+0x28/0x38) r5:807130c8 r4:00000096 [<8007cec4>] (generic_handle_irq+0x0/0x38) from [<8000f16c>] (handle_IRQ+0x54/0xb4) r4:8071d280 r3:00000180 [<8000f118>] (handle_IRQ+0x0/0xb4) from [<80008544>] (gic_handle_irq+0x30/0x64) r8:8000e924 r7:f4000100 r6:bf0ddef8 r5:8071c974 r4:f400010c r3:00000000 [<80008514>] (gic_handle_irq+0x0/0x64) from [<8000e2e4>] (__irq_svc+0x44/0x5c) Exception stack(0xbf0ddef8 to 0xbf0ddf40) Signed-off-by: Frank Li Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index fccc3bf..069a155 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -246,14 +246,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct bufdesc *bdp; void *bufaddr; unsigned short status; - unsigned long flags; + unsigned int index; if (!fep->link) { /* Link is down or autonegotiation is in progress. */ return NETDEV_TX_BUSY; } - spin_lock_irqsave(&fep->hw_lock, flags); /* Fill in a Tx ring entry */ bdp = fep->cur_tx; @@ -264,7 +263,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) * This should not happen, since ndev->tbusy should be set. */ printk("%s: tx queue full!.\n", ndev->name); - spin_unlock_irqrestore(&fep->hw_lock, flags); return NETDEV_TX_BUSY; } @@ -280,13 +278,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) * 4-byte boundaries. Use bounce buffers to copy data * and get it aligned. Ugh. */ + if (fep->bufdesc_ex) + index = (struct bufdesc_ex *)bdp - + (struct bufdesc_ex *)fep->tx_bd_base; + else + index = bdp - fep->tx_bd_base; + if (((unsigned long) bufaddr) & FEC_ALIGNMENT) { - unsigned int index; - if (fep->bufdesc_ex) - index = (struct bufdesc_ex *)bdp - - (struct bufdesc_ex *)fep->tx_bd_base; - else - index = bdp - fep->tx_bd_base; memcpy(fep->tx_bounce[index], skb->data, skb->len); bufaddr = fep->tx_bounce[index]; } @@ -300,10 +298,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) swap_buffer(bufaddr, skb->len); /* Save skb pointer */ - fep->tx_skbuff[fep->skb_cur] = skb; - - ndev->stats.tx_bytes += skb->len; - fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; + fep->tx_skbuff[index] = skb; /* Push the data cache so the CPM does not get stale memory * data. @@ -331,26 +326,22 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) ebdp->cbd_esc = BD_ENET_TX_INT; } } - /* Trigger transmission start */ - writel(0, fep->hwp + FEC_X_DES_ACTIVE); - /* If this was the last BD in the ring, start at the beginning again. */ if (status & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; else bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); - if (bdp == fep->dirty_tx) { - fep->tx_full = 1; + fep->cur_tx = bdp; + + if (fep->cur_tx == fep->dirty_tx) netif_stop_queue(ndev); - } - fep->cur_tx = bdp; + /* Trigger transmission start */ + writel(0, fep->hwp + FEC_X_DES_ACTIVE); skb_tx_timestamp(skb); - spin_unlock_irqrestore(&fep->hw_lock, flags); - return NETDEV_TX_OK; } @@ -406,11 +397,8 @@ fec_restart(struct net_device *ndev, int duplex) writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, fep->hwp + FEC_X_DES_START); - fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; fep->cur_rx = fep->rx_bd_base; - /* Reset SKB transmit buffers. */ - fep->skb_cur = fep->skb_dirty = 0; for (i = 0; i <= TX_RING_MOD_MASK; i++) { if (fep->tx_skbuff[i]) { dev_kfree_skb_any(fep->tx_skbuff[i]); @@ -573,20 +561,35 @@ fec_enet_tx(struct net_device *ndev) struct bufdesc *bdp; unsigned short status; struct sk_buff *skb; + int index = 0; fep = netdev_priv(ndev); - spin_lock(&fep->hw_lock); bdp = fep->dirty_tx; + /* get next bdp of dirty_tx */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = fep->tx_bd_base; + else + bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { - if (bdp == fep->cur_tx && fep->tx_full == 0) + + /* current queue is empty */ + if (bdp == fep->cur_tx) break; + if (fep->bufdesc_ex) + index = (struct bufdesc_ex *)bdp - + (struct bufdesc_ex *)fep->tx_bd_base; + else + index = bdp - fep->tx_bd_base; + dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); bdp->cbd_bufaddr = 0; - skb = fep->tx_skbuff[fep->skb_dirty]; + skb = fep->tx_skbuff[index]; + /* Check for errors. */ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN | @@ -631,8 +634,9 @@ fec_enet_tx(struct net_device *ndev) /* Free the sk buffer associated with this last transmit */ dev_kfree_skb_any(skb); - fep->tx_skbuff[fep->skb_dirty] = NULL; - fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; + fep->tx_skbuff[index] = NULL; + + fep->dirty_tx = bdp; /* Update pointer to next buffer descriptor to be transmitted */ if (status & BD_ENET_TX_WRAP) @@ -642,14 +646,12 @@ fec_enet_tx(struct net_device *ndev) /* Since we have freed up a buffer, the ring is no longer full */ - if (fep->tx_full) { - fep->tx_full = 0; + if (fep->dirty_tx != fep->cur_tx) { if (netif_queue_stopped(ndev)) netif_wake_queue(ndev); } } - fep->dirty_tx = bdp; - spin_unlock(&fep->hw_lock); + return; } @@ -816,7 +818,7 @@ fec_enet_interrupt(int irq, void *dev_id) int_events = readl(fep->hwp + FEC_IEVENT); writel(int_events, fep->hwp + FEC_IEVENT); - if (int_events & FEC_ENET_RXF) { + if (int_events & (FEC_ENET_RXF | FEC_ENET_TXF)) { ret = IRQ_HANDLED; /* Disable the RX interrupt */ @@ -827,15 +829,6 @@ fec_enet_interrupt(int irq, void *dev_id) } } - /* Transmit OK, or non-fatal error. Update the buffer - * descriptors. FEC handles all errors, we just discover - * them as part of the transmit process. - */ - if (int_events & FEC_ENET_TXF) { - ret = IRQ_HANDLED; - fec_enet_tx(ndev); - } - if (int_events & FEC_ENET_MII) { ret = IRQ_HANDLED; complete(&fep->mdio_done); @@ -851,6 +844,8 @@ static int fec_enet_rx_napi(struct napi_struct *napi, int budget) int pkts = fec_enet_rx(ndev, budget); struct fec_enet_private *fep = netdev_priv(ndev); + fec_enet_tx(ndev); + if (pkts < budget) { napi_complete(napi); writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); @@ -1646,6 +1641,7 @@ static int fec_enet_init(struct net_device *ndev) /* ...and the same for transmit */ bdp = fep->tx_bd_base; + fep->cur_tx = bdp; for (i = 0; i < TX_RING_SIZE; i++) { /* Initialize the BD for every fragment in the page. */ @@ -1657,6 +1653,7 @@ static int fec_enet_init(struct net_device *ndev) /* Set the last buffer to wrap */ bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); bdp->cbd_sc |= BD_SC_WRAP; + fep->dirty_tx = bdp; fec_restart(ndev, 0); diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 01579b8..c0f63be 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -214,8 +214,6 @@ struct fec_enet_private { unsigned char *tx_bounce[TX_RING_SIZE]; struct sk_buff *tx_skbuff[TX_RING_SIZE]; struct sk_buff *rx_skbuff[RX_RING_SIZE]; - ushort skb_cur; - ushort skb_dirty; /* CPM dual port RAM relative addresses */ dma_addr_t bd_dma; @@ -227,7 +225,6 @@ struct fec_enet_private { /* The ring entries to be free()ed */ struct bufdesc *dirty_tx; - uint tx_full; /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ spinlock_t hw_lock; -- cgit v0.10.2 From 3e8b0ac3e41e3c882222a5522d5df7212438ab51 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sun, 3 Mar 2013 20:46:46 +0000 Subject: net: ipv6: Don't purge default router if accept_ra=2 Setting net.ipv6.conf..accept_ra=2 causes the kernel to accept RAs even when forwarding is enabled. However, enabling forwarding purges all default routes on the system, breaking connectivity until the next RA is received. Fix this by not purging default routes on interfaces that have accept_ra=2. Signed-off-by: Lorenzo Colitti Acked-by: YOSHIFUJI Hideaki Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 9282665..e5fe004 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1915,7 +1915,8 @@ void rt6_purge_dflt_routers(struct net *net) restart: read_lock_bh(&table->tb6_lock); for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) { - if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { + if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) && + (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) { dst_hold(&rt->dst); read_unlock_bh(&table->tb6_lock); ip6_del_rt(rt); -- cgit v0.10.2 From acac8406cd523a3afbd6c6db31e9f763644bf6ba Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sun, 3 Mar 2013 20:52:38 +0000 Subject: net: fec: fix build error in no MXC platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build error cause by Commit ff43da86c69d76a726ffe7d1666148960dc1d108 ("NET: FEC: dynamtic check DMA desc buff type") drivers/net/ethernet/freescale/fec.c: In function ‘fec_enet_get_nextdesc’: drivers/net/ethernet/freescale/fec.c:215:18: error: invalid use of undefined type ‘struct bufdesc_ex’ drivers/net/ethernet/freescale/fec.c: In function ‘fec_enet_get_prevdesc’: drivers/net/ethernet/freescale/fec.c:224:18: error: invalid use of undefined type ‘struct bufdesc_ex’ drivers/net/ethernet/freescale/fec.c: In function ‘fec_enet_start_xmit’: drivers/net/ethernet/freescale/fec.c:286:37: error: arithmetic on pointer to an incomplete type drivers/net/ethernet/freescale/fec.c:287:13: error: arithmetic on pointer to an incomplete type drivers/net/ethernet/freescale/fec.c:324:7: error: dereferencing pointer to incomplete type etc.... Signed-off-by: Frank Li Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index c0f63be..f539007 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -97,6 +97,13 @@ struct bufdesc { unsigned short cbd_sc; /* Control and status info */ unsigned long cbd_bufaddr; /* Buffer address */ }; +#else +struct bufdesc { + unsigned short cbd_sc; /* Control and status info */ + unsigned short cbd_datlen; /* Data length */ + unsigned long cbd_bufaddr; /* Buffer address */ +}; +#endif struct bufdesc_ex { struct bufdesc desc; @@ -107,14 +114,6 @@ struct bufdesc_ex { unsigned short res0[4]; }; -#else -struct bufdesc { - unsigned short cbd_sc; /* Control and status info */ - unsigned short cbd_datlen; /* Data length */ - unsigned long cbd_bufaddr; /* Buffer address */ -}; -#endif - /* * The following definitions courtesy of commproc.h, which where * Copyright (c) 1997 Dan Malek (dmalek@jlc.net). -- cgit v0.10.2 From 7dac1b514a00817ddb43704068c14ffd8b8fba19 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Sun, 3 Mar 2013 20:57:18 +0000 Subject: rds: simplify a warning message Cc: David S. Miller Cc: Venkat Venkatsubra Signed-off-by: Cong Wang Signed-off-by: David S. Miller diff --git a/net/rds/message.c b/net/rds/message.c index aff589c..aba232f 100644 --- a/net/rds/message.c +++ b/net/rds/message.c @@ -82,10 +82,7 @@ static void rds_message_purge(struct rds_message *rm) void rds_message_put(struct rds_message *rm) { rdsdebug("put rm %p ref %d\n", rm, atomic_read(&rm->m_refcount)); - if (atomic_read(&rm->m_refcount) == 0) { -printk(KERN_CRIT "danger refcount zero on %p\n", rm); -WARN_ON(1); - } + WARN(!atomic_read(&rm->m_refcount), "danger refcount zero on %p\n", rm); if (atomic_dec_and_test(&rm->m_refcount)) { BUG_ON(!list_empty(&rm->m_sock_item)); BUG_ON(!list_empty(&rm->m_conn_item)); -- cgit v0.10.2 From d2123be0e55101742dacd6dae60cdd0f1e2ef302 Mon Sep 17 00:00:00 2001 From: Silviu-Mihai Popescu Date: Sun, 3 Mar 2013 21:09:31 +0000 Subject: CAIF: fix sparse warning for caif_usb This fixes the following sparse warning: net/caif/caif_usb.c:84:16: warning: symbol 'cfusbl_create' was not declared. Should it be static? Signed-off-by: Silviu-Mihai Popescu Signed-off-by: David S. Miller diff --git a/net/caif/caif_usb.c b/net/caif/caif_usb.c index 3ebc8cb..ef8ebaa 100644 --- a/net/caif/caif_usb.c +++ b/net/caif/caif_usb.c @@ -81,8 +81,8 @@ static void cfusbl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, layr->up->ctrlcmd(layr->up, ctrl, layr->id); } -struct cflayer *cfusbl_create(int phyid, u8 ethaddr[ETH_ALEN], - u8 braddr[ETH_ALEN]) +static struct cflayer *cfusbl_create(int phyid, u8 ethaddr[ETH_ALEN], + u8 braddr[ETH_ALEN]) { struct cfusbl *this = kmalloc(sizeof(struct cfusbl), GFP_ATOMIC); -- cgit v0.10.2 From aab2b4bf224ef8358d262f95b568b8ad0cecf0a0 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Mon, 4 Mar 2013 06:23:05 +0000 Subject: tcp: fix double-counted receiver RTT when leaving receiver fast path We should not update ts_recent and call tcp_rcv_rtt_measure_ts() both before and after going to step5. That wastes CPU and double-counts the receiver-side RTT sample. Signed-off-by: Neal Cardwell Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a759e19..0d9bdac 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5485,6 +5485,9 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, if (tcp_checksum_complete_user(sk, skb)) goto csum_error; + if ((int)skb->truesize > sk->sk_forward_alloc) + goto step5; + /* Predicted packet is in window by definition. * seq == rcv_nxt and rcv_wup <= rcv_nxt. * Hence, check seq<=rcv_wup reduces to: @@ -5496,9 +5499,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, tcp_rcv_rtt_measure_ts(sk, skb); - if ((int)skb->truesize > sk->sk_forward_alloc) - goto step5; - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITS); /* Bulk data transfer: receiver */ -- cgit v0.10.2 From f7f154f1246ccc5a0a7e9ce50932627d60a0c878 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 5 Mar 2013 10:07:08 +1030 Subject: hw_random: make buffer usable in scatterlist. virtio_rng feeds the randomness buffer handed by the core directly into the scatterlist, since commit bb347d98079a547e80bd4722dee1de61e4dca0e8. However, if CONFIG_HW_RANDOM=m, the static buffer isn't a linear address (at least on most archs). We could fix this in virtio_rng, but it's actually far easier to just do it in the core as virtio_rng would have to allocate a buffer every time (it doesn't know how much the core will want to read). Reported-by: Aurelien Jarno Tested-by: Aurelien Jarno Signed-off-by: Rusty Russell Cc: stable@kernel.org diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 1bafb40..69ae597 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -40,6 +40,7 @@ #include #include #include +#include #include @@ -52,8 +53,12 @@ static struct hwrng *current_rng; static LIST_HEAD(rng_list); static DEFINE_MUTEX(rng_mutex); static int data_avail; -static u8 rng_buffer[SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES] - __cacheline_aligned; +static u8 *rng_buffer; + +static size_t rng_buffer_size(void) +{ + return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; +} static inline int hwrng_init(struct hwrng *rng) { @@ -116,7 +121,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, if (!data_avail) { bytes_read = rng_get_data(current_rng, rng_buffer, - sizeof(rng_buffer), + rng_buffer_size(), !(filp->f_flags & O_NONBLOCK)); if (bytes_read < 0) { err = bytes_read; @@ -307,6 +312,14 @@ int hwrng_register(struct hwrng *rng) mutex_lock(&rng_mutex); + /* kmalloc makes this safe for virt_to_page() in virtio_rng.c */ + err = -ENOMEM; + if (!rng_buffer) { + rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL); + if (!rng_buffer) + goto out_unlock; + } + /* Must not register two RNGs with the same name. */ err = -EEXIST; list_for_each_entry(tmp, &rng_list, list) { -- cgit v0.10.2 From 27777890d0fae55d14ef18791fc7994faf1bc867 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Mon, 25 Feb 2013 16:20:05 +0000 Subject: powerpc: Fix compile of sha1-powerpc-asm.S on 32-bit When building with CRYPTO_SHA1_PPC enabled we fail with: powerpc/crypto/sha1-powerpc-asm.S: Assembler messages: powerpc/crypto/sha1-powerpc-asm.S:116: Error: can't resolve `0' {*ABS* section} - `STACKFRAMESIZE' {*UND* section} powerpc/crypto/sha1-powerpc-asm.S:116: Error: expression too complex powerpc/crypto/sha1-powerpc-asm.S:178: Error: unsupported relocation against STACKFRAMESIZE Use INT_FRAME_SIZE instead of STACKFRAMESIZE. Signed-off-by: Tony Breeds Tested-by: Christian Kujau Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/crypto/sha1-powerpc-asm.S b/arch/powerpc/crypto/sha1-powerpc-asm.S index a5f8264..125e165 100644 --- a/arch/powerpc/crypto/sha1-powerpc-asm.S +++ b/arch/powerpc/crypto/sha1-powerpc-asm.S @@ -113,7 +113,7 @@ STEPUP4((t)+16, fn) _GLOBAL(powerpc_sha_transform) - PPC_STLU r1,-STACKFRAMESIZE(r1) + PPC_STLU r1,-INT_FRAME_SIZE(r1) SAVE_8GPRS(14, r1) SAVE_10GPRS(22, r1) @@ -175,5 +175,5 @@ _GLOBAL(powerpc_sha_transform) REST_8GPRS(14, r1) REST_10GPRS(22, r1) - addi r1,r1,STACKFRAMESIZE + addi r1,r1,INT_FRAME_SIZE blr -- cgit v0.10.2 From 6b6680c4ea3952af8ae76915cbca41245147741b Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Mon, 25 Feb 2013 16:51:49 +0000 Subject: powerpc/pseries/hvcserver: Fix strncpy buffer limit in location code the dest buf len is 80 (HVCS_CLC_LENGTH + 1). the src buf len is PAGE_SIZE. if src buf string len is more than 80, it will cause issue. Signed-off-by: Chen Gang Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/hvcserver.c b/arch/powerpc/platforms/pseries/hvcserver.c index fcf4b4c..4557e91 100644 --- a/arch/powerpc/platforms/pseries/hvcserver.c +++ b/arch/powerpc/platforms/pseries/hvcserver.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -188,9 +189,9 @@ int hvcs_get_partner_info(uint32_t unit_address, struct list_head *head, = (unsigned int)last_p_partition_ID; /* copy the Null-term char too */ - strncpy(&next_partner_info->location_code[0], + strlcpy(&next_partner_info->location_code[0], (char *)&pi_buff[2], - strlen((char *)&pi_buff[2]) + 1); + sizeof(next_partner_info->location_code)); list_add_tail(&(next_partner_info->node), head); next_partner_info = NULL; -- cgit v0.10.2 From 9276dfd27897a0b29d8b5814f39a1f82f56b6b6b Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Mon, 25 Feb 2013 17:43:25 +0000 Subject: drivers/tty/hvc: Use strlcpy instead of strncpy when strlen pi->location_code is larger than HVCS_CLC_LENGTH + 1, original implementation can not let hvcsd->p_location_code NUL terminated. so need fix it (also can simplify the code) Signed-off-by: Chen Gang Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 1956593..81e939e 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -881,17 +881,12 @@ static struct vio_driver hvcs_vio_driver = { /* Only called from hvcs_get_pi please */ static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd) { - int clclength; - hvcsd->p_unit_address = pi->unit_address; hvcsd->p_partition_ID = pi->partition_ID; - clclength = strlen(&pi->location_code[0]); - if (clclength > HVCS_CLC_LENGTH) - clclength = HVCS_CLC_LENGTH; /* copy the null-term char too */ - strncpy(&hvcsd->p_location_code[0], - &pi->location_code[0], clclength + 1); + strlcpy(&hvcsd->p_location_code[0], + &pi->location_code[0], sizeof(hvcsd->p_location_code)); } /* -- cgit v0.10.2 From 6a404806dfceba9b154015705a9e647fa7749fd8 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 27 Feb 2013 10:45:52 +0000 Subject: powerpc: Avoid link stack corruption in MMU on syscall entry path Currently we use the link register to branch up high in the early MMU on syscall entry path. Unfortunately, this trashes the link stack as the address we are going to is not associated with the earlier mflr. This patch simply converts us to used the count register (volatile over syscalls anyway) instead. This is much better at predicting in this scenario and doesn't trash link stack causing a bunch of additional branch mispredicts later. Benchmarking this on POWER8 saves a bunch of cycles on Anton's null syscall benchmark here: http://ozlabs.org/~anton/junkcode/null_syscall.c Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index a8a5361..87ef8f5 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -74,13 +74,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ mflr r10 ; \ ld r12,PACAKBASE(r13) ; \ LOAD_HANDLER(r12, system_call_entry_direct) ; \ - mtlr r12 ; \ + mtctr r12 ; \ mfspr r12,SPRN_SRR1 ; \ /* Re-use of r13... No spare regs to do this */ \ li r13,MSR_RI ; \ mtmsrd r13,1 ; \ GET_PACA(r13) ; /* get r13 back */ \ - blr ; + bctr ; #else /* We can branch directly */ #define SYSCALL_PSERIES_2_DIRECT \ -- cgit v0.10.2 From a74f350b5ce6d8dd1847aa1191ea177fff025567 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 2 Mar 2013 04:06:30 +0000 Subject: powerpc: Remove unused BITOP_LE_SWIZZLE macro The BITOP_LE_SWIZZLE macro was used in the little-endian bitops functions for powerpc. But these functions were converted to generic bitops and the BITOP_LE_SWIZZLE is not used anymore. Signed-off-by: Akinobu Mita Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h index ef918a2..08bd299 100644 --- a/arch/powerpc/include/asm/bitops.h +++ b/arch/powerpc/include/asm/bitops.h @@ -52,8 +52,6 @@ #define smp_mb__before_clear_bit() smp_mb() #define smp_mb__after_clear_bit() smp_mb() -#define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7) - /* Macro for generating the ***_bits() functions */ #define DEFINE_BITOP(fn, op, prefix, postfix) \ static __inline__ void fn(unsigned long mask, \ -- cgit v0.10.2 From 8170a83f15eeca9a84ff895f1a89b58918425a3f Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Mon, 4 Mar 2013 15:57:30 +0000 Subject: powerpc: Wireup the kcmp syscall to sys_ni Since kmp takes 2 unsigned long args there should be a compat wrapper. Since one isn't provided I think it's safer just to hook this up to not implemented. If we need it later we can do it properly then. Signed-off-by: Tony Breeds Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 535b6d8..ebbec52 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -358,3 +358,4 @@ SYSCALL_SPU(setns) COMPAT_SYS(process_vm_readv) COMPAT_SYS(process_vm_writev) SYSCALL(finit_module) +SYSCALL(ni_syscall) /* sys_kcmp */ diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index f25b5c4..1487f0f 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -12,7 +12,7 @@ #include -#define __NR_syscalls 354 +#define __NR_syscalls 355 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/arch/powerpc/include/uapi/asm/unistd.h b/arch/powerpc/include/uapi/asm/unistd.h index 8c478c6..74cb4d7 100644 --- a/arch/powerpc/include/uapi/asm/unistd.h +++ b/arch/powerpc/include/uapi/asm/unistd.h @@ -376,6 +376,7 @@ #define __NR_process_vm_readv 351 #define __NR_process_vm_writev 352 #define __NR_finit_module 353 +#define __NR_kcmp 354 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */ -- cgit v0.10.2 From 57d231678ace658b3a73a0d144cfebbd4257bc0e Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 4 Mar 2013 19:45:50 +0000 Subject: powerpc: Fix setting FSCR for HV=0 and on secondary CPUs Currently we only set the FSCR (Facility Status and Control Register) when HV=1 but this feature is available when HV=0 also. This patch sets FSCR when HV=0. Also, we currently only set the FSCR on the master CPU. This patch also sets the FSCR on secondary CPUs. Signed-off-by: Michael Neuling cc: Ian Munsie Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index d29facb..bb2d203 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -48,6 +48,7 @@ _GLOBAL(__restore_cpu_power7) _GLOBAL(__setup_cpu_power8) mflr r11 + bl __init_FSCR bl __init_hvmode_206 mtlr r11 beqlr @@ -56,13 +57,13 @@ _GLOBAL(__setup_cpu_power8) mfspr r3,SPRN_LPCR oris r3, r3, LPCR_AIL_3@h bl __init_LPCR - bl __init_FSCR bl __init_TLB mtlr r11 blr _GLOBAL(__restore_cpu_power8) mflr r11 + bl __init_FSCR mfmsr r3 rldicl. r0,r3,4,63 beqlr -- cgit v0.10.2 From fa759e9b0984748cf626aac59bca60bdab42c644 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 4 Mar 2013 19:45:51 +0000 Subject: powerpc: Add DSCR FSCR register bit definition This sets the DSCR (Data Stream Control Register) in the FSCR (Facility Status & Control Register). Also harmonise TAR (Target Address Register) FSCR bit definition too. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index e665861..c9c67fc 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -266,7 +266,8 @@ #define SPRN_HSRR0 0x13A /* Hypervisor Save/Restore 0 */ #define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */ #define SPRN_FSCR 0x099 /* Facility Status & Control Register */ -#define FSCR_TAR (1<<8) /* Enable Target Adress Register */ +#define FSCR_TAR (1 << (63-55)) /* Enable Target Address Register */ +#define FSCR_DSCR (1 << (63-61)) /* Enable Data Stream Control Register */ #define SPRN_TAR 0x32f /* Target Address Register */ #define SPRN_LPCR 0x13E /* LPAR Control Register */ #define LPCR_VPM0 (1ul << (63-0)) -- cgit v0.10.2 From 54c9b2253d34e8998e4bff9ac2d7a3ba0b861d52 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 4 Mar 2013 19:45:52 +0000 Subject: powerpc: Set DSCR bit in FSCR setup We support DSCR (Data Stream Control Register) so we should make sure we set it in the FSCR (Facility Status & Control Register) incase some firmwares don't set it. If we don't set this, we'll take a facility unavailable exception when using the DSCR. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index bb2d203..ea847ab 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -116,7 +116,7 @@ __init_LPCR: __init_FSCR: mfspr r3,SPRN_FSCR - ori r3,r3,FSCR_TAR + ori r3,r3,FSCR_TAR|FSCR_DSCR mtspr SPRN_FSCR,r3 blr -- cgit v0.10.2 From e08f626b33eb636dbf38b21618ab32b7fd8e1ec4 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 20 Feb 2013 03:06:34 +0000 Subject: e1000e: workaround DMA unit hang on I218 At 1000Mbps link speed, one of the MAC's internal clocks can be stopped for up to 4us when entering K1 (a power mode of the MAC-PHY interconnect). If the MAC is waiting for completion indications for 2 DMA write requests into Host memory (e.g. descriptor writeback or Rx packet writing) and the indications occur while the clock is stopped, both indications will be missed by the MAC causing the MAC to wait for the completion indications and be unable to generate further DMA write requests. This results in an apparent hardware hang. Work-around the issue by disabling the de-assertion of the clock request when 1000Mbps link is acquired (K1 must be disabled while doing this). Signed-off-by: Bruce Allan Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index dff7bff..121a865 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -782,6 +782,59 @@ release: } /** + * e1000_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP + * @hw: pointer to the HW structure + * @link: link up bool flag + * + * When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications + * preventing further DMA write requests. Workaround the issue by disabling + * the de-assertion of the clock request when in 1Gpbs mode. + **/ +static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link) +{ + u32 fextnvm6 = er32(FEXTNVM6); + s32 ret_val = 0; + + if (link && (er32(STATUS) & E1000_STATUS_SPEED_1000)) { + u16 kmrn_reg; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + + ret_val = + e1000e_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, + &kmrn_reg); + if (ret_val) + goto release; + + ret_val = + e1000e_write_kmrn_reg_locked(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + kmrn_reg & + ~E1000_KMRNCTRLSTA_K1_ENABLE); + if (ret_val) + goto release; + + usleep_range(10, 20); + + ew32(FEXTNVM6, fextnvm6 | E1000_FEXTNVM6_REQ_PLL_CLK); + + ret_val = + e1000e_write_kmrn_reg_locked(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + kmrn_reg); +release: + hw->phy.ops.release(hw); + } else { + /* clear FEXTNVM6 bit 8 on link down or 10/100 */ + ew32(FEXTNVM6, fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK); + } + + return ret_val; +} + +/** * e1000_check_for_copper_link_ich8lan - Check for link (Copper) * @hw: pointer to the HW structure * @@ -818,6 +871,14 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) return ret_val; } + /* Work-around I218 hang issue */ + if ((hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_LM) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_V)) { + ret_val = e1000_k1_workaround_lpt_lp(hw, link); + if (ret_val) + return ret_val; + } + /* Clear link partner's EEE ability */ hw->dev_spec.ich8lan.eee_lp_ability = 0; @@ -3954,8 +4015,16 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw) phy_ctrl = er32(PHY_CTRL); phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE; + if (hw->phy.type == e1000_phy_i217) { - u16 phy_reg; + u16 phy_reg, device_id = hw->adapter->pdev->device; + + if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) || + (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V)) { + u32 fextnvm6 = er32(FEXTNVM6); + + ew32(FEXTNVM6, fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK); + } ret_val = hw->phy.ops.acquire(hw); if (ret_val) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index b6d3174..8bf4655 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -92,6 +92,8 @@ #define E1000_FEXTNVM4_BEACON_DURATION_8USEC 0x7 #define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3 +#define E1000_FEXTNVM6_REQ_PLL_CLK 0x00000100 + #define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL #define E1000_ICH_RAR_ENTRIES 7 diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h index 794fe14..a7e6a3e 100644 --- a/drivers/net/ethernet/intel/e1000e/regs.h +++ b/drivers/net/ethernet/intel/e1000e/regs.h @@ -42,6 +42,7 @@ #define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ #define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */ #define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */ +#define E1000_FEXTNVM6 0x00010 /* Future Extended NVM 6 - RW */ #define E1000_FEXTNVM7 0x000E4 /* Future Extended NVM 7 - RW */ #define E1000_FCT 0x00030 /* Flow Control Type - RW */ #define E1000_VET 0x00038 /* VLAN Ether Type - RW */ -- cgit v0.10.2 From e4f7dbb17e797d922d72567f37de3735722034ba Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 21 Feb 2013 03:08:50 +0000 Subject: igb: Drop BUILD_BUG_ON check from igb_build_rx_buffer On s390 the igb driver was throwing a build error due to the fact that a frame built using build_skb would be larger than 2K. Since this is not likely to change at any point in the future we are better off just dropping the check since we already had a check in igb_set_rx_buffer_len that will just disable the usage of build_skb anyway. Signed-off-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ed79a1c..4d53a17 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6227,13 +6227,6 @@ static struct sk_buff *igb_build_rx_buffer(struct igb_ring *rx_ring, /* If we spanned a buffer we have a huge mess so test for it */ BUG_ON(unlikely(!igb_test_staterr(rx_desc, E1000_RXD_STAT_EOP))); - /* Guarantee this function can be used by verifying buffer sizes */ - BUILD_BUG_ON(SKB_WITH_OVERHEAD(IGB_RX_BUFSZ) < (NET_SKB_PAD + - NET_IP_ALIGN + - IGB_TS_HDR_LEN + - ETH_FRAME_LEN + - ETH_FCS_LEN)); - rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean]; page = rx_buffer->page; prefetchw(page); -- cgit v0.10.2 From ed65bdd8c0086d69948e6380dba0cc279a6906de Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Wed, 6 Feb 2013 03:35:27 +0000 Subject: igb: Fix link setup for I210 devices This patch changes the setup copper link function to use a switch statement for the PHY id's available for the given PHY types. It also adds a case for the I210 PHY id, so the appropriate setup link function is called for it. Signed-off-by: Carolyn Wyborny Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 84e7e09..b64542a 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -1361,11 +1361,16 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) switch (hw->phy.type) { case e1000_phy_i210: case e1000_phy_m88: - if (hw->phy.id == I347AT4_E_PHY_ID || - hw->phy.id == M88E1112_E_PHY_ID) + switch (hw->phy.id) { + case I347AT4_E_PHY_ID: + case M88E1112_E_PHY_ID: + case I210_I_PHY_ID: ret_val = igb_copper_link_setup_m88_gen2(hw); - else + break; + default: ret_val = igb_copper_link_setup_m88(hw); + break; + } break; case e1000_phy_igp_3: ret_val = igb_copper_link_setup_igp(hw); -- cgit v0.10.2 From 603e86fa39cd48edba5ee8a4d19637bd41e2a8bf Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Wed, 20 Feb 2013 07:40:55 +0000 Subject: igb: Fix for lockdep issue in igb_get_i2c_client This patch fixes a lockdep warning in igb_get_i2c_client by refactoring the initialization and usage of the i2c_client completely. There is no on the fly allocation of the single client needed today. Signed-off-by: Carolyn Wyborny Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index d27edbc..2515140 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -447,7 +447,7 @@ struct igb_adapter { #endif struct i2c_algo_bit_data i2c_algo; struct i2c_adapter i2c_adap; - struct igb_i2c_client_list *i2c_clients; + struct i2c_client *i2c_client; }; #define IGB_FLAG_HAS_MSI (1 << 0) diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c index 0a9b073..4623502 100644 --- a/drivers/net/ethernet/intel/igb/igb_hwmon.c +++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c @@ -39,6 +39,10 @@ #include #ifdef CONFIG_IGB_HWMON +struct i2c_board_info i350_sensor_info = { + I2C_BOARD_INFO("i350bb", (0Xf8 >> 1)), +}; + /* hwmon callback functions */ static ssize_t igb_hwmon_show_location(struct device *dev, struct device_attribute *attr, @@ -188,6 +192,7 @@ int igb_sysfs_init(struct igb_adapter *adapter) unsigned int i; int n_attrs; int rc = 0; + struct i2c_client *client = NULL; /* If this method isn't defined we don't support thermals */ if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL) @@ -198,6 +203,15 @@ int igb_sysfs_init(struct igb_adapter *adapter) if (rc) goto exit; + /* init i2c_client */ + client = i2c_new_device(&adapter->i2c_adap, &i350_sensor_info); + if (client == NULL) { + dev_info(&adapter->pdev->dev, + "Failed to create new i2c device..\n"); + goto exit; + } + adapter->i2c_client = client; + /* Allocation space for max attributes * max num sensors * values (loc, temp, max, caution) */ diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 4d53a17..4dbd629 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1923,10 +1923,6 @@ void igb_set_fw_version(struct igb_adapter *adapter) return; } -static const struct i2c_board_info i350_sensor_info = { - I2C_BOARD_INFO("i350bb", 0Xf8), -}; - /* igb_init_i2c - Init I2C interface * @adapter: pointer to adapter structure * @@ -7717,67 +7713,6 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba) } } -static DEFINE_SPINLOCK(i2c_clients_lock); - -/* igb_get_i2c_client - returns matching client - * in adapters's client list. - * @adapter: adapter struct - * @dev_addr: device address of i2c needed. - */ -static struct i2c_client * -igb_get_i2c_client(struct igb_adapter *adapter, u8 dev_addr) -{ - ulong flags; - struct igb_i2c_client_list *client_list; - struct i2c_client *client = NULL; - struct i2c_board_info client_info = { - I2C_BOARD_INFO("igb", 0x00), - }; - - spin_lock_irqsave(&i2c_clients_lock, flags); - client_list = adapter->i2c_clients; - - /* See if we already have an i2c_client */ - while (client_list) { - if (client_list->client->addr == (dev_addr >> 1)) { - client = client_list->client; - goto exit; - } else { - client_list = client_list->next; - } - } - - /* no client_list found, create a new one */ - client_list = kzalloc(sizeof(*client_list), GFP_ATOMIC); - if (client_list == NULL) - goto exit; - - /* dev_addr passed to us is left-shifted by 1 bit - * i2c_new_device call expects it to be flush to the right. - */ - client_info.addr = dev_addr >> 1; - client_info.platform_data = adapter; - client_list->client = i2c_new_device(&adapter->i2c_adap, &client_info); - if (client_list->client == NULL) { - dev_info(&adapter->pdev->dev, - "Failed to create new i2c device..\n"); - goto err_no_client; - } - - /* insert new client at head of list */ - client_list->next = adapter->i2c_clients; - adapter->i2c_clients = client_list; - - client = client_list->client; - goto exit; - -err_no_client: - kfree(client_list); -exit: - spin_unlock_irqrestore(&i2c_clients_lock, flags); - return client; -} - /* igb_read_i2c_byte - Reads 8 bit word over I2C * @hw: pointer to hardware structure * @byte_offset: byte offset to read @@ -7791,7 +7726,7 @@ s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data) { struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw); - struct i2c_client *this_client = igb_get_i2c_client(adapter, dev_addr); + struct i2c_client *this_client = adapter->i2c_client; s32 status; u16 swfw_mask = 0; @@ -7828,7 +7763,7 @@ s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset, u8 dev_addr, u8 data) { struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw); - struct i2c_client *this_client = igb_get_i2c_client(adapter, dev_addr); + struct i2c_client *this_client = adapter->i2c_client; s32 status; u16 swfw_mask = E1000_SWFW_PHY0_SM; -- cgit v0.10.2 From a4ed2e737cb73e4405a3649f8aef7619b99fecae Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Tue, 5 Mar 2013 06:09:04 +0000 Subject: net/irda: Fix port open counts Saving the port count bump is unsafe. If the tty is hung up while this open was blocking, the port count is zeroed. Explicitly check if the tty was hung up while blocking, and correct the port count if not. Signed-off-by: Peter Hurley Signed-off-by: David S. Miller diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 9a5fd3c..1721dc7 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -280,7 +280,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, struct tty_port *port = &self->port; DECLARE_WAITQUEUE(wait, current); int retval; - int do_clocal = 0, extra_count = 0; + int do_clocal = 0; unsigned long flags; IRDA_DEBUG(2, "%s()\n", __func__ ); @@ -315,10 +315,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, __FILE__, __LINE__, tty->driver->name, port->count); spin_lock_irqsave(&port->lock, flags); - if (!tty_hung_up_p(filp)) { - extra_count = 1; + if (!tty_hung_up_p(filp)) port->count--; - } spin_unlock_irqrestore(&port->lock, flags); port->blocked_open++; @@ -361,12 +359,10 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, __set_current_state(TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); - if (extra_count) { - /* ++ is not atomic, so this should be protected - Jean II */ - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->lock, flags); + if (!tty_hung_up_p(filp)) port->count++; - spin_unlock_irqrestore(&port->lock, flags); - } + spin_unlock_irqrestore(&port->lock, flags); port->blocked_open--; IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n", -- cgit v0.10.2 From 2f7c069b96ed7b1f6236f2fa7b0bc06f4f54f2d9 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Tue, 5 Mar 2013 06:09:05 +0000 Subject: net/irda: Hold port lock while bumping blocked_open Although tty_lock() already protects concurrent update to blocked_open, that fails to meet the separation-of-concerns between tty_port and tty. Signed-off-by: Peter Hurley Signed-off-by: David S. Miller diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 1721dc7..d282bbe 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -317,8 +317,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, spin_lock_irqsave(&port->lock, flags); if (!tty_hung_up_p(filp)) port->count--; - spin_unlock_irqrestore(&port->lock, flags); port->blocked_open++; + spin_unlock_irqrestore(&port->lock, flags); while (1) { if (tty->termios.c_cflag & CBAUD) @@ -362,8 +362,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, spin_lock_irqsave(&port->lock, flags); if (!tty_hung_up_p(filp)) port->count++; - spin_unlock_irqrestore(&port->lock, flags); port->blocked_open--; + spin_unlock_irqrestore(&port->lock, flags); IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n", __FILE__, __LINE__, tty->driver->name, port->count); -- cgit v0.10.2 From 0b176ce3a7cbfa92eceddf3896f1a504877d974a Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Tue, 5 Mar 2013 06:09:06 +0000 Subject: net/irda: Use barrier to set task state Without a memory and compiler barrier, the task state change can migrate relative to the condition testing in a blocking loop. However, the task state change must be visible across all cpus prior to testing those conditions. Failing to do this can result in the familiar 'lost wakeup' and this task will hang until killed. Signed-off-by: Peter Hurley Signed-off-by: David S. Miller diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index d282bbe..522543d 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -324,7 +324,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, if (tty->termios.c_cflag & CBAUD) tty_port_raise_dtr_rts(port); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !test_bit(ASYNCB_INITIALIZED, &port->flags)) { -- cgit v0.10.2 From f74861ca87264e594e0134e8ac14db06be77fe6f Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Tue, 5 Mar 2013 06:09:07 +0000 Subject: net/irda: Raise dtr in non-blocking open DTR/RTS need to be raised, regardless of the open() mode, but not if the port has already shutdown. Signed-off-by: Peter Hurley Signed-off-by: David S. Miller diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 522543d..362ba47 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -289,8 +289,15 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ - if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ - /* nonblock mode is set or port is not enabled */ + if (test_bit(TTY_IO_ERROR, &tty->flags)) { + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (filp->f_flags & O_NONBLOCK) { + /* nonblock mode is set */ + if (tty->termios.c_cflag & CBAUD) + tty_port_raise_dtr_rts(port); port->flags |= ASYNC_NORMAL_ACTIVE; IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ ); return 0; -- cgit v0.10.2 From 9b99b7e90bf5cd9a88823c49574ba80d92a98262 Mon Sep 17 00:00:00 2001 From: Paolo Valente Date: Tue, 5 Mar 2013 08:04:57 +0000 Subject: pkt_sched: sch_qfq: properly cap timestamps in charge_actual_service QFQ+ schedules the active aggregates in a group using a bucket list (one list per group). The bucket in which each aggregate is inserted depends on the aggregate's timestamps, and the number of buckets in a group is enough to accomodate the possible (range of) values of the timestamps of all the aggregates in the group. For this property to hold, timestamps must however be computed correctly. One necessary condition for computing timestamps correctly is that the number of bits dequeued for each aggregate, while the aggregate is in service, does not exceed the maximum budget budgetmax assigned to the aggregate. For each aggregate, budgetmax is proportional to the number of classes in the aggregate. If the number of classes of the aggregate is decreased through qfq_change_class(), then budgetmax is decreased automatically as well. Problems may occur if the aggregate is in service when budgetmax is decreased, because the current remaining budget of the aggregate and/or the service already received by the aggregate may happen to be larger than the new value of budgetmax. In this case, when the aggregate is eventually deselected and its timestamps are updated, the aggregate may happen to have received an amount of service larger than budgetmax. This may cause the aggregate to be assigned a higher virtual finish time than the maximum acceptable value for the last bucket in the bucket list of the group. This fix introduces a cap that addresses this issue. Signed-off-by: Paolo Valente Reviewed-by: Fabio Checconi Signed-off-by: David S. Miller diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index e9a77f6..489edd9 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -298,6 +298,10 @@ static void qfq_update_agg(struct qfq_sched *q, struct qfq_aggregate *agg, new_num_classes == q->max_agg_classes - 1) /* agg no more full */ hlist_add_head(&agg->nonfull_next, &q->nonfull_aggs); + /* The next assignment may let + * agg->initial_budget > agg->budgetmax + * hold, we will take it into account in charge_actual_service(). + */ agg->budgetmax = new_num_classes * agg->lmax; new_agg_weight = agg->class_weight * new_num_classes; agg->inv_w = ONE_FP/new_agg_weight; @@ -988,8 +992,13 @@ static inline struct sk_buff *qfq_peek_skb(struct qfq_aggregate *agg, /* Update F according to the actual service received by the aggregate. */ static inline void charge_actual_service(struct qfq_aggregate *agg) { - /* compute the service received by the aggregate */ - u32 service_received = agg->initial_budget - agg->budget; + /* Compute the service received by the aggregate, taking into + * account that, after decreasing the number of classes in + * agg, it may happen that + * agg->initial_budget - agg->budget > agg->bugdetmax + */ + u32 service_received = min(agg->budgetmax, + agg->initial_budget - agg->budget); agg->F = agg->S + (u64)service_received * agg->inv_w; } -- cgit v0.10.2 From 624b85fb96206879c8146abdba071222bbd25259 Mon Sep 17 00:00:00 2001 From: Paolo Valente Date: Tue, 5 Mar 2013 08:04:58 +0000 Subject: pkt_sched: sch_qfq: fix the update of eligible-group sets Between two invocations of make_eligible, the system virtual time may happen to grow enough that, in its binary representation, a bit with higher order than 31 flips. This happens especially with TSO/GSO. Before this fix, the mask used in make_eligible was computed as (1UL< 31. The fix just replaces 1UL with 1ULL. Signed-off-by: Paolo Valente Reviewed-by: Fabio Checconi Signed-off-by: David S. Miller diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 489edd9..39d85cc 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -821,7 +821,7 @@ static void qfq_make_eligible(struct qfq_sched *q) unsigned long old_vslot = q->oldV >> q->min_slot_shift; if (vslot != old_vslot) { - unsigned long mask = (1UL << fls(vslot ^ old_vslot)) - 1; + unsigned long mask = (1ULL << fls(vslot ^ old_vslot)) - 1; qfq_move_groups(q, mask, IR, ER); qfq_move_groups(q, mask, IB, EB); } -- cgit v0.10.2 From 2f3b89a1fe0823fceb544856c9eeb036a75ff091 Mon Sep 17 00:00:00 2001 From: Paolo Valente Date: Tue, 5 Mar 2013 08:04:59 +0000 Subject: pkt_sched: sch_qfq: serve activated aggregates immediately if the scheduler is empty If no aggregate is in service, then the function qfq_dequeue() does not dequeue any packet. For this reason, to guarantee QFQ+ to be work conserving, a just-activated aggregate must be set as in service immediately if it happens to be the only active aggregate. This is done by the function qfq_enqueue(). Unfortunately, the function qfq_add_to_agg(), used to add a class to an aggregate, does not perform this important additional operation. In particular, if: 1) qfq_add_to_agg() is invoked to complete the move of a class from a source aggregate, becoming, for this move, inactive, to a destination aggregate, becoming instead active, and 2) the destination aggregate becomes the only active aggregate, then this aggregate is not however set as in service. QFQ+ remains then in a non-work-conserving state until a new invocation of qfq_enqueue() recovers the situation. This fix solves the problem by moving the logic for setting an aggregate as in service directly into the function qfq_activate_agg(). Hence, from whatever point qfq_activate_aggregate() is invoked, QFQ+ remains work conserving. Since the more-complex logic of this new version of activate_aggregate() is not necessary, in qfq_dequeue(), to reschedule an aggregate that finishes its budget, then the aggregate is now rescheduled by invoking directly the functions needed. Signed-off-by: Paolo Valente Reviewed-by: Fabio Checconi Signed-off-by: David S. Miller diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 39d85cc..8c5172c 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -1003,6 +1003,12 @@ static inline void charge_actual_service(struct qfq_aggregate *agg) agg->F = agg->S + (u64)service_received * agg->inv_w; } +static inline void qfq_update_agg_ts(struct qfq_sched *q, + struct qfq_aggregate *agg, + enum update_reason reason); + +static void qfq_schedule_agg(struct qfq_sched *q, struct qfq_aggregate *agg); + static struct sk_buff *qfq_dequeue(struct Qdisc *sch) { struct qfq_sched *q = qdisc_priv(sch); @@ -1030,7 +1036,7 @@ static struct sk_buff *qfq_dequeue(struct Qdisc *sch) in_serv_agg->initial_budget = in_serv_agg->budget = in_serv_agg->budgetmax; - if (!list_empty(&in_serv_agg->active)) + if (!list_empty(&in_serv_agg->active)) { /* * Still active: reschedule for * service. Possible optimization: if no other @@ -1041,8 +1047,9 @@ static struct sk_buff *qfq_dequeue(struct Qdisc *sch) * handle it, we would need to maintain an * extra num_active_aggs field. */ - qfq_activate_agg(q, in_serv_agg, requeue); - else if (sch->q.qlen == 0) { /* no aggregate to serve */ + qfq_update_agg_ts(q, in_serv_agg, requeue); + qfq_schedule_agg(q, in_serv_agg); + } else if (sch->q.qlen == 0) { /* no aggregate to serve */ q->in_serv_agg = NULL; return NULL; } @@ -1226,17 +1233,11 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) cl->deficit = agg->lmax; list_add_tail(&cl->alist, &agg->active); - if (list_first_entry(&agg->active, struct qfq_class, alist) != cl) - return err; /* aggregate was not empty, nothing else to do */ - - /* recharge budget */ - agg->initial_budget = agg->budget = agg->budgetmax; + if (list_first_entry(&agg->active, struct qfq_class, alist) != cl || + q->in_serv_agg == agg) + return err; /* non-empty or in service, nothing else to do */ - qfq_update_agg_ts(q, agg, enqueue); - if (q->in_serv_agg == NULL) - q->in_serv_agg = agg; - else if (agg != q->in_serv_agg) - qfq_schedule_agg(q, agg); + qfq_activate_agg(q, agg, enqueue); return err; } @@ -1293,8 +1294,15 @@ skip_update: static void qfq_activate_agg(struct qfq_sched *q, struct qfq_aggregate *agg, enum update_reason reason) { + agg->initial_budget = agg->budget = agg->budgetmax; /* recharge budg. */ + qfq_update_agg_ts(q, agg, reason); - qfq_schedule_agg(q, agg); + if (q->in_serv_agg == NULL) { /* no aggr. in service or scheduled */ + q->in_serv_agg = agg; /* start serving this aggregate */ + /* update V: to be in service, agg must be eligible */ + q->oldV = q->V = agg->S; + } else if (agg != q->in_serv_agg) + qfq_schedule_agg(q, agg); } static void qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp, -- cgit v0.10.2 From a0143efa96671dc51dab9bba776a66f9bfa1757f Mon Sep 17 00:00:00 2001 From: Paolo Valente Date: Tue, 5 Mar 2013 08:05:00 +0000 Subject: pkt_sched: sch_qfq: prevent budget from wrapping around after a dequeue Aggregate budgets are computed so as to guarantee that, after an aggregate has been selected for service, that aggregate has enough budget to serve at least one maximum-size packet for the classes it contains. For this reason, after a new aggregate has been selected for service, its next packet is immediately dequeued, without any further control. The maximum packet size for a class, lmax, can be changed through qfq_change_class(). In case the user sets lmax to a lower value than the the size of some of the still-to-arrive packets, QFQ+ will automatically push up lmax as it enqueues these packets. This automatic push up is likely to happen with TSO/GSO. In any case, if lmax is assigned a lower value than the size of some of the packets already enqueued for the class, then the following problem may occur: the size of the next packet to dequeue for the class may happen to be larger than lmax, after the aggregate to which the class belongs has been just selected for service. In this case, even the budget of the aggregate, which is an unsigned value, may be lower than the size of the next packet to dequeue. After dequeueing this packet and subtracting its size from the budget, the latter would wrap around. This fix prevents the budget from wrapping around after any packet dequeue. Signed-off-by: Paolo Valente Reviewed-by: Fabio Checconi Signed-off-by: David S. Miller diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 8c5172c..c34af93 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -1068,7 +1068,15 @@ static struct sk_buff *qfq_dequeue(struct Qdisc *sch) qdisc_bstats_update(sch, skb); agg_dequeue(in_serv_agg, cl, len); - in_serv_agg->budget -= len; + /* If lmax is lowered, through qfq_change_class, for a class + * owning pending packets with larger size than the new value + * of lmax, then the following condition may hold. + */ + if (unlikely(in_serv_agg->budget < len)) + in_serv_agg->budget = 0; + else + in_serv_agg->budget -= len; + q->V += (u64)len * IWSUM; pr_debug("qfq dequeue: len %u F %lld now %lld\n", len, (unsigned long long) in_serv_agg->F, -- cgit v0.10.2 From 40dd2d546198e7bbb8d3fe718957b158caa3fe52 Mon Sep 17 00:00:00 2001 From: Paolo Valente Date: Tue, 5 Mar 2013 08:05:01 +0000 Subject: pkt_sched: sch_qfq: do not allow virtual time to jump if an aggregate is in service By definition of (the algorithm of) QFQ+, the system virtual time must be pushed up only if there is no 'eligible' aggregate, i.e. no aggregate that would have started to be served also in the ideal system emulated by QFQ+. QFQ+ serves only eligible aggregates, hence the aggregate currently in service is eligible. As a consequence, to decide whether there is no eligible aggregate, QFQ+ must also check whether there is no aggregate in service. Signed-off-by: Paolo Valente Reviewed-by: Fabio Checconi Signed-off-by: David S. Miller diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index c34af93..6b7ce80 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -1279,7 +1279,8 @@ static void qfq_schedule_agg(struct qfq_sched *q, struct qfq_aggregate *agg) /* group was surely ineligible, remove */ __clear_bit(grp->index, &q->bitmaps[IR]); __clear_bit(grp->index, &q->bitmaps[IB]); - } else if (!q->bitmaps[ER] && qfq_gt(roundedS, q->V)) + } else if (!q->bitmaps[ER] && qfq_gt(roundedS, q->V) && + q->in_serv_agg == NULL) q->V = roundedS; grp->S = roundedS; -- cgit v0.10.2 From 76e4cb0d3a583900f844f1704b19b7e8c5df8837 Mon Sep 17 00:00:00 2001 From: Paolo Valente Date: Tue, 5 Mar 2013 08:05:02 +0000 Subject: pkt_sched: sch_qfq: remove a useless invocation of qfq_update_eligible QFQ+ can select for service only 'eligible' aggregates, i.e., aggregates that would have started to be served also in the emulated ideal system. As a consequence, for QFQ+ to be work conserving, at least one of the active aggregates must be eligible when it is time to choose the next aggregate to serve. The set of eligible aggregates is updated through the function qfq_update_eligible(), which does guarantee that, after its invocation, at least one of the active aggregates is eligible. Because of this property, this function is invoked in qfq_deactivate_agg() to guarantee that at least one of the active aggregates is still eligible after an aggregate has been deactivated. In particular, the critical case is when there are other active aggregates, but the aggregate being deactivated happens to be the only one eligible. However, this precaution is not needed for QFQ+ to be work conserving, because update_eligible() is always invoked also at the beginning of qfq_choose_next_agg(). This patch removes the additional invocation of update_eligible() in qfq_deactivate_agg(). Signed-off-by: Paolo Valente Reviewed-by: Fabio Checconi Signed-off-by: David S. Miller diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 6b7ce80..d51852b 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -1383,8 +1383,6 @@ static void qfq_deactivate_agg(struct qfq_sched *q, struct qfq_aggregate *agg) __set_bit(grp->index, &q->bitmaps[s]); } } - - qfq_update_eligible(q); } static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg) -- cgit v0.10.2 From 88c4c066c6b4db26dc4909ee94e6bf377e8e8e81 Mon Sep 17 00:00:00 2001 From: Zang MingJie Date: Mon, 4 Mar 2013 06:07:34 +0000 Subject: reset nf before xmit vxlan encapsulated packet We should reset nf settings bond to the skb as ipip/ipgre do. If not, the conntrack/nat info bond to the origin packet may continually redirect the packet to vxlan interface causing a routing loop. this is the scenario: VETP VXLAN Gateway /----\ /---------------\ | | | | | vx+--+vx --NAT-> eth0+--> Internet | | | | \----/ \---------------/ when there are any packet coming from internet to the vetp, there will be lots of garbage packets coming out the gateway's vxlan interface, but none actually sent to the physical interface, because they are redirected back to the vxlan interface in the postrouting chain of NAT rule, and dmesg complains: Mar 1 21:52:53 debian kernel: [ 8802.997699] Dead loop on virtual device vxlan0, fix it urgently! Mar 1 21:52:54 debian kernel: [ 8804.004907] Dead loop on virtual device vxlan0, fix it urgently! Mar 1 21:52:55 debian kernel: [ 8805.012189] Dead loop on virtual device vxlan0, fix it urgently! Mar 1 21:52:56 debian kernel: [ 8806.020593] Dead loop on virtual device vxlan0, fix it urgently! the patch should fix the problem Signed-off-by: Zang MingJie Signed-off-by: David S. Miller diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index f10e58a..c3e3d29 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -961,6 +961,8 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) iph->ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); tunnel_ip_select_ident(skb, old_iph, &rt->dst); + nf_reset(skb); + vxlan_set_owner(dev, skb); /* See iptunnel_xmit() */ -- cgit v0.10.2 From 691b3b7e1329141acf1e5ed44d8b468cea065fe3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 4 Mar 2013 12:32:43 +0000 Subject: net: fix new kernel-doc warnings in net core Fix new kernel-doc warnings in net/core/dev.c: Warning(net/core/dev.c:4788): No description found for parameter 'new_carrier' Warning(net/core/dev.c:4788): Excess function parameter 'new_carries' description in 'dev_change_carrier' Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index a06a7a5..5ca8734 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4780,7 +4780,7 @@ EXPORT_SYMBOL(dev_set_mac_address); /** * dev_change_carrier - Change device carrier * @dev: device - * @new_carries: new value + * @new_carrier: new value * * Change device carrier */ -- cgit v0.10.2 From d1f41b67ff7735193bc8b418b98ac99a448833e2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 5 Mar 2013 07:15:13 +0000 Subject: net: reduce net_rx_action() latency to 2 HZ We should use time_after_eq() to get maximum latency of two ticks, instead of three. Bug added in commit 24f8b2385 (net: increase receive packet quantum) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 5ca8734..8f152f9 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4103,7 +4103,7 @@ static void net_rx_action(struct softirq_action *h) * Allow this to run for 2 jiffies since which will allow * an average latency of 1.5/HZ. */ - if (unlikely(budget <= 0 || time_after(jiffies, time_limit))) + if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit))) goto softnet_break; local_irq_enable(); -- cgit v0.10.2 From fa2b04f4502d74659e4e4b1294c6d88e08ece032 Mon Sep 17 00:00:00 2001 From: David Ward Date: Tue, 5 Mar 2013 17:06:32 +0000 Subject: net/ipv4: Timestamp option cannot overflow with prespecified addresses When a router forwards a packet that contains the IPv4 timestamp option, if there is no space left in the option for the router to add its own timestamp, then the router increments the Overflow value in the option. However, if the addresses of the routers are prespecified in the option, then the overflow condition cannot happen: the option is structured so that each prespecified router has a place to write its timestamp. Other routers do not add a timestamp, so there will never be a lack of space. This fix ensures that the Overflow value in the IPv4 timestamp option is not incremented when the addresses of the routers are prespecified, even if the Pointer value is greater than the Length value. Signed-off-by: David Ward Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index f6289bf..310a364 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -423,7 +423,7 @@ int ip_options_compile(struct net *net, put_unaligned_be32(midtime, timeptr); opt->is_changed = 1; } - } else { + } else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) { unsigned int overflow = optptr[3]>>4; if (overflow == 15) { pp_ptr = optptr + 3; -- cgit v0.10.2 From 66d29cbc59433ba538922a9e958495156b31b83b Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Sun, 3 Mar 2013 21:48:46 +0000 Subject: benet: Wait f/w POST until timeout While PCI card faces EEH errors, reset (usually hot reset) is expected to recover from the EEH errors. After EEH core finishes the reset, the driver callback (be_eeh_reset) is called and wait the firmware to complete POST successfully. The original code would return with error once detecting failure during POST stage. That seems not enough. The patch forces the driver (be_eeh_reset) to wait the firmware completes POST until timeout, instead of returning error upon detection POST failure immediately. Also, it would improve the reliability of the EEH funtionality of the driver. Signed-off-by: Gavin Shan Acked-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 071aea7..813407f 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -473,7 +473,7 @@ static int be_mbox_notify_wait(struct be_adapter *adapter) return 0; } -static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage) +static void be_POST_stage_get(struct be_adapter *adapter, u16 *stage) { u32 sem; u32 reg = skyhawk_chip(adapter) ? SLIPORT_SEMAPHORE_OFFSET_SH : @@ -481,11 +481,6 @@ static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage) pci_read_config_dword(adapter->pdev, reg, &sem); *stage = sem & POST_STAGE_MASK; - - if ((sem >> POST_ERR_SHIFT) & POST_ERR_MASK) - return -1; - else - return 0; } int lancer_wait_ready(struct be_adapter *adapter) @@ -579,19 +574,17 @@ int be_fw_wait_ready(struct be_adapter *adapter) } do { - status = be_POST_stage_get(adapter, &stage); - if (status) { - dev_err(dev, "POST error; stage=0x%x\n", stage); - return -1; - } else if (stage != POST_STAGE_ARMFW_RDY) { - if (msleep_interruptible(2000)) { - dev_err(dev, "Waiting for POST aborted\n"); - return -EINTR; - } - timeout += 2; - } else { + be_POST_stage_get(adapter, &stage); + if (stage == POST_STAGE_ARMFW_RDY) return 0; + + dev_info(dev, "Waiting for POST, %ds elapsed\n", + timeout); + if (msleep_interruptible(2000)) { + dev_err(dev, "Waiting for POST aborted\n"); + return -EINTR; } + timeout += 2; } while (timeout < 60); dev_err(dev, "POST timeout; stage=0x%x\n", stage); -- cgit v0.10.2 From 35205b211c8d17a8a0b5e8926cb7c73e9a7ef1ad 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() 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 diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 50247df..d2f790d 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -171,9 +171,9 @@ static inline void efx_device_detach_sync(struct efx_nic *efx) * 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 */ -- cgit v0.10.2 From c73e787a8db9117d59b5180baf83203a42ecadca Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 5 Mar 2013 17:49:39 +0000 Subject: sfc: Correct efx_rx_buffer::page_offset when EFX_PAGE_IP_ALIGN != 0 RX DMA buffers start at an offset of EFX_PAGE_IP_ALIGN bytes from the start of a cache line. This offset obviously needs to be included in the virtual address, but this was missed in commit b590ace09d51 ('sfc: Fix efx_rx_buf_offset() in the presence of swiotlb') since EFX_PAGE_IP_ALIGN is equal to 0 on both x86 and powerpc. Signed-off-by: Ben Hutchings diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 879ff58..bb579a6 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -215,7 +215,7 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue) 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; + rx_buf->page_offset = page_offset + EFX_PAGE_IP_ALIGN; rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN; rx_buf->flags = EFX_RX_BUF_PAGE; ++rx_queue->added_count; -- cgit v0.10.2 From f422d2a04fe2e661fd439c19197a162cc9a36416 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 5 Mar 2013 19:10:26 +0000 Subject: net: docs: document multiqueue tuntap API Signed-off-by: Jason Wang Signed-off-by: David S. Miller diff --git a/Documentation/networking/tuntap.txt b/Documentation/networking/tuntap.txt index c0aab98..949d5dc 100644 --- a/Documentation/networking/tuntap.txt +++ b/Documentation/networking/tuntap.txt @@ -105,6 +105,83 @@ Copyright (C) 1999-2000 Maxim Krasnyansky Proto [2 bytes] Raw protocol(IP, IPv6, etc) frame. + 3.3 Multiqueue tuntap interface: + + From version 3.8, Linux supports multiqueue tuntap which can uses multiple + file descriptors (queues) to parallelize packets sending or receiving. The + device allocation is the same as before, and if user wants to create multiple + queues, TUNSETIFF with the same device name must be called many times with + IFF_MULTI_QUEUE flag. + + char *dev should be the name of the device, queues is the number of queues to + be created, fds is used to store and return the file descriptors (queues) + created to the caller. Each file descriptor were served as the interface of a + queue which could be accessed by userspace. + + #include + #include + + int tun_alloc_mq(char *dev, int queues, int *fds) + { + struct ifreq ifr; + int fd, err, i; + + if (!dev) + return -1; + + memset(&ifr, 0, sizeof(ifr)); + /* Flags: IFF_TUN - TUN device (no Ethernet headers) + * IFF_TAP - TAP device + * + * IFF_NO_PI - Do not provide packet information + * IFF_MULTI_QUEUE - Create a queue of multiqueue device + */ + ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_MULTI_QUEUE; + strcpy(ifr.ifr_name, dev); + + for (i = 0; i < queues; i++) { + if ((fd = open("/dev/net/tun", O_RDWR)) < 0) + goto err; + err = ioctl(fd, TUNSETIFF, (void *)&ifr); + if (err) { + close(fd); + goto err; + } + fds[i] = fd; + } + + return 0; + err: + for (--i; i >= 0; i--) + close(fds[i]); + return err; + } + + A new ioctl(TUNSETQUEUE) were introduced to enable or disable a queue. When + calling it with IFF_DETACH_QUEUE flag, the queue were disabled. And when + calling it with IFF_ATTACH_QUEUE flag, the queue were enabled. The queue were + enabled by default after it was created through TUNSETIFF. + + fd is the file descriptor (queue) that we want to enable or disable, when + enable is true we enable it, otherwise we disable it + + #include + #include + + int tun_set_queue(int fd, int enable) + { + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + + if (enable) + ifr.ifr_flags = IFF_ATTACH_QUEUE; + else + ifr.ifr_flags = IFF_DETACH_QUEUE; + + return ioctl(fd, TUNSETQUEUE, (void *)&ifr); + } + Universal TUN/TAP device driver Frequently Asked Question. 1. What platforms are supported by TUN/TAP driver ? -- cgit v0.10.2 From c5b3ad4c67989c778e4753be4f91dc7193a04d21 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Tue, 5 Mar 2013 22:23:20 +0000 Subject: be2net: use CSR-BAR SEMAPHORE reg for BE2/BE3 The SLIPORT_SEMAPHORE register shadowed in the config-space may not reflect the correct POST stage after an EEH reset in BE2/3; it may return FW_READY state even though FW is not ready. This causes the driver to prematurely poll the FW mailbox and fail. For BE2/3 use the CSR-BAR/0xac instead. Reported-by: Gavin Shan Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 28ceb84..29aff55 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -349,6 +349,7 @@ struct be_adapter { struct pci_dev *pdev; struct net_device *netdev; + u8 __iomem *csr; /* CSR BAR used only for BE2/3 */ u8 __iomem *db; /* Door Bell */ struct mutex mbox_lock; /* For serializing mbox cmds to BE card */ diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 813407f..3c9b4f1 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -473,14 +473,17 @@ static int be_mbox_notify_wait(struct be_adapter *adapter) return 0; } -static void be_POST_stage_get(struct be_adapter *adapter, u16 *stage) +static u16 be_POST_stage_get(struct be_adapter *adapter) { u32 sem; - u32 reg = skyhawk_chip(adapter) ? SLIPORT_SEMAPHORE_OFFSET_SH : - SLIPORT_SEMAPHORE_OFFSET_BE; - pci_read_config_dword(adapter->pdev, reg, &sem); - *stage = sem & POST_STAGE_MASK; + if (BEx_chip(adapter)) + sem = ioread32(adapter->csr + SLIPORT_SEMAPHORE_OFFSET_BEx); + else + pci_read_config_dword(adapter->pdev, + SLIPORT_SEMAPHORE_OFFSET_SH, &sem); + + return sem & POST_STAGE_MASK; } int lancer_wait_ready(struct be_adapter *adapter) @@ -574,7 +577,7 @@ int be_fw_wait_ready(struct be_adapter *adapter) } do { - be_POST_stage_get(adapter, &stage); + stage = be_POST_stage_get(adapter); if (stage == POST_STAGE_ARMFW_RDY) return 0; diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index 541d453..62dc220 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -32,8 +32,8 @@ #define MPU_EP_CONTROL 0 /********** MPU semphore: used for SH & BE *************/ -#define SLIPORT_SEMAPHORE_OFFSET_BE 0x7c -#define SLIPORT_SEMAPHORE_OFFSET_SH 0x94 +#define SLIPORT_SEMAPHORE_OFFSET_BEx 0xac /* CSR BAR offset */ +#define SLIPORT_SEMAPHORE_OFFSET_SH 0x94 /* PCI-CFG offset */ #define POST_STAGE_MASK 0x0000FFFF #define POST_ERR_MASK 0x1 #define POST_ERR_SHIFT 31 diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 3860888..08e54f3 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3688,6 +3688,8 @@ static void be_netdev_init(struct net_device *netdev) static void be_unmap_pci_bars(struct be_adapter *adapter) { + if (adapter->csr) + pci_iounmap(adapter->pdev, adapter->csr); if (adapter->db) pci_iounmap(adapter->pdev, adapter->db); } @@ -3721,6 +3723,12 @@ static int be_map_pci_bars(struct be_adapter *adapter) adapter->if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >> SLI_INTF_IF_TYPE_SHIFT; + if (BEx_chip(adapter) && be_physfn(adapter)) { + adapter->csr = pci_iomap(adapter->pdev, 2, 0); + if (adapter->csr == NULL) + return -ENOMEM; + } + addr = pci_iomap(adapter->pdev, db_bar(adapter), 0); if (addr == NULL) goto pci_map_err; @@ -4329,6 +4337,8 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) pci_restore_state(pdev); /* Check if card is ok and fw is ready */ + dev_info(&adapter->pdev->dev, + "Waiting for FW to be ready after EEH reset\n"); status = be_fw_wait_ready(adapter); if (status) return PCI_ERS_RESULT_DISCONNECT; -- cgit v0.10.2 From b141e811a0763bb107af4cd99d456193ccdb8053 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 21 Feb 2013 11:04:45 +0100 Subject: NFC: llcp: Decrease socket ack log when accepting a connection This is really difficult to test with real NFC devices, but without this fix an LLCP server will eventually refuse new connections. Signed-off-by: Samuel Ortiz diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 5332751..5c7cdf3 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -278,6 +278,8 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent, pr_debug("Returning sk state %d\n", sk->sk_state); + sk_acceptq_removed(parent); + return sk; } -- cgit v0.10.2 From 3536da06db0baa675f32de608c0a4c0f5ef0e9ff Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 21 Feb 2013 15:40:04 +0100 Subject: NFC: llcp: Clean local timers and works when removing a device Whenever an adapter is removed we must clean all the local structures, especially the timers and scheduled work. Otherwise those asynchronous threads will eventually try to access the freed nfc_dev pointer if an LLCP link is up. Signed-off-by: Samuel Ortiz diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 7f8266d..77e1d97 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -142,20 +142,25 @@ struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) return local; } -static void local_release(struct kref *ref) +static void local_cleanup(struct nfc_llcp_local *local, bool listen) { - struct nfc_llcp_local *local; - - local = container_of(ref, struct nfc_llcp_local, ref); - - list_del(&local->list); - nfc_llcp_socket_release(local, false); + nfc_llcp_socket_release(local, listen); del_timer_sync(&local->link_timer); skb_queue_purge(&local->tx_queue); cancel_work_sync(&local->tx_work); cancel_work_sync(&local->rx_work); cancel_work_sync(&local->timeout_work); kfree_skb(local->rx_pending); +} + +static void local_release(struct kref *ref) +{ + struct nfc_llcp_local *local; + + local = container_of(ref, struct nfc_llcp_local, ref); + + list_del(&local->list); + local_cleanup(local, false); kfree(local); } @@ -1427,6 +1432,8 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev) return; } + local_cleanup(local, false); + nfc_llcp_local_put(local); } -- cgit v0.10.2 From e6a3a4bb856a6fba551b43376c80f45836132710 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 21 Feb 2013 16:33:30 +0100 Subject: NFC: llcp: Clean raw sockets from nfc_llcp_socket_release Signed-off-by: Samuel Ortiz diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 77e1d97..8a35423 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -133,6 +133,35 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) } write_unlock(&local->sockets.lock); + + /* + * If we want to keep the listening sockets alive, + * we don't touch the RAW ones. + */ + if (listen == true) + return; + + write_lock(&local->raw_sockets.lock); + + sk_for_each_safe(sk, tmp, &local->raw_sockets.head) { + llcp_sock = nfc_llcp_sock(sk); + + bh_lock_sock(sk); + + nfc_llcp_socket_purge(llcp_sock); + + sk->sk_state = LLCP_CLOSED; + + sk->sk_state_change(sk); + + bh_unlock_sock(sk); + + sock_orphan(sk); + + sk_del_node_init(sk); + } + + write_unlock(&local->raw_sockets.lock); } struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) -- cgit v0.10.2 From 3bbc0ceb7ac2bf694d31362eea2c71a680e5deeb Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 21 Feb 2013 17:01:06 +0100 Subject: NFC: llcp: Report error to pending sockets when a device is removed Signed-off-by: Samuel Ortiz diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 8a35423..b530afa 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -68,7 +68,8 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock) } } -static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) +static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, + int err) { struct sock *sk; struct hlist_node *tmp; @@ -100,7 +101,10 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) nfc_llcp_accept_unlink(accept_sk); + if (err) + accept_sk->sk_err = err; accept_sk->sk_state = LLCP_CLOSED; + accept_sk->sk_state_change(sk); bh_unlock_sock(accept_sk); @@ -123,7 +127,10 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) continue; } + if (err) + sk->sk_err = err; sk->sk_state = LLCP_CLOSED; + sk->sk_state_change(sk); bh_unlock_sock(sk); @@ -150,8 +157,9 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) nfc_llcp_socket_purge(llcp_sock); + if (err) + sk->sk_err = err; sk->sk_state = LLCP_CLOSED; - sk->sk_state_change(sk); bh_unlock_sock(sk); @@ -173,7 +181,7 @@ struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) static void local_cleanup(struct nfc_llcp_local *local, bool listen) { - nfc_llcp_socket_release(local, listen); + nfc_llcp_socket_release(local, listen, ENXIO); del_timer_sync(&local->link_timer); skb_queue_purge(&local->tx_queue); cancel_work_sync(&local->tx_work); @@ -1382,7 +1390,7 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) return; /* Close and purge all existing sockets */ - nfc_llcp_socket_release(local, true); + nfc_llcp_socket_release(local, true, 0); } void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, -- cgit v0.10.2 From 5f0fabf84d7b52f979dcbafa3d3c530c60d9a92c Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Thu, 7 Mar 2013 20:00:16 -0800 Subject: mwifiex: fix potential out-of-boundary access to ibss rate table smatch found this error: CHECK drivers/net/wireless/mwifiex/join.c drivers/net/wireless/mwifiex/join.c:1121 mwifiex_cmd_802_11_ad_hoc_join() error: testing array offset 'i' after use. Cc: # 3.0+ Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 246aa62..2fe0ceb 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1117,10 +1117,9 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, adhoc_join->bss_descriptor.bssid, adhoc_join->bss_descriptor.ssid); - for (i = 0; bss_desc->supported_rates[i] && - i < MWIFIEX_SUPPORTED_RATES; - i++) - ; + for (i = 0; i < MWIFIEX_SUPPORTED_RATES && + bss_desc->supported_rates[i]; i++) + ; rates_size = i; /* Copy Data Rates from the Rates recorded in scan response */ -- cgit v0.10.2 From 664899786cb49cb52f620e06ac19c0be524a7cfa Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 27 Feb 2013 14:10:30 -0600 Subject: rtlwifi: rtl8192cu: Fix schedule while atomic bug splat When run at debug 3 or higher, rtl8192cu reports a BUG as follows: BUG: scheduling while atomic: kworker/u:0/5281/0x00000002 INFO: lockdep is turned off. Modules linked in: rtl8192cu rtl8192c_common rtlwifi fuse af_packet bnep bluetooth b43 mac80211 cfg80211 ipv6 snd_hda_codec_conexant kvm_amd k vm snd_hda_intel snd_hda_codec bcma rng_core snd_pcm ssb mmc_core snd_seq snd_timer snd_seq_device snd i2c_nforce2 sr_mod pcmcia forcedeth i2c_core soundcore cdrom sg serio_raw k8temp hwmon joydev ac battery pcmcia_core snd_page_alloc video button wmi autofs4 ext4 mbcache jbd2 crc16 thermal processor scsi_dh_alua scsi_dh_hp_sw scsi_dh_rdac scsi_dh_emc scsi_dh ata_generic pata_acpi pata_amd [last unloaded: rtlwifi] Pid: 5281, comm: kworker/u:0 Tainted: G W 3.8.0-wl+ #119 Call Trace: [] __schedule_bug+0x62/0x70 [] __schedule+0x730/0xa30 [] ? usb_hcd_link_urb_to_ep+0x19/0xa0 [] schedule+0x24/0x70 [] schedule_timeout+0x18c/0x2f0 [] ? wait_for_common+0x40/0x180 [] ? ehci_urb_enqueue+0xf1/0xee0 [] ? trace_hardirqs_on+0xd/0x10 [] wait_for_common+0xe5/0x180 [] ? try_to_wake_up+0x2d0/0x2d0 [] wait_for_completion_timeout+0xe/0x10 [] usb_start_wait_urb+0x8c/0x100 [] usb_control_msg+0xd9/0x130 [] _usb_read_sync+0xcd/0x140 [rtlwifi] [] _usb_read32_sync+0xe/0x10 [rtlwifi] [] rtl92cu_update_hal_rate_table+0x1a5/0x1f0 [rtl8192cu] The cause is a synchronous read from routine rtl92cu_update_hal_rate_table(). The resulting output is not critical, thus the debug statement is deleted. Reported-by: Jussi Kivilinna Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index b1ccff4..3c6e18c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -2058,8 +2058,6 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, (shortgi_rate << 4) | (shortgi_rate); } rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); - RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n", - rtl_read_dword(rtlpriv, REG_ARFR0)); } void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) -- cgit v0.10.2 From 94a32d10f47b637ae24b78b1ddc7ef0e8396fda4 Mon Sep 17 00:00:00 2001 From: Sunguk Lee Date: Tue, 12 Mar 2013 04:41:58 +0900 Subject: Bluetooth: Device 0cf3:3008 should map AR 3012 T: Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=3008 Rev= 0.01 S: Manufacturer=Atheros Communications S: Product=Bluetooth USB Host Controller S: SerialNumber=Alaska Day 2006 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Sunguk Lee Signed-off-by: Gustavo Padovan diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index b9908dd..3095d2e 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -74,6 +74,7 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR3012 with sflash firmware*/ { USB_DEVICE(0x0CF3, 0x3004) }, + { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x04CA, 0x3004) }, @@ -107,6 +108,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { /* Atheros AR3012 with sflash firmware*/ { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 59cde8e..e547851 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -132,6 +132,7 @@ static struct usb_device_id blacklist_table[] = { /* Atheros 3012 with sflash firmware */ { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, -- cgit v0.10.2 From 5818a46a999ad9546e68e8765a3ca1d9d87f9b4a Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 13 Mar 2013 13:20:15 +0100 Subject: rt2x00: fix rt2x00 to work with the new ralink SoC config symbols Since v3.9-rc1 the kernel has basic support for Ralink WiSoC. The config symbols are named slightly different than before. Fix the rt2x00 to match the new symbols. The commit causing this breakage is: commit ae2b5bb6570481b50a7175c64176b82da0a81836 Author: John Crispin Date: Sun Jan 20 22:05:30 2013 +0100 MIPS: ralink: adds Kbuild files Signed-off-by: John Crispin Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 44d6ead..2bf4efa 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -55,10 +55,10 @@ config RT61PCI config RT2800PCI tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support" - depends on PCI || RALINK_RT288X || RALINK_RT305X + depends on PCI || SOC_RT288X || SOC_RT305X select RT2800_LIB select RT2X00_LIB_PCI if PCI - select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X + select RT2X00_LIB_SOC if SOC_RT288X || SOC_RT305X select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO select CRC_CCITT diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 48a01aa..ded73da 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -89,7 +89,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); } -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X) static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE); @@ -107,7 +107,7 @@ static inline int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { return -ENOMEM; } -#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ +#endif /* CONFIG_SOC_RT288X || CONFIG_SOC_RT305X */ #ifdef CONFIG_PCI static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) @@ -1177,7 +1177,7 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table); #endif /* CONFIG_PCI */ MODULE_LICENSE("GPL"); -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X) static int rt2800soc_probe(struct platform_device *pdev) { return rt2x00soc_probe(pdev, &rt2800pci_ops); @@ -1194,7 +1194,7 @@ static struct platform_driver rt2800soc_driver = { .suspend = rt2x00soc_suspend, .resume = rt2x00soc_resume, }; -#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ +#endif /* CONFIG_SOC_RT288X || CONFIG_SOC_RT305X */ #ifdef CONFIG_PCI static int rt2800pci_probe(struct pci_dev *pci_dev, @@ -1217,7 +1217,7 @@ static int __init rt2800pci_init(void) { int ret = 0; -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X) ret = platform_driver_register(&rt2800soc_driver); if (ret) return ret; @@ -1225,7 +1225,7 @@ static int __init rt2800pci_init(void) #ifdef CONFIG_PCI ret = pci_register_driver(&rt2800pci_driver); if (ret) { -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X) platform_driver_unregister(&rt2800soc_driver); #endif return ret; @@ -1240,7 +1240,7 @@ static void __exit rt2800pci_exit(void) #ifdef CONFIG_PCI pci_unregister_driver(&rt2800pci_driver); #endif -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X) platform_driver_unregister(&rt2800soc_driver); #endif } -- cgit v0.10.2 From 9437a248e7cac427c898bdb11bd1ac6844a1ead4 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 13 Mar 2013 10:28:13 -0500 Subject: rtlwifi: rtl8192cu: Fix problem that prevents reassociation The driver was failing to clear the BSSID when a disconnect happened. That prevented a reconnection. This problem is reported at https://bugzilla.redhat.com/show_bug.cgi?id=789605, https://bugzilla.redhat.com/show_bug.cgi?id=866786, https://bugzilla.redhat.com/show_bug.cgi?id=906734, and https://bugzilla.kernel.org/show_bug.cgi?id=46171. Thanks to Jussi Kivilinna for making the critical observation that led to the solution. Reported-by: Jussi Kivilinna Tested-by: Jussi Kivilinna Tested-by: Alessandro Lannocca Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 3c6e18c..c08d0f4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1377,74 +1377,57 @@ void rtl92cu_card_disable(struct ieee80211_hw *hw) void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { - /* dummy routine needed for callback from rtl_op_configure_filter() */ -} - -/*========================================================================== */ - -static void _rtl92cu_set_check_bssid(struct ieee80211_hw *hw, - enum nl80211_iftype type) -{ struct rtl_priv *rtlpriv = rtl_priv(hw); - u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - u8 filterout_non_associated_bssid = false; + u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); - switch (type) { - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_STATION: - filterout_non_associated_bssid = true; - break; - case NL80211_IFTYPE_UNSPECIFIED: - case NL80211_IFTYPE_AP: - default: - break; - } - if (filterout_non_associated_bssid) { + if (rtlpriv->psc.rfpwr_state != ERFON) + return; + + if (check_bssid) { + u8 tmp; if (IS_NORMAL_CHIP(rtlhal->version)) { - switch (rtlphy->current_io_type) { - case IO_CMD_RESUME_DM_BY_SCAN: - reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); - rtlpriv->cfg->ops->set_hw_reg(hw, - HW_VAR_RCR, (u8 *)(®_rcr)); - /* enable update TSF */ - _rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(4)); - break; - case IO_CMD_PAUSE_DM_BY_SCAN: - reg_rcr &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); - rtlpriv->cfg->ops->set_hw_reg(hw, - HW_VAR_RCR, (u8 *)(®_rcr)); - /* disable update TSF */ - _rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); - break; - } + reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); + tmp = BIT(4); } else { - reg_rcr |= (RCR_CBSSID); - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, - (u8 *)(®_rcr)); - _rtl92cu_set_bcn_ctrl_reg(hw, 0, (BIT(4)|BIT(5))); + reg_rcr |= RCR_CBSSID; + tmp = BIT(4) | BIT(5); } - } else if (filterout_non_associated_bssid == false) { + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, + (u8 *) (®_rcr)); + _rtl92cu_set_bcn_ctrl_reg(hw, 0, tmp); + } else { + u8 tmp; if (IS_NORMAL_CHIP(rtlhal->version)) { - reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, - (u8 *)(®_rcr)); - _rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); + reg_rcr &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); + tmp = BIT(4); } else { - reg_rcr &= (~RCR_CBSSID); - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, - (u8 *)(®_rcr)); - _rtl92cu_set_bcn_ctrl_reg(hw, (BIT(4)|BIT(5)), 0); + reg_rcr &= ~RCR_CBSSID; + tmp = BIT(4) | BIT(5); } + reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_RCR, (u8 *) (®_rcr)); + _rtl92cu_set_bcn_ctrl_reg(hw, tmp, 0); } } +/*========================================================================== */ + int rtl92cu_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (_rtl92cu_set_media_status(hw, type)) return -EOPNOTSUPP; - _rtl92cu_set_check_bssid(hw, type); + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl92cu_set_check_bssid(hw, true); + } else { + rtl92cu_set_check_bssid(hw, false); + } + return 0; } -- cgit v0.10.2