]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 7 May 2020 11:26:09 +0000 (13:26 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 7 May 2020 11:26:09 +0000 (13:26 +0200)
added patches:
net-don-t-delete-routes-in-different-vrfs.patch
net-vrf-fix-dst-reference-counting.patch
power-bq27xxx-fix-reading-for-bq27000-and-bq27010.patch
power-bq27xxx-fix-register-numbers-of-bq27500.patch
power-bq27xxx_battery-fix-bq27541-averagepower-register-address.patch
power-test_power-correctly-handle-empty-writes.patch
power_supply-tps65217-charger-fix-null-deref-during-property-export.patch

queue-4.4/net-don-t-delete-routes-in-different-vrfs.patch [new file with mode: 0644]
queue-4.4/net-vrf-fix-dst-reference-counting.patch [new file with mode: 0644]
queue-4.4/power-bq27xxx-fix-reading-for-bq27000-and-bq27010.patch [new file with mode: 0644]
queue-4.4/power-bq27xxx-fix-register-numbers-of-bq27500.patch [new file with mode: 0644]
queue-4.4/power-bq27xxx_battery-fix-bq27541-averagepower-register-address.patch [new file with mode: 0644]
queue-4.4/power-test_power-correctly-handle-empty-writes.patch [new file with mode: 0644]
queue-4.4/power_supply-tps65217-charger-fix-null-deref-during-property-export.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/net-don-t-delete-routes-in-different-vrfs.patch b/queue-4.4/net-don-t-delete-routes-in-different-vrfs.patch
new file mode 100644 (file)
index 0000000..7eb6ab8
--- /dev/null
@@ -0,0 +1,106 @@
+From 5a56a0b3a45dd0cc5b2f7bec6afd053a474ed9f5 Mon Sep 17 00:00:00 2001
+From: Mark Tomlinson <mark.tomlinson@alliedtelesis.co.nz>
+Date: Mon, 5 Sep 2016 10:20:20 +1200
+Subject: net: Don't delete routes in different VRFs
+
+From: Mark Tomlinson <mark.tomlinson@alliedtelesis.co.nz>
+
+commit 5a56a0b3a45dd0cc5b2f7bec6afd053a474ed9f5 upstream.
+
+When deleting an IP address from an interface, there is a clean-up of
+routes which refer to this local address. However, there was no check to
+see that the VRF matched. This meant that deletion wasn't confined to
+the VRF it should have been.
+
+To solve this, a new field has been added to fib_info to hold a table
+id. When removing fib entries corresponding to a local ip address, this
+table id is also used in the comparison.
+
+The table id is populated when the fib_info is created. This was already
+done in some places, but not in ip_rt_ioctl(). This has now been fixed.
+
+Fixes: 021dd3b8a142 ("net: Add routes to the table associated with the device")
+Acked-by: David Ahern <dsa@cumulusnetworks.com>
+Tested-by: David Ahern <dsa@cumulusnetworks.com>
+Signed-off-by: Mark Tomlinson <mark.tomlinson@alliedtelesis.co.nz>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/net/ip_fib.h     |    3 ++-
+ net/ipv4/fib_frontend.c  |    3 ++-
+ net/ipv4/fib_semantics.c |    8 ++++++--
+ 3 files changed, 10 insertions(+), 4 deletions(-)
+
+--- a/include/net/ip_fib.h
++++ b/include/net/ip_fib.h
+@@ -112,6 +112,7 @@ struct fib_info {
+       unsigned char           fib_scope;
+       unsigned char           fib_type;
+       __be32                  fib_prefsrc;
++      u32                     fib_tb_id;
+       u32                     fib_priority;
+       struct dst_metrics      *fib_metrics;
+ #define fib_mtu fib_metrics->metrics[RTAX_MTU-1]
+@@ -320,7 +321,7 @@ void fib_flush_external(struct net *net)
+ /* Exported by fib_semantics.c */
+ int ip_fib_check_default(__be32 gw, struct net_device *dev);
+ int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force);
+-int fib_sync_down_addr(struct net *net, __be32 local);
++int fib_sync_down_addr(struct net_device *dev, __be32 local);
+ int fib_sync_up(struct net_device *dev, unsigned int nh_flags);
+ void fib_sync_mtu(struct net_device *dev, u32 orig_mtu);
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -509,6 +509,7 @@ static int rtentry_to_fib_config(struct
+               if (!dev)
+                       return -ENODEV;
+               cfg->fc_oif = dev->ifindex;
++              cfg->fc_table = l3mdev_fib_table(dev);
+               if (colon) {
+                       struct in_ifaddr *ifa;
+                       struct in_device *in_dev = __in_dev_get_rtnl(dev);
+@@ -1034,7 +1035,7 @@ no_promotions:
+                        * First of all, we scan fib_info list searching
+                        * for stray nexthop entries, then ignite fib_flush.
+                        */
+-                      if (fib_sync_down_addr(dev_net(dev), ifa->ifa_local))
++                      if (fib_sync_down_addr(dev, ifa->ifa_local))
+                               fib_flush(dev_net(dev));
+               }
+       }
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -1069,6 +1069,7 @@ struct fib_info *fib_create_info(struct
+       fi->fib_priority = cfg->fc_priority;
+       fi->fib_prefsrc = cfg->fc_prefsrc;
+       fi->fib_type = cfg->fc_type;
++      fi->fib_tb_id = cfg->fc_table;
+       fi->fib_nhs = nhs;
+       change_nexthops(fi) {
+@@ -1352,18 +1353,21 @@ nla_put_failure:
+  *   referring to it.
+  * - device went down -> we must shutdown all nexthops going via it.
+  */
+-int fib_sync_down_addr(struct net *net, __be32 local)
++int fib_sync_down_addr(struct net_device *dev, __be32 local)
+ {
+       int ret = 0;
+       unsigned int hash = fib_laddr_hashfn(local);
+       struct hlist_head *head = &fib_info_laddrhash[hash];
++      struct net *net = dev_net(dev);
++      int tb_id = l3mdev_fib_table(dev);
+       struct fib_info *fi;
+       if (!fib_info_laddrhash || local == 0)
+               return 0;
+       hlist_for_each_entry(fi, head, fib_lhash) {
+-              if (!net_eq(fi->fib_net, net))
++              if (!net_eq(fi->fib_net, net) ||
++                  fi->fib_tb_id != tb_id)
+                       continue;
+               if (fi->fib_prefsrc == local) {
+                       fi->fib_flags |= RTNH_F_DEAD;
diff --git a/queue-4.4/net-vrf-fix-dst-reference-counting.patch b/queue-4.4/net-vrf-fix-dst-reference-counting.patch
new file mode 100644 (file)
index 0000000..6aefc2f
--- /dev/null
@@ -0,0 +1,392 @@
+From 9ab179d83b4e31ea277a123492e419067c2f129a Mon Sep 17 00:00:00 2001
+From: David Ahern <dsa@cumulusnetworks.com>
+Date: Thu, 7 Apr 2016 11:10:06 -0700
+Subject: net: vrf: Fix dst reference counting
+
+From: David Ahern <dsa@cumulusnetworks.com>
+
+commit 9ab179d83b4e31ea277a123492e419067c2f129a upstream.
+
+Vivek reported a kernel exception deleting a VRF with an active
+connection through it. The root cause is that the socket has a cached
+reference to a dst that is destroyed. Converting the dst_destroy to
+dst_release and letting proper reference counting kick in does not
+work as the dst has a reference to the device which needs to be released
+as well.
+
+I talked to Hannes about this at netdev and he pointed out the ipv4 and
+ipv6 dst handling has dst_ifdown for just this scenario. Rather than
+continuing with the reinvented dst wheel in VRF just remove it and
+leverage the ipv4 and ipv6 versions.
+
+Fixes: 193125dbd8eb2 ("net: Introduce VRF device driver")
+Fixes: 35402e3136634 ("net: Add IPv6 support to VRF device")
+
+Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/vrf.c       |  177 ++++--------------------------------------------
+ include/net/ip6_route.h |    3 
+ include/net/route.h     |    3 
+ net/ipv4/route.c        |    7 +
+ net/ipv6/route.c        |    7 +
+ 5 files changed, 30 insertions(+), 167 deletions(-)
+
+--- a/drivers/net/vrf.c
++++ b/drivers/net/vrf.c
+@@ -71,41 +71,6 @@ struct pcpu_dstats {
+       struct u64_stats_sync   syncp;
+ };
+-static struct dst_entry *vrf_ip_check(struct dst_entry *dst, u32 cookie)
+-{
+-      return dst;
+-}
+-
+-static int vrf_ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
+-{
+-      return ip_local_out(net, sk, skb);
+-}
+-
+-static unsigned int vrf_v4_mtu(const struct dst_entry *dst)
+-{
+-      /* TO-DO: return max ethernet size? */
+-      return dst->dev->mtu;
+-}
+-
+-static void vrf_dst_destroy(struct dst_entry *dst)
+-{
+-      /* our dst lives forever - or until the device is closed */
+-}
+-
+-static unsigned int vrf_default_advmss(const struct dst_entry *dst)
+-{
+-      return 65535 - 40;
+-}
+-
+-static struct dst_ops vrf_dst_ops = {
+-      .family         = AF_INET,
+-      .local_out      = vrf_ip_local_out,
+-      .check          = vrf_ip_check,
+-      .mtu            = vrf_v4_mtu,
+-      .destroy        = vrf_dst_destroy,
+-      .default_advmss = vrf_default_advmss,
+-};
+-
+ /* neighbor handling is done with actual device; do not want
+  * to flip skb->dev for those ndisc packets. This really fails
+  * for multiple next protocols (e.g., NEXTHDR_HOP). But it is
+@@ -363,46 +328,6 @@ static netdev_tx_t vrf_xmit(struct sk_bu
+ }
+ #if IS_ENABLED(CONFIG_IPV6)
+-static struct dst_entry *vrf_ip6_check(struct dst_entry *dst, u32 cookie)
+-{
+-      return dst;
+-}
+-
+-static struct dst_ops vrf_dst_ops6 = {
+-      .family         = AF_INET6,
+-      .local_out      = ip6_local_out,
+-      .check          = vrf_ip6_check,
+-      .mtu            = vrf_v4_mtu,
+-      .destroy        = vrf_dst_destroy,
+-      .default_advmss = vrf_default_advmss,
+-};
+-
+-static int init_dst_ops6_kmem_cachep(void)
+-{
+-      vrf_dst_ops6.kmem_cachep = kmem_cache_create("vrf_ip6_dst_cache",
+-                                                   sizeof(struct rt6_info),
+-                                                   0,
+-                                                   SLAB_HWCACHE_ALIGN,
+-                                                   NULL);
+-
+-      if (!vrf_dst_ops6.kmem_cachep)
+-              return -ENOMEM;
+-
+-      return 0;
+-}
+-
+-static void free_dst_ops6_kmem_cachep(void)
+-{
+-      kmem_cache_destroy(vrf_dst_ops6.kmem_cachep);
+-}
+-
+-static int vrf_input6(struct sk_buff *skb)
+-{
+-      skb->dev->stats.rx_errors++;
+-      kfree_skb(skb);
+-      return 0;
+-}
+-
+ /* modelled after ip6_finish_output2 */
+ static int vrf_finish_output6(struct net *net, struct sock *sk,
+                             struct sk_buff *skb)
+@@ -445,67 +370,34 @@ static int vrf_output6(struct net *net,
+                           !(IP6CB(skb)->flags & IP6SKB_REROUTED));
+ }
+-static void vrf_rt6_destroy(struct net_vrf *vrf)
++static void vrf_rt6_release(struct net_vrf *vrf)
+ {
+-      dst_destroy(&vrf->rt6->dst);
+-      free_percpu(vrf->rt6->rt6i_pcpu);
++      dst_release(&vrf->rt6->dst);
+       vrf->rt6 = NULL;
+ }
+ static int vrf_rt6_create(struct net_device *dev)
+ {
+       struct net_vrf *vrf = netdev_priv(dev);
+-      struct dst_entry *dst;
++      struct net *net = dev_net(dev);
+       struct rt6_info *rt6;
+-      int cpu;
+       int rc = -ENOMEM;
+-      rt6 = dst_alloc(&vrf_dst_ops6, dev, 0,
+-                      DST_OBSOLETE_NONE,
+-                      (DST_HOST | DST_NOPOLICY | DST_NOXFRM));
++      rt6 = ip6_dst_alloc(net, dev,
++                          DST_HOST | DST_NOPOLICY | DST_NOXFRM | DST_NOCACHE);
+       if (!rt6)
+               goto out;
+-      dst = &rt6->dst;
+-
+-      rt6->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_KERNEL);
+-      if (!rt6->rt6i_pcpu) {
+-              dst_destroy(dst);
+-              goto out;
+-      }
+-      for_each_possible_cpu(cpu) {
+-              struct rt6_info **p = per_cpu_ptr(rt6->rt6i_pcpu, cpu);
+-              *p =  NULL;
+-      }
+-
+-      memset(dst + 1, 0, sizeof(*rt6) - sizeof(*dst));
+-
+-      INIT_LIST_HEAD(&rt6->rt6i_siblings);
+-      INIT_LIST_HEAD(&rt6->rt6i_uncached);
+-
+-      rt6->dst.input  = vrf_input6;
+       rt6->dst.output = vrf_output6;
+-
+-      rt6->rt6i_table = fib6_get_table(dev_net(dev), vrf->tb_id);
+-
+-      atomic_set(&rt6->dst.__refcnt, 2);
+-
++      rt6->rt6i_table = fib6_get_table(net, vrf->tb_id);
++      dst_hold(&rt6->dst);
+       vrf->rt6 = rt6;
+       rc = 0;
+ out:
+       return rc;
+ }
+ #else
+-static int init_dst_ops6_kmem_cachep(void)
+-{
+-      return 0;
+-}
+-
+-static void free_dst_ops6_kmem_cachep(void)
+-{
+-}
+-
+-static void vrf_rt6_destroy(struct net_vrf *vrf)
++static void vrf_rt6_release(struct net_vrf *vrf)
+ {
+ }
+@@ -577,11 +469,11 @@ static int vrf_output(struct net *net, s
+                           !(IPCB(skb)->flags & IPSKB_REROUTED));
+ }
+-static void vrf_rtable_destroy(struct net_vrf *vrf)
++static void vrf_rtable_release(struct net_vrf *vrf)
+ {
+       struct dst_entry *dst = (struct dst_entry *)vrf->rth;
+-      dst_destroy(dst);
++      dst_release(dst);
+       vrf->rth = NULL;
+ }
+@@ -590,22 +482,10 @@ static struct rtable *vrf_rtable_create(
+       struct net_vrf *vrf = netdev_priv(dev);
+       struct rtable *rth;
+-      rth = dst_alloc(&vrf_dst_ops, dev, 2,
+-                      DST_OBSOLETE_NONE,
+-                      (DST_HOST | DST_NOPOLICY | DST_NOXFRM));
++      rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1, 1, 0);
+       if (rth) {
+               rth->dst.output = vrf_output;
+-              rth->rt_genid   = rt_genid_ipv4(dev_net(dev));
+-              rth->rt_flags   = 0;
+-              rth->rt_type    = RTN_UNICAST;
+-              rth->rt_is_input = 0;
+-              rth->rt_iif     = 0;
+-              rth->rt_pmtu    = 0;
+-              rth->rt_gateway = 0;
+-              rth->rt_uses_gateway = 0;
+               rth->rt_table_id = vrf->tb_id;
+-              INIT_LIST_HEAD(&rth->rt_uncached);
+-              rth->rt_uncached_list = NULL;
+       }
+       return rth;
+@@ -739,8 +619,8 @@ static void vrf_dev_uninit(struct net_de
+ //    struct list_head *head = &queue->all_slaves;
+ //    struct slave *slave, *next;
+-      vrf_rtable_destroy(vrf);
+-      vrf_rt6_destroy(vrf);
++      vrf_rtable_release(vrf);
++      vrf_rt6_release(vrf);
+ //    list_for_each_entry_safe(slave, next, head, list)
+ //            vrf_del_slave(dev, slave->dev);
+@@ -772,7 +652,7 @@ static int vrf_dev_init(struct net_devic
+       return 0;
+ out_rth:
+-      vrf_rtable_destroy(vrf);
++      vrf_rtable_release(vrf);
+ out_stats:
+       free_percpu(dev->dstats);
+       dev->dstats = NULL;
+@@ -805,7 +685,7 @@ static struct rtable *vrf_get_rtable(con
+               struct net_vrf *vrf = netdev_priv(dev);
+               rth = vrf->rth;
+-              atomic_inc(&rth->dst.__refcnt);
++              dst_hold(&rth->dst);
+       }
+       return rth;
+@@ -856,7 +736,7 @@ static struct dst_entry *vrf_get_rt6_dst
+               struct net_vrf *vrf = netdev_priv(dev);
+               rt = vrf->rt6;
+-              atomic_inc(&rt->dst.__refcnt);
++              dst_hold(&rt->dst);
+       }
+       return (struct dst_entry *)rt;
+@@ -1003,19 +883,6 @@ static int __init vrf_init_module(void)
+ {
+       int rc;
+-      vrf_dst_ops.kmem_cachep =
+-              kmem_cache_create("vrf_ip_dst_cache",
+-                                sizeof(struct rtable), 0,
+-                                SLAB_HWCACHE_ALIGN,
+-                                NULL);
+-
+-      if (!vrf_dst_ops.kmem_cachep)
+-              return -ENOMEM;
+-
+-      rc = init_dst_ops6_kmem_cachep();
+-      if (rc != 0)
+-              goto error2;
+-
+       register_netdevice_notifier(&vrf_notifier_block);
+       rc = rtnl_link_register(&vrf_link_ops);
+@@ -1026,22 +893,10 @@ static int __init vrf_init_module(void)
+ error:
+       unregister_netdevice_notifier(&vrf_notifier_block);
+-      free_dst_ops6_kmem_cachep();
+-error2:
+-      kmem_cache_destroy(vrf_dst_ops.kmem_cachep);
+       return rc;
+ }
+-static void __exit vrf_cleanup_module(void)
+-{
+-      rtnl_link_unregister(&vrf_link_ops);
+-      unregister_netdevice_notifier(&vrf_notifier_block);
+-      kmem_cache_destroy(vrf_dst_ops.kmem_cachep);
+-      free_dst_ops6_kmem_cachep();
+-}
+-
+ module_init(vrf_init_module);
+-module_exit(vrf_cleanup_module);
+ MODULE_AUTHOR("Shrijeet Mukherjee, David Ahern");
+ MODULE_DESCRIPTION("Device driver to instantiate VRF domains");
+ MODULE_LICENSE("GPL");
+--- a/include/net/ip6_route.h
++++ b/include/net/ip6_route.h
+@@ -103,6 +103,9 @@ void fib6_force_start_gc(struct net *net
+ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
+                                   const struct in6_addr *addr, bool anycast);
++struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,
++                             int flags);
++
+ /*
+  *    support functions for ND
+  *
+--- a/include/net/route.h
++++ b/include/net/route.h
+@@ -210,6 +210,9 @@ unsigned int inet_addr_type_dev_table(st
+ void ip_rt_multicast_event(struct in_device *);
+ int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg);
+ void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
++struct rtable *rt_dst_alloc(struct net_device *dev,
++                           unsigned int flags, u16 type,
++                           bool nopolicy, bool noxfrm, bool will_cache);
+ struct in_ifaddr;
+ void fib_add_ifaddr(struct in_ifaddr *);
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -1500,9 +1500,9 @@ static void rt_set_nexthop(struct rtable
+ #endif
+ }
+-static struct rtable *rt_dst_alloc(struct net_device *dev,
+-                                 unsigned int flags, u16 type,
+-                                 bool nopolicy, bool noxfrm, bool will_cache)
++struct rtable *rt_dst_alloc(struct net_device *dev,
++                          unsigned int flags, u16 type,
++                          bool nopolicy, bool noxfrm, bool will_cache)
+ {
+       struct rtable *rt;
+@@ -1531,6 +1531,7 @@ static struct rtable *rt_dst_alloc(struc
+       return rt;
+ }
++EXPORT_SYMBOL(rt_dst_alloc);
+ /* called in rcu_read_lock() section */
+ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -339,9 +339,9 @@ static struct rt6_info *__ip6_dst_alloc(
+       return rt;
+ }
+-static struct rt6_info *ip6_dst_alloc(struct net *net,
+-                                    struct net_device *dev,
+-                                    int flags)
++struct rt6_info *ip6_dst_alloc(struct net *net,
++                             struct net_device *dev,
++                             int flags)
+ {
+       struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
+@@ -365,6 +365,7 @@ static struct rt6_info *ip6_dst_alloc(st
+       return rt;
+ }
++EXPORT_SYMBOL(ip6_dst_alloc);
+ static void ip6_dst_destroy(struct dst_entry *dst)
+ {
diff --git a/queue-4.4/power-bq27xxx-fix-reading-for-bq27000-and-bq27010.patch b/queue-4.4/power-bq27xxx-fix-reading-for-bq27000-and-bq27010.patch
new file mode 100644 (file)
index 0000000..da06fcf
--- /dev/null
@@ -0,0 +1,85 @@
+From 549d7b317c761dbf4ed0c2945aec3acc9ca7ae14 Mon Sep 17 00:00:00 2001
+From: "H. Nikolaus Schaller" <hns@goldelico.com>
+Date: Thu, 17 Dec 2015 11:12:53 +0100
+Subject: power: bq27xxx: fix reading for bq27000 and bq27010
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: H. Nikolaus Schaller <hns@goldelico.com>
+
+commit 549d7b317c761dbf4ed0c2945aec3acc9ca7ae14 upstream.
+
+bug: the driver reports funny capacity values:
+
+root@letux:/sys/class/power_supply/bq27000-battery# cat uevent
+POWER_SUPPLY_NAME=bq27000-battery
+POWER_SUPPLY_STATUS=Charging
+POWER_SUPPLY_PRESENT=1
+POWER_SUPPLY_VOLTAGE_NOW=3702000
+POWER_SUPPLY_CURRENT_NOW=-464635
+POWER_SUPPLY_CAPACITY=1536                     <- over 100% is magic
+POWER_SUPPLY_CAPACITY_LEVEL=Normal
+POWER_SUPPLY_TEMP=311
+POWER_SUPPLY_TIME_TO_FULL_NOW=10440
+POWER_SUPPLY_TECHNOLOGY=Li-ion
+POWER_SUPPLY_CHARGE_FULL=805450
+POWER_SUPPLY_CHARGE_NOW=1068
+POWER_SUPPLY_CHARGE_FULL_DESIGN=8844998        <- battery has just 1200 mAh
+POWER_SUPPLY_CYCLE_COUNT=21
+POWER_SUPPLY_ENERGY_NOW=0
+POWER_SUPPLY_POWER_AVG=0
+POWER_SUPPLY_HEALTH=Good
+POWER_SUPPLY_MANUFACTURER=Texas Instruments
+
+reason: the state of charge and the design capacity register are single
+byte only. The design capacity returns the higer order byte.
+
+tested: GTA04 with Openmoko/FIC HF08x battery (using hdq)
+
+Fixes: d74534c27775 ("power: bq27xxx_battery: Add support for additional bq27xxx family devices")
+Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
+Acked-by: Andrew F. Davis <afd@ti.com>
+Reviewed-by: Pali Rohár <pali.rohar@gmail.com>
+Signed-off-by: Sebastian Reichel <sre@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/power/bq27xxx_battery.c |   12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- a/drivers/power/bq27xxx_battery.c
++++ b/drivers/power/bq27xxx_battery.c
+@@ -471,7 +471,10 @@ static int bq27xxx_battery_read_soc(stru
+ {
+       int soc;
+-      soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false);
++      if (di->chip == BQ27000 || di->chip == BQ27010)
++              soc = bq27xxx_read(di, BQ27XXX_REG_SOC, true);
++      else
++              soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false);
+       if (soc < 0)
+               dev_dbg(di->dev, "error reading State-of-Charge\n");
+@@ -536,7 +539,10 @@ static int bq27xxx_battery_read_dcap(str
+ {
+       int dcap;
+-      dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false);
++      if (di->chip == BQ27000 || di->chip == BQ27010)
++              dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true);
++      else
++              dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false);
+       if (dcap < 0) {
+               dev_dbg(di->dev, "error reading initial last measured discharge\n");
+@@ -544,7 +550,7 @@ static int bq27xxx_battery_read_dcap(str
+       }
+       if (di->chip == BQ27000 || di->chip == BQ27010)
+-              dcap *= BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS;
++              dcap = (dcap << 8) * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS;
+       else
+               dcap *= 1000;
diff --git a/queue-4.4/power-bq27xxx-fix-register-numbers-of-bq27500.patch b/queue-4.4/power-bq27xxx-fix-register-numbers-of-bq27500.patch
new file mode 100644 (file)
index 0000000..a0ae0df
--- /dev/null
@@ -0,0 +1,39 @@
+From 099867a16a0fa9fd5aafc32e3b1a6f8a90f17834 Mon Sep 17 00:00:00 2001
+From: "H. Nikolaus Schaller" <hns@goldelico.com>
+Date: Thu, 17 Dec 2015 11:12:54 +0100
+Subject: power: bq27xxx: fix register numbers of bq27500
+
+From: H. Nikolaus Schaller <hns@goldelico.com>
+
+commit 099867a16a0fa9fd5aafc32e3b1a6f8a90f17834 upstream.
+
+bug: according to data sheet some register numbers are wrong.
+
+tested: no
+
+Fixes: d74534c27775 ("power: bq27xxx_battery: Add support for additional bq27xxx family devices")
+Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
+Acked-by: Andrew F. Davis <afd@ti.com>
+Signed-off-by: Sebastian Reichel <sre@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/power/bq27xxx_battery.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/power/bq27xxx_battery.c
++++ b/drivers/power/bq27xxx_battery.c
+@@ -198,10 +198,10 @@ static u8 bq27500_regs[] = {
+       INVALID_REG_ADDR,       /* TTECP - NA   */
+       0x0c,   /* NAC          */
+       0x12,   /* LMD(FCC)     */
+-      0x1e,   /* CYCT         */
++      0x2a,   /* CYCT         */
+       INVALID_REG_ADDR,       /* AE - NA      */
+-      0x20,   /* SOC(RSOC)    */
+-      0x2e,   /* DCAP(ILMD)   */
++      0x2c,   /* SOC(RSOC)    */
++      0x3c,   /* DCAP(ILMD)   */
+       INVALID_REG_ADDR,       /* AP - NA      */
+ };
diff --git a/queue-4.4/power-bq27xxx_battery-fix-bq27541-averagepower-register-address.patch b/queue-4.4/power-bq27xxx_battery-fix-bq27541-averagepower-register-address.patch
new file mode 100644 (file)
index 0000000..31a4fe0
--- /dev/null
@@ -0,0 +1,36 @@
+From 265b60497a57da56a4be7d5c72983ae89dc0765e Mon Sep 17 00:00:00 2001
+From: Liu Xiang <liu.xiang6@zte.com.cn>
+Date: Sat, 9 Jan 2016 22:10:39 +0800
+Subject: power: bq27xxx_battery: Fix bq27541 AveragePower register address
+
+From: Liu Xiang <liu.xiang6@zte.com.cn>
+
+commit 265b60497a57da56a4be7d5c72983ae89dc0765e upstream.
+
+Currently in bq27541 driver, the average power register address is
+incorrectly set to 0x76, which would result in an error:
+bq27xxx-battery 2-0055: error reading average power register  10: -11
+According to the bq27541 datasheet, fix this problem by setting
+the average power register address to 0x24.
+
+Fixes: d74534c27775 ("power: bq27xxx_battery: Add support for additional bq27xxx family devices")
+Signed-off-by: Liu Xiang <liu.xiang6@zte.com.cn>
+Acked-by: Andrew F. Davis <afd@ti.com>
+Signed-off-by: Sebastian Reichel <sre@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/power/bq27xxx_battery.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/power/bq27xxx_battery.c
++++ b/drivers/power/bq27xxx_battery.c
+@@ -242,7 +242,7 @@ static u8 bq27541_regs[] = {
+       INVALID_REG_ADDR,       /* AE - NA      */
+       0x2c,   /* SOC(RSOC)    */
+       0x3c,   /* DCAP         */
+-      0x76,   /* AP           */
++      0x24,   /* AP           */
+ };
+ static u8 bq27545_regs[] = {
diff --git a/queue-4.4/power-test_power-correctly-handle-empty-writes.patch b/queue-4.4/power-test_power-correctly-handle-empty-writes.patch
new file mode 100644 (file)
index 0000000..fc4ee83
--- /dev/null
@@ -0,0 +1,32 @@
+From 6b9140f39c2aaf76791197fbab0839c0e4af56e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sasha.levin@oracle.com>
+Date: Tue, 22 Dec 2015 12:43:36 -0500
+Subject: power: test_power: correctly handle empty writes
+
+From: Sasha Levin <sasha.levin@oracle.com>
+
+commit 6b9140f39c2aaf76791197fbab0839c0e4af56e8 upstream.
+
+Writing 0 length data into test_power makes it access an invalid array
+location and kill the system.
+
+Fixes: f17ef9b2d ("power: Make test_power driver more dynamic.")
+Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
+Signed-off-by: Sebastian Reichel <sre@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/power/test_power.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/power/test_power.c
++++ b/drivers/power/test_power.c
+@@ -301,6 +301,8 @@ static int map_get_value(struct battery_
+       buf[MAX_KEYLENGTH-1] = '\0';
+       cr = strnlen(buf, MAX_KEYLENGTH) - 1;
++      if (cr < 0)
++              return def_val;
+       if (buf[cr] == '\n')
+               buf[cr] = '\0';
diff --git a/queue-4.4/power_supply-tps65217-charger-fix-null-deref-during-property-export.patch b/queue-4.4/power_supply-tps65217-charger-fix-null-deref-during-property-export.patch
new file mode 100644 (file)
index 0000000..a042ddb
--- /dev/null
@@ -0,0 +1,61 @@
+From 362761299eea7dfc3a4870551de36e08758b9254 Mon Sep 17 00:00:00 2001
+From: Marcin Niestroj <m.niestroj@grinn-global.com>
+Date: Tue, 14 Jun 2016 15:29:24 +0200
+Subject: power_supply: tps65217-charger: Fix NULL deref during property export
+
+From: Marcin Niestroj <m.niestroj@grinn-global.com>
+
+commit 362761299eea7dfc3a4870551de36e08758b9254 upstream.
+
+This bug leads to:
+
+[    1.906411] Unable to handle kernel NULL pointer dereference at virtual address 0000000c
+[    1.914878] pgd = c0004000
+[    1.917786] [0000000c] *pgd=00000000
+[    1.921536] Internal error: Oops: 5 [#1] SMP ARM
+[    1.926357] Modules linked in:
+[    1.929556] CPU: 0 PID: 14 Comm: kworker/0:1 Not tainted 4.4.5 #18
+[    1.936006] Hardware name: Generic AM33XX (Flattened Device Tree)
+[    1.942383] Workqueue: events power_supply_changed_work
+[    1.947842] task: de2c41c0 ti: de2c8000 task.ti: de2c8000
+[    1.953483] PC is at tps65217_ac_get_property+0x14/0x28
+[    1.958937] LR is at tps65217_ac_get_property+0x10/0x28
+
+Driver was trying to use drv_data in property get handler. However drv_data
+was not set, so it caused NULL pointer dereference. This patch properly
+sets drv_data during probe by power_supply_config parameter, so the
+property get handler works as desired.
+
+Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
+Fixes: 3636859b280c ("power_supply: Add support for tps65217-charger")
+Signed-off-by: Sebastian Reichel <sre@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/power/tps65217_charger.c |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/power/tps65217_charger.c
++++ b/drivers/power/tps65217_charger.c
+@@ -197,6 +197,7 @@ static int tps65217_charger_probe(struct
+ {
+       struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
+       struct tps65217_charger *charger;
++      struct power_supply_config cfg = {};
+       int ret;
+       dev_dbg(&pdev->dev, "%s\n", __func__);
+@@ -209,9 +210,12 @@ static int tps65217_charger_probe(struct
+       charger->tps = tps;
+       charger->dev = &pdev->dev;
++      cfg.of_node = pdev->dev.of_node;
++      cfg.drv_data = charger;
++
+       charger->ac = devm_power_supply_register(&pdev->dev,
+                                                &tps65217_charger_desc,
+-                                               NULL);
++                                               &cfg);
+       if (IS_ERR(charger->ac)) {
+               dev_err(&pdev->dev, "failed: power supply register\n");
+               return PTR_ERR(charger->ac);
index 2f3cd51795f529389b943b524e5ce2e4ffdafcfb..89270f970ee5ff8eb7e6bf07a04f5df43124aebe 100644 (file)
@@ -237,3 +237,10 @@ net-ethernet-fec-fix-fixed-link-phydev-leaks.patch
 net-ethernet-ti-davinci_emac-fix-fixed-link-phydev-and-of-node-leaks.patch
 net-dsa-move-dsa-slave-destroy-code-to-slave.c.patch
 net-dsa-slave-fix-fixed-link-phydev-leaks.patch
+power-bq27xxx-fix-reading-for-bq27000-and-bq27010.patch
+power-bq27xxx-fix-register-numbers-of-bq27500.patch
+power-test_power-correctly-handle-empty-writes.patch
+power-bq27xxx_battery-fix-bq27541-averagepower-register-address.patch
+power_supply-tps65217-charger-fix-null-deref-during-property-export.patch
+net-vrf-fix-dst-reference-counting.patch
+net-don-t-delete-routes-in-different-vrfs.patch