Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next RFC WIP] Patch for XDP support for virtio_net
From: David Miller @ 2016-10-28  2:10 UTC (permalink / raw)
  To: alexander.duyck
  Cc: mst, john.fastabend, brouer, shrijeet, tom, netdev, shm, roopa,
	nikolay
In-Reply-To: <CAKgT0Ufe3QYtFpmtsL39-nbyy+YEt=gZKU_WUr9Wir+LTYLuEQ@mail.gmail.com>

From: Alexander Duyck <alexander.duyck@gmail.com>
Date: Thu, 27 Oct 2016 18:43:59 -0700

> On Thu, Oct 27, 2016 at 6:35 PM, David Miller <davem@davemloft.net> wrote:
>> From: "Michael S. Tsirkin" <mst@redhat.com>
>> Date: Fri, 28 Oct 2016 01:25:48 +0300
>>
>>> On Thu, Oct 27, 2016 at 05:42:18PM -0400, David Miller wrote:
>>>> From: "Michael S. Tsirkin" <mst@redhat.com>
>>>> Date: Fri, 28 Oct 2016 00:30:35 +0300
>>>>
>>>> > Something I'd like to understand is how does XDP address the
>>>> > problem that 100Byte packets are consuming 4K of memory now.
>>>>
>>>> Via page pools.  We're going to make a generic one, but right now
>>>> each and every driver implements a quick list of pages to allocate
>>>> from (and thus avoid the DMA man/unmap overhead, etc.)
>>>
>>> So to clarify, ATM virtio doesn't attempt to avoid dma map/unmap
>>> so there should be no issue with that even when using sub/page
>>> regions, assuming DMA APIs support sub-page map/unmap correctly.
>>
>> That's not what I said.
>>
>> The page pools are meant to address the performance degradation from
>> going to having one packet per page for the sake of XDP's
>> requirements.
>>
>> You still need to have one packet per page for correct XDP operation
>> whether you do page pools or not, and whether you have DMA mapping
>> (or it's equivalent virutalization operation) or not.
> 
> Maybe I am missing something here, but why do you need to limit things
> to one packet per page for correct XDP operation?  Most of the drivers
> out there now are usually storing something closer to at least 2
> packets per page, and with the DMA API fixes I am working on there
> should be no issue with changing the contents inside those pages since
> we won't invalidate or overwrite the data after the DMA buffer has
> been synchronized for use by the CPU.

Because with SKB's you can share the page with other packets.

With XDP you simply cannot.

It's software semantics that are the issue.  SKB frag list pages
are read only, XDP packets are writable.

This has nothing to do with "writability" of the pages wrt. DMA
mapping or cpu mappings.

^ permalink raw reply

* Re: [PATCH v2] ip6_tunnel: Clear IP6CB in ip6_tnl_xmit() after encapsulation
From: Tom Herbert @ 2016-10-28  2:17 UTC (permalink / raw)
  To: Eli Cooper; +Cc: Linux Kernel Network Developers, David S . Miller
In-Reply-To: <20161028015241.23258-1-elicooper@gmx.com>

On Thu, Oct 27, 2016 at 6:52 PM, Eli Cooper <elicooper@gmx.com> wrote:
> skb->cb may contain data from previous layers. In the observed scenario,
> the garbage data were misinterpreted as IP6CB(skb)->frag_max_size, so
> that small packets sent through the tunnel are mistakenly fragmented.
>
> This patch clears the control buffer for the next layer, after an IPv6
> header is installed.
>
Nice catch, but can you rectify this with what udp_tunnel6_xmit_skb is
doing. udp_tunnel6_xmit_skb calls ip6tunnel_xmit directly. Looks like
we do

memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED
                            | IPSKB_REROUTED);

Is this what we should be doing in ip6_tnl_xmit also, or is
udp_tunnel6_xmit_skb broken because it doesn't zero all the cb?

Thanks,
Tom

> Signed-off-by: Eli Cooper <elicooper@gmx.com>
> ---
> v2: clears the whole IP6CB altogether and does it after encapsulation
>
>  net/ipv6/ip6_tunnel.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
> index 202d16a..1487e17 100644
> --- a/net/ipv6/ip6_tunnel.c
> +++ b/net/ipv6/ip6_tunnel.c
> @@ -1174,6 +1174,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
>
>         skb_push(skb, sizeof(struct ipv6hdr));
>         skb_reset_network_header(skb);
> +       memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
>         ipv6h = ipv6_hdr(skb);
>         ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
>                      ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6));
> --
> 2.10.1
>

^ permalink raw reply

* Re: [net-next PATCH 2/3] net: Refactor removal of queues from XPS map and apply on num_tc changes
From: Tom Herbert @ 2016-10-28  2:35 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: Linux Kernel Network Developers, John Fastabend, intel-wired-lan,
	David S. Miller
In-Reply-To: <20161027154009.13989.25522.stgit@ahduyck-blue-test.jf.intel.com>

On Thu, Oct 27, 2016 at 8:40 AM, Alexander Duyck
<alexander.h.duyck@intel.com> wrote:
> This patch updates the code for removing queues from the XPS map and makes
> it so that we can apply the code any time we change either the number of
> traffic classes or the mapping of a given block of queues.  This way we
> avoid having queues pulling traffic from a foreign traffic class.
>
> Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
> ---
>  net/core/dev.c |   79 ++++++++++++++++++++++++++++++++++++++++----------------
>  1 file changed, 56 insertions(+), 23 deletions(-)
>
> diff --git a/net/core/dev.c b/net/core/dev.c
> index d4d45bf..d124081 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -1953,32 +1953,56 @@ static void netif_setup_tc(struct net_device *dev, unsigned int txq)
>  #define xmap_dereference(P)            \
>         rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex))
>
> -static struct xps_map *remove_xps_queue(struct xps_dev_maps *dev_maps,
> -                                       int cpu, u16 index)
> +static bool remove_xps_queue(struct xps_dev_maps *dev_maps,
> +                            int tci, u16 index)
>  {
>         struct xps_map *map = NULL;
>         int pos;
>
>         if (dev_maps)
> -               map = xmap_dereference(dev_maps->cpu_map[cpu]);
> +               map = xmap_dereference(dev_maps->cpu_map[tci]);
> +       if (!map)
> +               return false;
>
> -       for (pos = 0; map && pos < map->len; pos++) {
> -               if (map->queues[pos] == index) {
> -                       if (map->len > 1) {
> -                               map->queues[pos] = map->queues[--map->len];
> -                       } else {
> -                               RCU_INIT_POINTER(dev_maps->cpu_map[cpu], NULL);
> -                               kfree_rcu(map, rcu);
> -                               map = NULL;
> -                       }
> +       for (pos = map->len; pos--;) {
> +               if (map->queues[pos] != index)
> +                       continue;
> +
> +               if (map->len > 1) {
> +                       map->queues[pos] = map->queues[--map->len];
>                         break;
>                 }
> +
> +               RCU_INIT_POINTER(dev_maps->cpu_map[tci], NULL);
> +               kfree_rcu(map, rcu);
> +               return false;
>         }
>
> -       return map;
> +       return true;
>  }
>
> -static void netif_reset_xps_queues_gt(struct net_device *dev, u16 index)
> +static bool remove_xps_queue_cpu(struct net_device *dev,
> +                                struct xps_dev_maps *dev_maps,
> +                                int cpu, u16 offset, u16 count)
> +{
> +       bool active = false;
> +       int i;
> +
> +       count += offset;
> +       i = count;
> +
> +       do {
> +               if (i-- == offset) {
> +                       active = true;
> +                       break;
> +               }
> +       } while (remove_xps_queue(dev_maps, cpu, i));
> +
IMO do/while's are hard to read. Does something like this work:

static bool remove_xps_queue_cpu(struct net_device *dev,
                                struct xps_dev_maps *dev_maps,
                                int cpu, u16 offset, u16 count)
{
     int i;

     for (i = count + offset; i > offset; i--)
          if (!remove_xps_queue(dev_maps, cpu, i - 1))
              break;

     return (i == offset);
}

> +       return active;
> +}
> +
> +static void netif_reset_xps_queues(struct net_device *dev, u16 offset,
> +                                  u16 count)
>  {
>         struct xps_dev_maps *dev_maps;
>         int cpu, i;
> @@ -1990,21 +2014,16 @@ static void netif_reset_xps_queues_gt(struct net_device *dev, u16 index)
>         if (!dev_maps)
>                 goto out_no_maps;
>
> -       for_each_possible_cpu(cpu) {
> -               for (i = index; i < dev->num_tx_queues; i++) {
> -                       if (!remove_xps_queue(dev_maps, cpu, i))
> -                               break;
> -               }
> -               if (i == dev->num_tx_queues)
> -                       active = true;
> -       }
> +       for_each_possible_cpu(cpu)
> +               active |= remove_xps_queue_cpu(dev, dev_maps, cpu, offset,
> +                                              count);

Maybe just do dumb "if (remove_xps...) active = true;"

>
>         if (!active) {
>                 RCU_INIT_POINTER(dev->xps_maps, NULL);
>                 kfree_rcu(dev_maps, rcu);
>         }
>
> -       for (i = index; i < dev->num_tx_queues; i++)
> +       for (i = offset + (count - 1); count--; i--)
>                 netdev_queue_numa_node_write(netdev_get_tx_queue(dev, i),
>                                              NUMA_NO_NODE);
>
> @@ -2012,6 +2031,11 @@ static void netif_reset_xps_queues_gt(struct net_device *dev, u16 index)
>         mutex_unlock(&xps_map_mutex);
>  }
>
> +static void netif_reset_xps_queues_gt(struct net_device *dev, u16 index)
> +{
> +       netif_reset_xps_queues(dev, index, dev->num_tx_queues - index);
> +}
> +
>  static struct xps_map *expand_xps_map(struct xps_map *map,
>                                       int cpu, u16 index)
>  {
> @@ -2175,6 +2199,9 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
>  #endif
>  void netdev_reset_tc(struct net_device *dev)
>  {
> +#ifdef CONFIG_XPS
> +       netif_reset_xps_queues_gt(dev, 0);
> +#endif
>         dev->num_tc = 0;
>         memset(dev->tc_to_txq, 0, sizeof(dev->tc_to_txq));
>         memset(dev->prio_tc_map, 0, sizeof(dev->prio_tc_map));
> @@ -2186,6 +2213,9 @@ int netdev_set_tc_queue(struct net_device *dev, u8 tc, u16 count, u16 offset)
>         if (tc >= dev->num_tc)
>                 return -EINVAL;
>
> +#ifdef CONFIG_XPS
> +       netif_reset_xps_queues(dev, offset, count);
> +#endif
>         dev->tc_to_txq[tc].count = count;
>         dev->tc_to_txq[tc].offset = offset;
>         return 0;
> @@ -2197,6 +2227,9 @@ int netdev_set_num_tc(struct net_device *dev, u8 num_tc)
>         if (num_tc > TC_MAX_QUEUE)
>                 return -EINVAL;
>
> +#ifdef CONFIG_XPS
> +       netif_reset_xps_queues_gt(dev, 0);
> +#endif
>         dev->num_tc = num_tc;
>         return 0;
>  }
>

^ permalink raw reply

* Re: [net-next PATCH 3/3] net: Add support for XPS with QoS via traffic classes
From: Tom Herbert @ 2016-10-28  2:38 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: Linux Kernel Network Developers, John Fastabend, intel-wired-lan,
	David S. Miller
In-Reply-To: <20161027154014.13989.33421.stgit@ahduyck-blue-test.jf.intel.com>

On Thu, Oct 27, 2016 at 8:40 AM, Alexander Duyck
<alexander.h.duyck@intel.com> wrote:
> This patch adds support for setting and using XPS when QoS via traffic
> classes is enabled.  With this change we will factor in the priority and
> traffic class mapping of the packet and use that information to correctly
> select the queue.
>
> This allows us to define a set of queues for a given traffic class via
> mqprio and then configure the XPS mapping for those queues so that the
> traffic flows can avoid head-of-line blocking between the individual CPUs
> if so desired.
>
Does this change the sys API for XPS? Is it up the user to know which
are priority queues in sys?

Thanks,
Tom

> Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
> ---
>  include/linux/netdevice.h |    5 +-
>  net/core/dev.c            |  136 +++++++++++++++++++++++++++++++++------------
>  net/core/net-sysfs.c      |   31 +++++++---
>  3 files changed, 122 insertions(+), 50 deletions(-)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index d045432..56f90f7 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -732,8 +732,8 @@ struct xps_dev_maps {
>         struct rcu_head rcu;
>         struct xps_map __rcu *cpu_map[0];
>  };
> -#define XPS_DEV_MAPS_SIZE (sizeof(struct xps_dev_maps) +               \
> -    (nr_cpu_ids * sizeof(struct xps_map *)))
> +#define XPS_DEV_MAPS_SIZE(_tcs) (sizeof(struct xps_dev_maps) +         \
> +       (nr_cpu_ids * (_tcs) * sizeof(struct xps_map *)))
>  #endif /* CONFIG_XPS */
>
>  #define TC_MAX_QUEUE   16
> @@ -1920,6 +1920,7 @@ int netdev_set_prio_tc_map(struct net_device *dev, u8 prio, u8 tc)
>         return 0;
>  }
>
> +int netdev_txq_to_tc(struct net_device *dev, unsigned int txq);
>  void netdev_reset_tc(struct net_device *dev);
>  int netdev_set_tc_queue(struct net_device *dev, u8 tc, u16 count, u16 offset);
>  int netdev_set_num_tc(struct net_device *dev, u8 num_tc);
> diff --git a/net/core/dev.c b/net/core/dev.c
> index d124081..37c1096 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -1948,6 +1948,23 @@ static void netif_setup_tc(struct net_device *dev, unsigned int txq)
>         }
>  }
>
> +int netdev_txq_to_tc(struct net_device *dev, unsigned int txq)
> +{
> +       if (dev->num_tc) {
> +               struct netdev_tc_txq *tc = &dev->tc_to_txq[0];
> +               int i;
> +
> +               for (i = 0; i < TC_MAX_QUEUE; i++, tc++) {
> +                       if ((txq - tc->offset) < tc->count)
> +                               return i;
> +               }
> +
> +               return -1;
> +       }
> +
> +       return 0;
> +}
> +
>  #ifdef CONFIG_XPS
>  static DEFINE_MUTEX(xps_map_mutex);
>  #define xmap_dereference(P)            \
> @@ -1985,18 +2002,22 @@ static bool remove_xps_queue_cpu(struct net_device *dev,
>                                  struct xps_dev_maps *dev_maps,
>                                  int cpu, u16 offset, u16 count)
>  {
> +       int tc = dev->num_tc ? : 1;
>         bool active = false;
> -       int i;
> +       int tci;
>
>         count += offset;
> -       i = count;
>
> -       do {
> -               if (i-- == offset) {
> -                       active = true;
> -                       break;
> -               }
> -       } while (remove_xps_queue(dev_maps, cpu, i));
> +       for (tci = cpu * tc; tc--; tci++) {
> +               int i = count;
> +
> +               do {
> +                       if (i-- == offset) {
> +                               active = true;
> +                               break;
> +                       }
> +               } while (remove_xps_queue(dev_maps, tci, i));
> +       }
>
>         return active;
>  }
> @@ -2075,20 +2096,28 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
>                         u16 index)
>  {
>         struct xps_dev_maps *dev_maps, *new_dev_maps = NULL;
> +       int i, cpu, tci, numa_node_id = -2;
> +       int maps_sz, num_tc = 1, tc = 0;
>         struct xps_map *map, *new_map;
> -       int maps_sz = max_t(unsigned int, XPS_DEV_MAPS_SIZE, L1_CACHE_BYTES);
> -       int cpu, numa_node_id = -2;
>         bool active = false;
>
> +       if (dev->num_tc) {
> +               num_tc = dev->num_tc;
> +               tc = netdev_txq_to_tc(dev, index);
> +               if (tc < 0)
> +                       return -EINVAL;
> +       }
> +
> +       maps_sz = XPS_DEV_MAPS_SIZE(num_tc);
> +       if (maps_sz < L1_CACHE_BYTES)
> +               maps_sz = L1_CACHE_BYTES;
> +
>         mutex_lock(&xps_map_mutex);
>
>         dev_maps = xmap_dereference(dev->xps_maps);
>
>         /* allocate memory for queue storage */
> -       for_each_online_cpu(cpu) {
> -               if (!cpumask_test_cpu(cpu, mask))
> -                       continue;
> -
> +       for_each_cpu_and(cpu, cpu_online_mask, mask) {
>                 if (!new_dev_maps)
>                         new_dev_maps = kzalloc(maps_sz, GFP_KERNEL);
>                 if (!new_dev_maps) {
> @@ -2096,25 +2125,35 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
>                         return -ENOMEM;
>                 }
>
> -               map = dev_maps ? xmap_dereference(dev_maps->cpu_map[cpu]) :
> +               tci = cpu * num_tc + tc;
> +               map = dev_maps ? xmap_dereference(dev_maps->cpu_map[tci]) :
>                                  NULL;
>
>                 map = expand_xps_map(map, cpu, index);
>                 if (!map)
>                         goto error;
>
> -               RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu], map);
> +               RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map);
>         }
>
>         if (!new_dev_maps)
>                 goto out_no_new_maps;
>
>         for_each_possible_cpu(cpu) {
> +               /* copy maps belonging to foreign traffic classes */
> +               tci = cpu * num_tc;
> +               for (i = 0; dev_maps && i < tc; i++, tci++) {
> +                       /* fill in the new device map from the old device map */
> +                       map = xmap_dereference(dev_maps->cpu_map[tci]);
> +                       RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map);
> +               }
> +
> +               tci = cpu * num_tc + tc;
>                 if (cpumask_test_cpu(cpu, mask) && cpu_online(cpu)) {
>                         /* add queue to CPU maps */
>                         int pos = 0;
>
> -                       map = xmap_dereference(new_dev_maps->cpu_map[cpu]);
> +                       map = xmap_dereference(new_dev_maps->cpu_map[tci]);
>                         while ((pos < map->len) && (map->queues[pos] != index))
>                                 pos++;
>
> @@ -2128,26 +2167,37 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
>  #endif
>                 } else if (dev_maps) {
>                         /* fill in the new device map from the old device map */
> -                       map = xmap_dereference(dev_maps->cpu_map[cpu]);
> -                       RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu], map);
> +                       map = xmap_dereference(dev_maps->cpu_map[tci]);
> +                       RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map);
>                 }
>
> +               /* copy maps belonging to foreign traffic classes */
> +               for (i = tc, tci++; dev_maps && (++i < num_tc); tci++) {
> +                       /* fill in the new device map from the old device map */
> +                       map = xmap_dereference(dev_maps->cpu_map[tci]);
> +                       RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map);
> +               }
>         }
>
>         rcu_assign_pointer(dev->xps_maps, new_dev_maps);
>
>         /* Cleanup old maps */
> -       if (dev_maps) {
> -               for_each_possible_cpu(cpu) {
> -                       new_map = xmap_dereference(new_dev_maps->cpu_map[cpu]);
> -                       map = xmap_dereference(dev_maps->cpu_map[cpu]);
> +       if (!dev_maps)
> +               goto out_no_old_maps;
> +
> +       for_each_possible_cpu(cpu) {
> +               tci = cpu * num_tc;
> +               for (i = 0; i < num_tc; i++, tci++) {
> +                       new_map = xmap_dereference(new_dev_maps->cpu_map[tci]);
> +                       map = xmap_dereference(dev_maps->cpu_map[tci]);
>                         if (map && map != new_map)
>                                 kfree_rcu(map, rcu);
>                 }
> -
> -               kfree_rcu(dev_maps, rcu);
>         }
>
> +       kfree_rcu(dev_maps, rcu);
> +
> +out_no_old_maps:
>         dev_maps = new_dev_maps;
>         active = true;
>
> @@ -2162,11 +2212,13 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
>
>         /* removes queue from unused CPUs */
>         for_each_possible_cpu(cpu) {
> -               if (cpumask_test_cpu(cpu, mask) && cpu_online(cpu))
> -                       continue;
> -
> -               if (remove_xps_queue(dev_maps, cpu, index))
> -                       active = true;
> +               tci = cpu * num_tc;
> +               for (i = 0; i < tc; i++, tci++)
> +                       active |= remove_xps_queue(dev_maps, tci, index);
> +               if (!cpumask_test_cpu(cpu, mask) || !cpu_online(cpu))
> +                       active |= remove_xps_queue(dev_maps, tci, index);
> +               for (i = tc, tci++; ++i < num_tc; tci++)
> +                       active |= remove_xps_queue(dev_maps, tci, index);
>         }
>
>         /* free map if not active */
> @@ -2182,11 +2234,15 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
>  error:
>         /* remove any maps that we added */
>         for_each_possible_cpu(cpu) {
> -               new_map = xmap_dereference(new_dev_maps->cpu_map[cpu]);
> -               map = dev_maps ? xmap_dereference(dev_maps->cpu_map[cpu]) :
> -                                NULL;
> -               if (new_map && new_map != map)
> -                       kfree(new_map);
> +               tci = cpu * num_tc;
> +               for (i = 0; i < num_tc; i++, tci++) {
> +                       new_map = xmap_dereference(new_dev_maps->cpu_map[tci]);
> +                       map = dev_maps ?
> +                             xmap_dereference(dev_maps->cpu_map[tci]) :
> +                             NULL;
> +                       if (new_map && new_map != map)
> +                               kfree(new_map);
> +               }
>         }
>
>         mutex_unlock(&xps_map_mutex);
> @@ -3146,8 +3202,14 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
>         rcu_read_lock();
>         dev_maps = rcu_dereference(dev->xps_maps);
>         if (dev_maps) {
> -               map = rcu_dereference(
> -                   dev_maps->cpu_map[skb->sender_cpu - 1]);
> +               unsigned int tci = skb->sender_cpu - 1;
> +
> +               if (dev->num_tc) {
> +                       tci *= dev->num_tc;
> +                       tci += netdev_get_prio_tc_map(dev, skb->priority);
> +               }
> +
> +               map = rcu_dereference(dev_maps->cpu_map[tci]);
>                 if (map) {
>                         if (map->len == 1)
>                                 queue_index = map->queues[0];
> diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
> index 6e4f347..763c1e1 100644
> --- a/net/core/net-sysfs.c
> +++ b/net/core/net-sysfs.c
> @@ -1190,29 +1190,38 @@ static ssize_t show_xps_map(struct netdev_queue *queue,
>                             struct netdev_queue_attribute *attribute, char *buf)
>  {
>         struct net_device *dev = queue->dev;
> +       int cpu, len, num_tc = 1, tc = 0;
>         struct xps_dev_maps *dev_maps;
>         cpumask_var_t mask;
>         unsigned long index;
> -       int i, len;
>
>         if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
>                 return -ENOMEM;
>
>         index = get_netdev_queue_index(queue);
>
> +       if (dev->num_tc) {
> +               num_tc = dev->num_tc;
> +               tc = netdev_txq_to_tc(dev, index);
> +               if (tc < 0)
> +                       return -EINVAL;
> +       }
> +
>         rcu_read_lock();
>         dev_maps = rcu_dereference(dev->xps_maps);
>         if (dev_maps) {
> -               for_each_possible_cpu(i) {
> -                       struct xps_map *map =
> -                           rcu_dereference(dev_maps->cpu_map[i]);
> -                       if (map) {
> -                               int j;
> -                               for (j = 0; j < map->len; j++) {
> -                                       if (map->queues[j] == index) {
> -                                               cpumask_set_cpu(i, mask);
> -                                               break;
> -                                       }
> +               for_each_possible_cpu(cpu) {
> +                       int i, tci = cpu * num_tc + tc;
> +                       struct xps_map *map;
> +
> +                       map = rcu_dereference(dev_maps->cpu_map[tci]);
> +                       if (!map)
> +                               continue;
> +
> +                       for (i = map->len; i--;) {
> +                               if (map->queues[i] == index) {
> +                                       cpumask_set_cpu(cpu, mask);
> +                                       break;
>                                 }
>                         }
>                 }
>

^ permalink raw reply

* RE: [PATCH] e1000e: x86: e1000 driver trying to free already-free irq.
From: Brown, Aaron F @ 2016-10-28  2:50 UTC (permalink / raw)
  To: David Singleton, Kirsher, Jeffrey T
  Cc: khalidm, intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <20161017165108.29718-5-davsingl@cisco.com>

> From: netdev-owner@vger.kernel.org [mailto:netdev-
> owner@vger.kernel.org] On Behalf Of David Singleton
> Sent: Monday, October 17, 2016 9:51 AM
> To: Kirsher, Jeffrey T <jeffrey.t.kirsher@intel.com>
> Cc: khalidm <khalidm@cisco.com>; intel-wired-lan@lists.osuosl.org;
> netdev@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: [PATCH] e1000e: x86: e1000 driver trying to free already-free irq.
> 
> From: khalidm <khalidm@cisco.com>
> 
> During systemd reboot sequence network driver interface is shutdown
> by e1000_close. The PCI driver interface is shut by e1000_shutdown.
> The e1000_shutdown checks for netif_running status, if still up it
> brings down driver. But it disables msi outside of this if statement,
> regardless of netif status. All this is OK when e1000_close happens
> after shutdown. However, by default, everything in systemd is done
> in parallel. This creates a conditions where e1000_shutdown is called
> after e1000_close, therefore hitting BUG_ON assert in free_msi_irqs.
> 
> Cc-Id: xe-kernel@external.cisco.com
> Signed-off-by: khalidm <khalidm@cisco.com>
> Signed-off-by: David Singleton <davsingl@cisco.com>
> ---
>  drivers/net/ethernet/intel/e1000e/netdev.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Tested-by: Aaron Brown <aaron.f.brown@intel.com>

^ permalink raw reply

* Re: [PATCH v2 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)
From: Tom Herbert @ 2016-10-28  2:50 UTC (permalink / raw)
  To: David Lebrun; +Cc: Linux Kernel Network Developers
In-Reply-To: <1477497292-22155-2-git-send-email-david.lebrun@uclouvain.be>

On Wed, Oct 26, 2016 at 8:54 AM, David Lebrun <david.lebrun@uclouvain.be> wrote:
> Implement minimal support for processing of SR-enabled packets
> as described in
> https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-02.
>
> This patch implements the following operations:
> - Intermediate segment endpoint: incrementation of active segment and rerouting.
> - Egress for SR-encapsulated packets: decapsulation of outer IPv6 header + SRH
>   and routing of inner packet.
> - Cleanup flag support for SR-inlined packets: removal of SRH if we are the
>   penultimate segment endpoint.
>
> A per-interface sysctl seg6_enabled is provided, to accept/deny SR-enabled
> packets. Default is deny.
>
> This patch does not provide support for HMAC-signed packets.
>
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
> ---
>  include/linux/ipv6.h      |   1 +
>  include/linux/seg6.h      |   6 ++
>  include/uapi/linux/ipv6.h |   2 +
>  include/uapi/linux/seg6.h |  48 ++++++++++++
>  net/ipv6/addrconf.c       |  10 +++
>  net/ipv6/exthdrs.c        | 183 ++++++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 250 insertions(+)
>  create mode 100644 include/linux/seg6.h
>  create mode 100644 include/uapi/linux/seg6.h
>
> diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
> index 7e9a789..76830e6 100644
> --- a/include/linux/ipv6.h
> +++ b/include/linux/ipv6.h
> @@ -64,6 +64,7 @@ struct ipv6_devconf {
>         } stable_secret;
>         __s32           use_oif_addrs_only;
>         __s32           keep_addr_on_down;
> +       __s32           seg6_enabled;
>
>         struct ctl_table_header *sysctl_header;
>  };
> diff --git a/include/linux/seg6.h b/include/linux/seg6.h
> new file mode 100644
> index 0000000..7a66d2b
> --- /dev/null
> +++ b/include/linux/seg6.h
> @@ -0,0 +1,6 @@
> +#ifndef _LINUX_SEG6_H
> +#define _LINUX_SEG6_H
> +
> +#include <uapi/linux/seg6.h>
> +
> +#endif
> diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
> index 8c27723..7ff1d65 100644
> --- a/include/uapi/linux/ipv6.h
> +++ b/include/uapi/linux/ipv6.h
> @@ -39,6 +39,7 @@ struct in6_ifreq {
>  #define IPV6_SRCRT_STRICT      0x01    /* Deprecated; will be removed */
>  #define IPV6_SRCRT_TYPE_0      0       /* Deprecated; will be removed */
>  #define IPV6_SRCRT_TYPE_2      2       /* IPv6 type 2 Routing Header   */
> +#define IPV6_SRCRT_TYPE_4      4       /* Segment Routing with IPv6 */
>
>  /*
>   *     routing header
> @@ -178,6 +179,7 @@ enum {
>         DEVCONF_DROP_UNSOLICITED_NA,
>         DEVCONF_KEEP_ADDR_ON_DOWN,
>         DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
> +       DEVCONF_SEG6_ENABLED,
>         DEVCONF_MAX
>  };
>
> diff --git a/include/uapi/linux/seg6.h b/include/uapi/linux/seg6.h
> new file mode 100644
> index 0000000..7630e7d
> --- /dev/null
> +++ b/include/uapi/linux/seg6.h
> @@ -0,0 +1,48 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  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.
> + */
> +
> +#ifndef _UAPI_LINUX_SEG6_H
> +#define _UAPI_LINUX_SEG6_H
> +
> +/*
> + * SRH
> + */
> +struct ipv6_sr_hdr {
> +       __u8    nexthdr;
> +       __u8    hdrlen;
> +       __u8    type;
> +       __u8    segments_left;
> +       __u8    first_segment;
> +       __u8    flag_1;
> +       __u8    flag_2;
> +       __u8    reserved;
> +
> +       struct in6_addr segments[0];
> +};
> +
> +#define SR6_FLAG1_CLEANUP      (1 << 7)
> +#define SR6_FLAG1_PROTECTED    (1 << 6)
> +#define SR6_FLAG1_OAM          (1 << 5)
> +#define SR6_FLAG1_ALERT                (1 << 4)
> +#define SR6_FLAG1_HMAC         (1 << 3)
> +
> +#define SR6_TLV_INGRESS                1
> +#define SR6_TLV_EGRESS         2
> +#define SR6_TLV_OPAQUE         3
> +#define SR6_TLV_PADDING                4
> +#define SR6_TLV_HMAC           5
> +
> +#define sr_has_cleanup(srh) ((srh)->flag_1 & SR6_FLAG1_CLEANUP)
> +#define sr_has_hmac(srh) ((srh)->flag_1 & SR6_FLAG1_HMAC)
> +
> +#endif
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index d8983e1..8d068ee 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -239,6 +239,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
>         .use_oif_addrs_only     = 0,
>         .ignore_routes_with_linkdown = 0,
>         .keep_addr_on_down      = 0,
> +       .seg6_enabled           = 0,
>  };
>
>  static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> @@ -285,6 +286,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
>         .use_oif_addrs_only     = 0,
>         .ignore_routes_with_linkdown = 0,
>         .keep_addr_on_down      = 0,
> +       .seg6_enabled           = 0,
>  };
>
>  /* Check if a valid qdisc is available */
> @@ -4965,6 +4967,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
>         array[DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = cnf->drop_unicast_in_l2_multicast;
>         array[DEVCONF_DROP_UNSOLICITED_NA] = cnf->drop_unsolicited_na;
>         array[DEVCONF_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down;
> +       array[DEVCONF_SEG6_ENABLED] = cnf->seg6_enabled;
>  }
>
>  static inline size_t inet6_ifla6_size(void)
> @@ -6057,6 +6060,13 @@ static const struct ctl_table addrconf_sysctl[] = {
>
>         },
>         {
> +               .procname       = "seg6_enabled",
> +               .data           = &ipv6_devconf.seg6_enabled,
> +               .maxlen         = sizeof(int),
> +               .mode           = 0644,
> +               .proc_handler   = proc_dointvec,
> +       },
> +       {
>                 /* sentinel */
>         }
>  };
> diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
> index 139ceb6..cf9f338 100644
> --- a/net/ipv6/exthdrs.c
> +++ b/net/ipv6/exthdrs.c
> @@ -47,6 +47,7 @@
>  #if IS_ENABLED(CONFIG_IPV6_MIP6)
>  #include <net/xfrm.h>
>  #endif
> +#include <linux/seg6.h>
>
>  #include <linux/uaccess.h>
>
> @@ -286,6 +287,184 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
>         return -1;
>  }
>
> +static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,
> +                                    __be32 to)
> +{
> +       __be32 diff[] = { ~from, to };
> +
> +       skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);
> +}
> +
> +static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,
> +                                     __be32 *to)
> +{
> +       __be32 diff[] = {
> +               ~from[0], ~from[1], ~from[2], ~from[3],
> +               to[0], to[1], to[2], to[3],
> +       };
> +
> +       skb->csum = ~csum_partial((char *)diff, sizeof(diff), ~skb->csum);
> +}
These should be in a common header file.

> +
> +static void seg6_update_csum(struct sk_buff *skb)
> +{
> +       struct ipv6_sr_hdr *hdr;
> +       struct in6_addr *addr;
> +       __be32 from, to;
> +
> +       /* srh is at transport offset and seg_left is already decremented
> +        * but daddr is not yet updated with next segment
> +        */
> +
> +       hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
> +       addr = hdr->segments + hdr->segments_left;
> +
> +       hdr->segments_left++;
> +       from = *(__be32 *)hdr;
> +
> +       hdr->segments_left--;
> +       to = *(__be32 *)hdr;
> +
> +       /* update skb csum with diff resulting from seg_left decrement */
> +
> +       update_csum_diff4(skb, from, to);
> +
> +       /* compute csum diff between current and next segment and update */
> +
> +       update_csum_diff16(skb, (__be32 *)(&ipv6_hdr(skb)->daddr),
> +                          (__be32 *)addr);
> +}
NIce. Have you tested that checksum offload works if the penultimate
and final addresses are in same host?

> +
> +static int ipv6_srh_rcv(struct sk_buff *skb)
> +{
> +       struct inet6_skb_parm *opt = IP6CB(skb);
> +       struct net *net = dev_net(skb->dev);
> +       struct ipv6_sr_hdr *hdr;
> +       struct inet6_dev *idev;
> +       struct in6_addr *addr;
> +       int cleanup = 0;
Should be a bool?

> +       int accept_seg6;
> +
> +       hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
> +
> +       idev = __in6_dev_get(skb->dev);
> +
> +       accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
> +       if (accept_seg6 > idev->cnf.seg6_enabled)
> +               accept_seg6 = idev->cnf.seg6_enabled;
> +
> +       if (!accept_seg6) {
> +               kfree_skb(skb);
> +               return -1;
> +       }
> +
> +looped_back:
> +       if (hdr->segments_left > 0) {
> +               if (hdr->nexthdr != NEXTHDR_IPV6 && hdr->segments_left == 1 &&
> +                   sr_has_cleanup(hdr))
> +                       cleanup = 1;
> +       } else {
> +               if (hdr->nexthdr == NEXTHDR_IPV6) {
> +                       int offset = (hdr->hdrlen + 1) << 3;
> +
> +                       skb_postpull_rcsum(skb, skb_network_header(skb),
> +                                          skb_network_header_len(skb));
> +
> +                       if (!pskb_pull(skb, offset)) {
> +                               kfree_skb(skb);
> +                               return -1;
> +                       }
> +                       skb_postpull_rcsum(skb, skb_transport_header(skb),
> +                                          offset);
> +
> +                       skb_reset_network_header(skb);
> +                       skb_reset_transport_header(skb);
> +                       skb->encapsulation = 0;
> +
> +                       __skb_tunnel_rx(skb, skb->dev, net);
> +
> +                       netif_rx(skb);
> +                       return -1;
> +               }
> +
> +               opt->srcrt = skb_network_header_len(skb);
> +               opt->lastopt = opt->srcrt;
> +               skb->transport_header += (hdr->hdrlen + 1) << 3;
> +               opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
> +
> +               return 1;
> +       }
> +
> +       if (skb_cloned(skb)) {
> +               if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
> +                       __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
> +                                       IPSTATS_MIB_OUTDISCARDS);
> +                       kfree_skb(skb);
> +                       return -1;
> +               }
> +       }
> +
> +       hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
> +
> +       hdr->segments_left--;
> +       addr = hdr->segments + hdr->segments_left;
> +
> +       skb_push(skb, sizeof(struct ipv6hdr));
> +
> +       if (skb->ip_summed == CHECKSUM_COMPLETE)
> +               seg6_update_csum(skb);
> +
> +       ipv6_hdr(skb)->daddr = *addr;
> +
> +       if (cleanup) {
> +               int srhlen = (hdr->hdrlen + 1) << 3;
> +               int nh = hdr->nexthdr;
> +
> +               skb_pull_rcsum(skb, sizeof(struct ipv6hdr) + srhlen);
> +               memmove(skb_network_header(skb) + srhlen,
> +                       skb_network_header(skb),
> +                       (unsigned char *)hdr - skb_network_header(skb));
> +               skb->network_header += srhlen;
> +               ipv6_hdr(skb)->nexthdr = nh;
> +               ipv6_hdr(skb)->payload_len = htons(skb->len -
> +                                                  sizeof(struct ipv6hdr));
> +               skb_push_rcsum(skb, sizeof(struct ipv6hdr));
> +       }
> +
> +       skb_dst_drop(skb);
> +
> +       ip6_route_input(skb);
> +
> +       if (skb_dst(skb)->error) {
> +               dst_input(skb);
> +               return -1;
> +       }
> +
> +       if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
> +               if (ipv6_hdr(skb)->hop_limit <= 1) {
> +                       __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
> +                                       IPSTATS_MIB_INHDRERRORS);
> +                       icmpv6_send(skb, ICMPV6_TIME_EXCEED,
> +                                   ICMPV6_EXC_HOPLIMIT, 0);
> +                       kfree_skb(skb);
> +                       return -1;
> +               }
> +               ipv6_hdr(skb)->hop_limit--;
> +
> +               /* be sure that srh is still present before reinjecting */
> +               if (!cleanup) {
> +                       skb_pull(skb, sizeof(struct ipv6hdr));
> +                       goto looped_back;
> +               }
> +               skb_set_transport_header(skb, sizeof(struct ipv6hdr));
> +               IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
> +       }
> +
> +       dst_input(skb);
> +
> +       return -1;
> +}
> +
>  /********************************
>    Routing header.
>   ********************************/
> @@ -326,6 +505,10 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
>                 return -1;
>         }
>
> +       /* segment routing */
> +       if (hdr->type == IPV6_SRCRT_TYPE_4)
> +               return ipv6_srh_rcv(skb);
> +
>  looped_back:
>         if (hdr->segments_left == 0) {
>                 switch (hdr->type) {
> --
> 2.7.3
>
Acked-by: Tom Herbert <tom@herberland.com>

^ permalink raw reply

* Re: [PATCH v2 3/9] ipv6: sr: add support for SRH encapsulation and injection with lwtunnels
From: Tom Herbert @ 2016-10-28  2:56 UTC (permalink / raw)
  To: David Lebrun; +Cc: Linux Kernel Network Developers
In-Reply-To: <1477497292-22155-4-git-send-email-david.lebrun@uclouvain.be>

On Wed, Oct 26, 2016 at 8:54 AM, David Lebrun <david.lebrun@uclouvain.be> wrote:
> This patch creates a new type of interfaceless lightweight tunnel (SEG6),
> enabling the encapsulation and injection of SRH within locally emitted
> packets and forwarded packets.
>
> From a configuration viewpoint, a seg6 tunnel would be configured as follows:
>
>   ip -6 ro ad fc00::1/128 encap seg6 mode encap segs fc42::1,fc42::2,fc42::3 dev eth0
>
> Any packet whose destination address is fc00::1 would thus be encapsulated
> within an outer IPv6 header containing the SRH with three segments, and would
> actually be routed to the first segment of the list. If `mode inline' was
> specified instead of `mode encap', then the SRH would be directly inserted
> after the IPv6 header without outer encapsulation.
>
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
> ---
>  include/linux/seg6_iptunnel.h      |   6 +
>  include/net/seg6.h                 |   1 +
>  include/uapi/linux/lwtunnel.h      |   1 +
>  include/uapi/linux/seg6_iptunnel.h |  41 ++++
>  net/core/lwtunnel.c                |   2 +
>  net/ipv6/Makefile                  |   2 +-
>  net/ipv6/seg6_iptunnel.c           | 370 +++++++++++++++++++++++++++++++++++++
>  7 files changed, 422 insertions(+), 1 deletion(-)
>  create mode 100644 include/linux/seg6_iptunnel.h
>  create mode 100644 include/uapi/linux/seg6_iptunnel.h
>  create mode 100644 net/ipv6/seg6_iptunnel.c
>
> diff --git a/include/linux/seg6_iptunnel.h b/include/linux/seg6_iptunnel.h
> new file mode 100644
> index 0000000..5377cf6
> --- /dev/null
> +++ b/include/linux/seg6_iptunnel.h
> @@ -0,0 +1,6 @@
> +#ifndef _LINUX_SEG6_IPTUNNEL_H
> +#define _LINUX_SEG6_IPTUNNEL_H
> +
> +#include <uapi/linux/seg6_iptunnel.h>
> +
> +#endif
> diff --git a/include/net/seg6.h b/include/net/seg6.h
> index a9d9a9b..53d3bdb 100644
> --- a/include/net/seg6.h
> +++ b/include/net/seg6.h
> @@ -16,6 +16,7 @@
>
>  #include <linux/net.h>
>  #include <linux/ipv6.h>
> +#include <net/lwtunnel.h>
>
>  struct seg6_pernet_data {
>         struct mutex lock;
> diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h
> index a478fe8..453cc62 100644
> --- a/include/uapi/linux/lwtunnel.h
> +++ b/include/uapi/linux/lwtunnel.h
> @@ -9,6 +9,7 @@ enum lwtunnel_encap_types {
>         LWTUNNEL_ENCAP_IP,
>         LWTUNNEL_ENCAP_ILA,
>         LWTUNNEL_ENCAP_IP6,
> +       LWTUNNEL_ENCAP_SEG6,
>         __LWTUNNEL_ENCAP_MAX,
>  };
>
> diff --git a/include/uapi/linux/seg6_iptunnel.h b/include/uapi/linux/seg6_iptunnel.h
> new file mode 100644
> index 0000000..da5524a
> --- /dev/null
> +++ b/include/uapi/linux/seg6_iptunnel.h
> @@ -0,0 +1,41 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  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.
> + */
> +
> +#ifndef _UAPI_LINUX_SEG6_IPTUNNEL_H
> +#define _UAPI_LINUX_SEG6_IPTUNNEL_H
> +
> +enum {
> +       SEG6_IPTUNNEL_UNSPEC,
> +       SEG6_IPTUNNEL_SRH,
> +       __SEG6_IPTUNNEL_MAX,
> +};
> +#define SEG6_IPTUNNEL_MAX (__SEG6_IPTUNNEL_MAX - 1)
> +
> +struct seg6_iptunnel_encap {
> +       int flags;
> +       struct ipv6_sr_hdr srh[0];
> +};
> +
> +#define SEG6_IPTUN_ENCAP_SIZE(x) ((sizeof(*x)) + (((x)->srh->hdrlen + 1) << 3))
> +
> +#define SEG6_IPTUN_FLAG_ENCAP   0x1
> +
> +static inline size_t seg6_lwt_headroom(struct seg6_iptunnel_encap *tuninfo)
> +{
> +       int encap = !!(tuninfo->flags & SEG6_IPTUN_FLAG_ENCAP);
> +
> +       return ((tuninfo->srh->hdrlen + 1) << 3) +
> +              (encap * sizeof(struct ipv6hdr));
> +}
> +
> +#endif
> diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
> index 88fd642..03976e9 100644
> --- a/net/core/lwtunnel.c
> +++ b/net/core/lwtunnel.c
> @@ -39,6 +39,8 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
>                 return "MPLS";
>         case LWTUNNEL_ENCAP_ILA:
>                 return "ILA";
> +       case LWTUNNEL_ENCAP_SEG6:
> +               return "SEG6";
>         case LWTUNNEL_ENCAP_IP6:
>         case LWTUNNEL_ENCAP_IP:
>         case LWTUNNEL_ENCAP_NONE:
> diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
> index 29a77d3..4bd1e73 100644
> --- a/net/ipv6/Makefile
> +++ b/net/ipv6/Makefile
> @@ -45,7 +45,7 @@ obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
>  obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
>  obj-$(CONFIG_IPV6_FOU) += fou6.o
>
> -obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o seg6.o
> +obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o seg6.o seg6_iptunnel.o
>  obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
>
>  obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
> diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
> new file mode 100644
> index 0000000..caae8ab
> --- /dev/null
> +++ b/net/ipv6/seg6_iptunnel.c
> @@ -0,0 +1,370 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  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.
> + */
> +
> +#include <linux/types.h>
> +#include <linux/skbuff.h>
> +#include <linux/net.h>
> +#include <linux/module.h>
> +#include <net/ip.h>
> +#include <net/lwtunnel.h>
> +#include <net/netevent.h>
> +#include <net/netns/generic.h>
> +#include <net/ip6_fib.h>
> +#include <net/route.h>
> +#include <net/seg6.h>
> +#include <linux/seg6.h>
> +#include <linux/seg6_iptunnel.h>
> +#include <net/addrconf.h>
> +#include <net/ip6_route.h>
> +#include <net/dst_cache.h>
> +
> +struct seg6_lwt {
> +       struct dst_cache cache;
> +       struct seg6_iptunnel_encap tuninfo[0];
> +};
> +
> +static inline struct seg6_lwt *seg6_lwt_lwtunnel(struct lwtunnel_state *lwt)
> +{
> +       return (struct seg6_lwt *)lwt->data;
> +}
> +
> +static inline struct seg6_iptunnel_encap *
> +seg6_encap_lwtunnel(struct lwtunnel_state *lwt)
> +{
> +       return seg6_lwt_lwtunnel(lwt)->tuninfo;
> +}
> +
> +static const struct nla_policy seg6_iptunnel_policy[SEG6_IPTUNNEL_MAX + 1] = {
> +       [SEG6_IPTUNNEL_SRH]     = { .type = NLA_BINARY },
> +};
> +
> +int nla_put_srh(struct sk_buff *skb, int attrtype,
> +               struct seg6_iptunnel_encap *tuninfo)
> +{
> +       struct seg6_iptunnel_encap *data;
> +       struct nlattr *nla;
> +       int len;
> +
> +       len = SEG6_IPTUN_ENCAP_SIZE(tuninfo);
> +
> +       nla = nla_reserve(skb, attrtype, len);
> +       if (!nla)
> +               return -EMSGSIZE;
> +
> +       data = nla_data(nla);
> +       memcpy(data, tuninfo, len);
> +
> +       return 0;
> +}
> +
> +static void set_tun_src(struct net *net, struct net_device *dev,
> +                       struct in6_addr *daddr, struct in6_addr *saddr)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +       struct in6_addr *tun_src;
> +
> +       rcu_read_lock();
> +
> +       tun_src = rcu_dereference(sdata->tun_src);
> +
> +       if (!ipv6_addr_any(tun_src)) {
> +               memcpy(saddr, tun_src, sizeof(struct in6_addr));
> +       } else {
> +               ipv6_dev_get_saddr(net, dev, daddr, IPV6_PREFER_SRC_PUBLIC,
> +                                  saddr);
> +       }
> +
> +       rcu_read_unlock();
> +}
> +
> +/* encapsulate an IPv6 packet within an outer IPv6 header with a given SRH */
> +static int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
> +{
> +       struct net *net = dev_net(skb_dst(skb)->dev);
> +       struct ipv6hdr *hdr, *inner_hdr;
> +       struct ipv6_sr_hdr *isrh;
> +       int hdrlen, tot_len, err;
> +
> +       hdrlen = (osrh->hdrlen + 1) << 3;
> +       tot_len = hdrlen + sizeof(*hdr);
> +
> +       err = pskb_expand_head(skb, tot_len, 0, GFP_ATOMIC);
> +       if (unlikely(err))
> +               return err;
> +
> +       inner_hdr = ipv6_hdr(skb);
> +
> +       skb_push(skb, tot_len);
> +       skb_reset_network_header(skb);
> +       skb_mac_header_rebuild(skb);
> +       hdr = ipv6_hdr(skb);
> +
> +       /* inherit tc, flowlabel and hlim
> +        * hlim will be decremented in ip6_forward() afterwards and
> +        * decapsulation will overwrite inner hlim with outer hlim
> +        */
> +       ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr)),
> +                    ip6_flowlabel(inner_hdr));
> +       hdr->hop_limit = inner_hdr->hop_limit;
> +       hdr->nexthdr = NEXTHDR_ROUTING;
> +
> +       isrh = (void *)hdr + sizeof(*hdr);
> +       memcpy(isrh, osrh, hdrlen);
> +
> +       isrh->nexthdr = NEXTHDR_IPV6;
> +
> +       hdr->daddr = isrh->segments[isrh->first_segment];
> +       set_tun_src(net, skb->dev, &hdr->daddr, &hdr->saddr);
> +
> +       skb_postpush_rcsum(skb, hdr, tot_len);
> +
> +       return 0;
> +}
> +
> +/* insert an SRH within an IPv6 packet, just after the IPv6 header */
> +static int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
> +{
> +       struct ipv6hdr *hdr, *oldhdr;
> +       struct ipv6_sr_hdr *isrh;
> +       int hdrlen, err;
> +
> +       hdrlen = (osrh->hdrlen + 1) << 3;
> +
> +       err = pskb_expand_head(skb, hdrlen, 0, GFP_ATOMIC);
> +       if (unlikely(err))
> +               return err;
> +
> +       oldhdr = ipv6_hdr(skb);
> +
> +       skb_pull(skb, sizeof(struct ipv6hdr));
> +       skb_postpull_rcsum(skb, skb_network_header(skb),
> +                          sizeof(struct ipv6hdr));
> +
> +       skb_push(skb, sizeof(struct ipv6hdr) + hdrlen);
> +       skb_reset_network_header(skb);
> +       skb_mac_header_rebuild(skb);
> +
> +       hdr = ipv6_hdr(skb);
> +
> +       memmove(hdr, oldhdr, sizeof(*hdr));
> +
> +       isrh = (void *)hdr + sizeof(*hdr);
> +       memcpy(isrh, osrh, hdrlen);
> +
> +       isrh->nexthdr = hdr->nexthdr;
> +       hdr->nexthdr = NEXTHDR_ROUTING;
> +
> +       isrh->segments[0] = hdr->daddr;
> +       hdr->daddr = isrh->segments[isrh->first_segment];
> +
> +       skb_postpush_rcsum(skb, hdr, sizeof(struct ipv6hdr) + hdrlen);
> +
> +       return 0;
> +}
> +
> +static int seg6_do_srh(struct sk_buff *skb)
> +{
> +       struct dst_entry *dst = skb_dst(skb);
> +       struct seg6_iptunnel_encap *tinfo;
> +       int err = 0;
> +
> +       tinfo = seg6_encap_lwtunnel(dst->lwtstate);
> +
> +       if (likely(!skb->encapsulation)) {
> +               skb_reset_inner_headers(skb);
> +               skb->encapsulation = 1;
> +       }
> +
> +       if (tinfo->flags & SEG6_IPTUN_FLAG_ENCAP) {
> +               err = seg6_do_srh_encap(skb, tinfo->srh);
> +       } else {
> +               err = seg6_do_srh_inline(skb, tinfo->srh);
> +               skb_reset_inner_headers(skb);
> +       }
> +
> +       if (err)
> +               return err;
> +
> +       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
> +       skb_set_transport_header(skb, sizeof(struct ipv6hdr));
> +
> +       skb_set_inner_protocol(skb, skb->protocol);
> +
> +       return 0;
> +}
> +
> +int seg6_input(struct sk_buff *skb)
> +{
> +       int err;
> +
> +       err = seg6_do_srh(skb);
> +       if (unlikely(err)) {
> +               kfree_skb(skb);
> +               return err;
> +       }
> +
> +       skb_dst_drop(skb);
> +       ip6_route_input(skb);
> +
> +       return dst_input(skb);
> +}
> +
> +int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
> +{
> +       struct dst_entry *orig_dst = skb_dst(skb);
> +       struct seg6_lwt *slwt;
> +       struct dst_entry *dst;
> +       int err = -EINVAL;
> +
> +       err = seg6_do_srh(skb);
> +       if (unlikely(err))
> +               goto drop;
> +
> +       slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
> +
> +       dst = dst_cache_get(&slwt->cache);
> +       if (unlikely(!dst)) {
> +               struct ipv6hdr *hdr = ipv6_hdr(skb);
> +               struct flowi6 fl6;
> +
> +               fl6.daddr = hdr->daddr;
> +               fl6.saddr = hdr->saddr;
> +               fl6.flowlabel = ip6_flowinfo(hdr);
> +               fl6.flowi6_mark = skb->mark;
> +               fl6.flowi6_proto = hdr->nexthdr;
> +
> +               dst = ip6_route_output(net, NULL, &fl6);
> +               if (dst->error) {
> +                       err = dst->error;
> +                       dst_release(dst);
> +                       goto drop;
> +               }
> +
> +               dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr);
> +       }
> +
> +       skb_dst_drop(skb);
> +       skb_dst_set(skb, dst);
> +
> +       return dst_output(net, sk, skb);
> +drop:
> +       kfree_skb(skb);
> +       return err;
> +}
> +
> +static int seg6_build_state(struct net_device *dev, struct nlattr *nla,
> +                           unsigned int family, const void *cfg,
> +                           struct lwtunnel_state **ts)
> +{
> +       struct nlattr *tb[SEG6_IPTUNNEL_MAX + 1];
> +       struct seg6_iptunnel_encap *tuninfo;
> +       struct lwtunnel_state *newts;
> +       struct seg6_lwt *slwt;
> +       int tuninfo_len;
> +       int err;
> +
> +       err = nla_parse_nested(tb, SEG6_IPTUNNEL_MAX, nla,
> +                              seg6_iptunnel_policy);
> +
> +       if (err < 0)
> +               return err;
> +
> +       if (!tb[SEG6_IPTUNNEL_SRH])
> +               return -EINVAL;
> +
> +       tuninfo = nla_data(tb[SEG6_IPTUNNEL_SRH]);
> +       tuninfo_len = SEG6_IPTUN_ENCAP_SIZE(tuninfo);
> +
> +       newts = lwtunnel_state_alloc(tuninfo_len + sizeof(*slwt));
> +       if (!newts)
> +               return -ENOMEM;
> +
> +       slwt = seg6_lwt_lwtunnel(newts);
> +
> +       err = dst_cache_init(&slwt->cache, GFP_KERNEL);
> +       if (err) {
> +               kfree(newts);
> +               return err;
> +       }
> +
> +       memcpy(&slwt->tuninfo, tuninfo, tuninfo_len);
> +
> +       newts->type = LWTUNNEL_ENCAP_SEG6;
> +       newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT |
> +                       LWTUNNEL_STATE_INPUT_REDIRECT;
> +       newts->headroom = seg6_lwt_headroom(tuninfo);
> +
> +       *ts = newts;
> +
> +       return 0;
> +}
> +
> +static void seg6_destroy_state(struct lwtunnel_state *lwt)
> +{
> +       dst_cache_destroy(&seg6_lwt_lwtunnel(lwt)->cache);
> +}
> +
> +static int seg6_fill_encap_info(struct sk_buff *skb,
> +                               struct lwtunnel_state *lwtstate)
> +{
> +       struct seg6_iptunnel_encap *tuninfo = seg6_encap_lwtunnel(lwtstate);
> +
> +       if (nla_put_srh(skb, SEG6_IPTUNNEL_SRH, tuninfo))
> +               return -EMSGSIZE;
> +
> +       return 0;
> +}
> +
> +static int seg6_encap_nlsize(struct lwtunnel_state *lwtstate)
> +{
> +       struct seg6_iptunnel_encap *tuninfo = seg6_encap_lwtunnel(lwtstate);
> +
> +       return nla_total_size(SEG6_IPTUN_ENCAP_SIZE(tuninfo));
> +}
> +
> +static int seg6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
> +{
> +       struct seg6_iptunnel_encap *a_hdr = seg6_encap_lwtunnel(a);
> +       struct seg6_iptunnel_encap *b_hdr = seg6_encap_lwtunnel(b);
> +       int len = SEG6_IPTUN_ENCAP_SIZE(a_hdr);
> +
> +       if (len != SEG6_IPTUN_ENCAP_SIZE(b_hdr))
> +               return 1;
> +
> +       return memcmp(a_hdr, b_hdr, len);
> +}
> +
> +static const struct lwtunnel_encap_ops seg6_iptun_ops = {
> +       .build_state = seg6_build_state,
> +       .destroy_state = seg6_destroy_state,
> +       .output = seg6_output,
> +       .input = seg6_input,
> +       .fill_encap = seg6_fill_encap_info,
> +       .get_encap_size = seg6_encap_nlsize,
> +       .cmp_encap = seg6_encap_cmp,
> +};
> +
> +static int __init seg6_iptunnel_init(void)
> +{
> +       return lwtunnel_encap_add_ops(&seg6_iptun_ops, LWTUNNEL_ENCAP_SEG6);
> +}
> +module_init(seg6_iptunnel_init);
> +
> +static void __exit seg6_iptunnel_exit(void)
> +{
> +       lwtunnel_encap_del_ops(&seg6_iptun_ops, LWTUNNEL_ENCAP_SEG6);
> +}
> +module_exit(seg6_iptunnel_exit);
> +
> +MODULE_DESCRIPTION("Segment Routing with IPv6 IP Tunnels");
> +MODULE_LICENSE("GPL v2");
> --
> 2.7.3
>

Looks good.

Acked-by: Tom Herbert <tom@herbertland.com>

^ permalink raw reply

* Re: [PATCH v2 4/9] ipv6: sr: add core files for SR HMAC support
From: Tom Herbert @ 2016-10-28  3:05 UTC (permalink / raw)
  To: David Lebrun; +Cc: Linux Kernel Network Developers
In-Reply-To: <1477497292-22155-5-git-send-email-david.lebrun@uclouvain.be>

On Wed, Oct 26, 2016 at 8:54 AM, David Lebrun <david.lebrun@uclouvain.be> wrote:
> This patch adds the necessary functions to compute and check the HMAC signature
> of an SR-enabled packet. Two HMAC algorithms are supported: hmac(sha1) and
> hmac(sha256).
>
> In order to avoid dynamic memory allocation for each HMAC computation,
> a per-cpu ring buffer is allocated for this purpose.
>
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
> ---
>  include/linux/seg6_hmac.h      |   6 +
>  include/net/seg6_hmac.h        |  61 ++++++
>  include/uapi/linux/seg6_hmac.h |  20 ++
>  net/ipv6/Kconfig               |  12 ++
>  net/ipv6/seg6_hmac.c           | 432 +++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 531 insertions(+)
>  create mode 100644 include/linux/seg6_hmac.h
>  create mode 100644 include/net/seg6_hmac.h
>  create mode 100644 include/uapi/linux/seg6_hmac.h
>  create mode 100644 net/ipv6/seg6_hmac.c
>
> diff --git a/include/linux/seg6_hmac.h b/include/linux/seg6_hmac.h
> new file mode 100644
> index 0000000..da437eb
> --- /dev/null
> +++ b/include/linux/seg6_hmac.h
> @@ -0,0 +1,6 @@
> +#ifndef _LINUX_SEG6_HMAC_H
> +#define _LINUX_SEG6_HMAC_H
> +
> +#include <uapi/linux/seg6_hmac.h>
> +
> +#endif
> diff --git a/include/net/seg6_hmac.h b/include/net/seg6_hmac.h
> new file mode 100644
> index 0000000..6e5ee6a
> --- /dev/null
> +++ b/include/net/seg6_hmac.h
> @@ -0,0 +1,61 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  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.
> + */
> +
> +#ifndef _NET_SEG6_HMAC_H
> +#define _NET_SEG6_HMAC_H
> +
> +#include <net/flow.h>
> +#include <net/ip6_fib.h>
> +#include <net/sock.h>
> +#include <linux/ip.h>
> +#include <linux/ipv6.h>
> +#include <linux/route.h>
> +#include <net/seg6.h>
> +#include <linux/seg6_hmac.h>
> +
> +#define SEG6_HMAC_MAX_DIGESTSIZE       160
> +#define SEG6_HMAC_RING_SIZE            256
> +
> +struct seg6_hmac_info {
> +       struct list_head list;
> +
> +       u32 hmackeyid;
> +       char secret[SEG6_HMAC_SECRET_LEN];
> +       u8 slen;
> +       u8 alg_id;
> +};
> +
> +struct seg6_hmac_algo {
> +       u8 alg_id;
> +       char name[64];
> +       struct crypto_shash * __percpu *tfms;
> +       struct shash_desc * __percpu *shashs;
> +};
> +
> +extern int seg6_hmac_compute(struct seg6_hmac_info *hinfo,
> +                            struct ipv6_sr_hdr *hdr, struct in6_addr *saddr,
> +                            u8 *output);
> +extern struct seg6_hmac_info *seg6_hmac_info_lookup(struct net *net, u32 key);
> +extern int seg6_hmac_info_add(struct net *net, u32 key,
> +                             struct seg6_hmac_info *hinfo);
> +extern int seg6_hmac_info_del(struct net *net, u32 key,
> +                             struct seg6_hmac_info *hinfo);
> +extern int seg6_push_hmac(struct net *net, struct in6_addr *saddr,
> +                         struct ipv6_sr_hdr *srh);
> +extern bool seg6_hmac_validate_skb(struct sk_buff *skb);
> +extern int seg6_hmac_init(void);
> +extern void seg6_hmac_exit(void);
> +extern int seg6_hmac_net_init(struct net *net);
> +extern void seg6_hmac_net_exit(struct net *net);
> +
> +#endif
> diff --git a/include/uapi/linux/seg6_hmac.h b/include/uapi/linux/seg6_hmac.h
> new file mode 100644
> index 0000000..0b5eda7
> --- /dev/null
> +++ b/include/uapi/linux/seg6_hmac.h
> @@ -0,0 +1,20 @@
> +#ifndef _UAPI_LINUX_SEG6_HMAC_H
> +#define _UAPI_LINUX_SEG6_HMAC_H
> +
> +#define SEG6_HMAC_SECRET_LEN   64
> +#define SEG6_HMAC_FIELD_LEN    32
> +
> +struct sr6_tlv_hmac {
> +       __u8 type;
> +       __u8 len;
> +       __u16 reserved;
Maybe add a common definition for SR TLV.

> +       __be32 hmackeyid;
> +       __u8 hmac[SEG6_HMAC_FIELD_LEN];
> +} __attribute__((packed));
> +
> +enum {
> +       SEG6_HMAC_ALGO_SHA1 = 1,
> +       SEG6_HMAC_ALGO_SHA256 = 2,
> +};
> +
> +#endif
> diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
> index 2343e4f..c647712 100644
> --- a/net/ipv6/Kconfig
> +++ b/net/ipv6/Kconfig
> @@ -289,4 +289,16 @@ config IPV6_PIMSM_V2
>           Support for IPv6 PIM multicast routing protocol PIM-SMv2.
>           If unsure, say N.
>
> +config IPV6_SEG6_HMAC
> +       bool "IPv6: Segment Routing HMAC support"
> +       depends on IPV6
> +       select CRYPTO_HMAC
> +       select CRYPTO_SHA1
> +       select CRYPTO_SHA256
> +       ---help---
> +         Support for HMAC signature generation and verification
> +         of SR-enabled packets.
> +
> +         If unsure, say N.
> +
>  endif # IPV6
> diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
> new file mode 100644
> index 0000000..65ebc0c
> --- /dev/null
> +++ b/net/ipv6/seg6_hmac.c
> @@ -0,0 +1,432 @@
> +/*
> + *  SR-IPv6 implementation -- HMAC functions
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  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.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/socket.h>
> +#include <linux/sockios.h>
> +#include <linux/net.h>
> +#include <linux/netdevice.h>
> +#include <linux/in6.h>
> +#include <linux/icmpv6.h>
> +#include <linux/mroute6.h>
> +#include <linux/slab.h>
> +
> +#include <linux/netfilter.h>
> +#include <linux/netfilter_ipv6.h>
> +
> +#include <net/sock.h>
> +#include <net/snmp.h>
> +
> +#include <net/ipv6.h>
> +#include <net/protocol.h>
> +#include <net/transp_v6.h>
> +#include <net/rawv6.h>
> +#include <net/ndisc.h>
> +#include <net/ip6_route.h>
> +#include <net/addrconf.h>
> +#include <net/xfrm.h>
> +
> +#include <linux/cryptohash.h>
> +#include <crypto/hash.h>
> +#include <crypto/sha.h>
> +#include <net/seg6.h>
> +#include <net/genetlink.h>
> +#include <net/seg6_hmac.h>
> +#include <linux/random.h>
> +
> +static char * __percpu *hmac_ring;
> +
> +static struct seg6_hmac_algo hmac_algos[] = {
> +       {
> +               .alg_id = SEG6_HMAC_ALGO_SHA1,
> +               .name = "hmac(sha1)",
> +       },
> +       {
> +               .alg_id = SEG6_HMAC_ALGO_SHA256,
> +               .name = "hmac(sha256)",
> +       },
> +};
> +
> +static struct seg6_hmac_algo *__hmac_get_algo(u8 alg_id)
> +{
> +       struct seg6_hmac_algo *algo;
> +       int i, alg_count;
> +
> +       alg_count = sizeof(hmac_algos) / sizeof(struct seg6_hmac_algo);
> +       for (i = 0; i < alg_count; i++) {
> +               algo = &hmac_algos[i];
> +               if (algo->alg_id == alg_id)
> +                       return algo;
> +       }
> +
> +       return NULL;
> +}
> +
> +static int __do_hmac(struct seg6_hmac_info *hinfo, const char *text, u8 psize,
> +                    u8 *output, int outlen)
> +{
> +       struct seg6_hmac_algo *algo;
> +       struct crypto_shash *tfm;
> +       struct shash_desc *shash;
> +       int ret, dgsize;
> +
> +       algo = __hmac_get_algo(hinfo->alg_id);
> +       if (!algo)
> +               return -ENOENT;
> +
> +       tfm = *this_cpu_ptr(algo->tfms);
> +
> +       dgsize = crypto_shash_digestsize(tfm);
> +       if (dgsize > outlen) {
> +               pr_debug("sr-ipv6: __do_hmac: digest size too big (%d / %d)\n",
> +                        dgsize, outlen);
> +               return -ENOMEM;
> +       }
> +
> +       ret = crypto_shash_setkey(tfm, hinfo->secret, hinfo->slen);
> +       if (ret < 0) {
> +               pr_debug("sr-ipv6: crypto_shash_setkey failed: err %d\n", ret);
> +               goto failed;
> +       }
> +
> +       shash = *this_cpu_ptr(algo->shashs);
> +       shash->tfm = tfm;
> +
> +       ret = crypto_shash_digest(shash, text, psize, output);
> +       if (ret < 0) {
> +               pr_debug("sr-ipv6: crypto_shash_digest failed: err %d\n", ret);
> +               goto failed;
> +       }
> +
> +       return dgsize;
> +
> +failed:
> +       return ret;
> +}
> +
> +int seg6_hmac_compute(struct seg6_hmac_info *hinfo, struct ipv6_sr_hdr *hdr,
> +                     struct in6_addr *saddr, u8 *output)
> +{
> +       __be32 hmackeyid = cpu_to_be32(hinfo->hmackeyid);
> +       u8 tmp_out[SEG6_HMAC_MAX_DIGESTSIZE];
> +       int plen, i, dgsize, wrsize;
> +       char *ring, *off;
> +
> +       /* a 160-byte buffer for digest output allows to store highest known
> +        * hash function (RadioGatun) with up to 1216 bits
> +        */
> +
> +       /* saddr(16) + first_seg(1) + cleanup(1) + keyid(4) + seglist(16n) */
> +       plen = 16 + 1 + 1 + 4 + (hdr->first_segment + 1) * 16;
> +
> +       /* this limit allows for 14 segments */
> +       if (plen >= SEG6_HMAC_RING_SIZE)
> +               return -EMSGSIZE;
> +
> +       local_bh_disable();
> +       ring = *this_cpu_ptr(hmac_ring);
> +       off = ring;
> +       memcpy(off, saddr, 16);
> +       off += 16;
> +       *off++ = hdr->first_segment;
> +       *off++ = !!(sr_has_cleanup(hdr)) << 7;
> +       memcpy(off, &hmackeyid, 4);
> +       off += 4;
> +
It's not clear what is being done here. Comment might be nice.

> +       for (i = 0; i < hdr->first_segment + 1; i++) {
> +               memcpy(off, hdr->segments + i, 16);
> +               off += 16;
> +       }
> +
> +       dgsize = __do_hmac(hinfo, ring, plen, tmp_out,
> +                          SEG6_HMAC_MAX_DIGESTSIZE);
> +       local_bh_enable();
> +
> +       if (dgsize < 0)
> +               return dgsize;
> +
> +       wrsize = SEG6_HMAC_FIELD_LEN;
> +       if (wrsize > dgsize)
> +               wrsize = dgsize;
> +
> +       memset(output, 0, SEG6_HMAC_FIELD_LEN);
> +       memcpy(output, tmp_out, wrsize);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(seg6_hmac_compute);
> +
> +/* checks if an incoming SR-enabled packet's HMAC status matches
> + * the incoming policy.
> + *
> + * called with rcu_read_lock()
> + */
> +bool seg6_hmac_validate_skb(struct sk_buff *skb)
> +{
> +       u8 hmac_output[SEG6_HMAC_FIELD_LEN];
> +       struct net *net = dev_net(skb->dev);
> +       struct seg6_hmac_info *hinfo;
> +       struct sr6_tlv_hmac *tlv;
> +       struct ipv6_sr_hdr *srh;
> +       struct inet6_dev *idev;
> +
> +       idev = __in6_dev_get(skb->dev);
> +
> +       srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
> +
> +       tlv = seg6_get_tlv_hmac(srh);
> +
> +       /* mandatory check but no tlv */
> +       if (idev->cnf.seg6_require_hmac > 0 && !tlv)
> +               return false;
> +
> +       /* no check */
> +       if (idev->cnf.seg6_require_hmac < 0)
> +               return true;
> +
> +       /* check only if present */
> +       if (idev->cnf.seg6_require_hmac == 0 && !tlv)
> +               return true;
> +
> +       /* now, seg6_require_hmac >= 0 && tlv */
> +
> +       hinfo = seg6_hmac_info_lookup(net, be32_to_cpu(tlv->hmackeyid));
> +       if (!hinfo)
> +               return false;
> +
> +       if (seg6_hmac_compute(hinfo, srh, &ipv6_hdr(skb)->saddr, hmac_output))
> +               return false;
> +
> +       if (memcmp(hmac_output, tlv->hmac, SEG6_HMAC_FIELD_LEN) != 0)
> +               return false;
> +
> +       return true;
> +}
> +
> +/* called with rcu_read_lock() */
> +struct seg6_hmac_info *seg6_hmac_info_lookup(struct net *net, u32 key)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +       struct seg6_hmac_info *hinfo;
> +
Linked list? Is this something that should have a hash table.

> +       list_for_each_entry_rcu(hinfo, &sdata->hmac_infos, list) {
> +               if (hinfo->hmackeyid == key)
> +                       return hinfo;
> +       }
> +
> +       return NULL;
> +}
> +EXPORT_SYMBOL(seg6_hmac_info_lookup);
> +
> +int seg6_hmac_info_add(struct net *net, u32 key, struct seg6_hmac_info *hinfo)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +       struct seg6_hmac_info *old_hinfo;
> +
> +       old_hinfo = seg6_hmac_info_lookup(net, key);
> +       if (old_hinfo)
> +               return -EEXIST;
> +
> +       list_add_rcu(&hinfo->list, &sdata->hmac_infos);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(seg6_hmac_info_add);
> +
> +int seg6_hmac_info_del(struct net *net, u32 key, struct seg6_hmac_info *hinfo)
> +{
> +       struct seg6_hmac_info *tmp;
> +
> +       tmp = seg6_hmac_info_lookup(net, key);
> +       if (!tmp)
> +               return -ENOENT;
> +
> +       /* entry was replaced, ignore deletion */
> +       if (tmp != hinfo)
> +               return -ENOENT;
> +
> +       list_del_rcu(&hinfo->list);
> +       synchronize_net();
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(seg6_hmac_info_del);
> +
> +static void seg6_hmac_info_flush(struct net *net)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +       struct seg6_hmac_info *hinfo;
> +
> +       mutex_lock(&sdata->lock);
> +       while ((hinfo = list_first_or_null_rcu(&sdata->hmac_infos,
> +                                              struct seg6_hmac_info,
> +                                              list)) != NULL) {
> +               list_del_rcu(&hinfo->list);
> +               mutex_unlock(&sdata->lock);
> +               synchronize_net();
> +               kfree(hinfo);
> +               mutex_lock(&sdata->lock);
> +       }
> +
> +       mutex_unlock(&sdata->lock);
> +}
> +
> +int seg6_push_hmac(struct net *net, struct in6_addr *saddr,
> +                  struct ipv6_sr_hdr *srh)
> +{
> +       struct seg6_hmac_info *hinfo;
> +       struct sr6_tlv_hmac *tlv;
> +       int err = -ENOENT;
> +
> +       tlv = seg6_get_tlv_hmac(srh);
> +       if (!tlv)
> +               return -EINVAL;
> +
> +       rcu_read_lock();
> +
> +       hinfo = seg6_hmac_info_lookup(net, be32_to_cpu(tlv->hmackeyid));
> +       if (!hinfo)
> +               goto out;
> +
> +       memset(tlv->hmac, 0, SEG6_HMAC_FIELD_LEN);
> +       err = seg6_hmac_compute(hinfo, srh, saddr, tlv->hmac);
> +
> +out:
> +       rcu_read_unlock();
> +       return err;
> +}
> +EXPORT_SYMBOL(seg6_push_hmac);
> +
> +static int seg6_hmac_init_ring(void)
> +{
> +       int i;
> +
> +       hmac_ring = alloc_percpu(char *);
> +
> +       if (!hmac_ring)
> +               return -ENOMEM;
> +
> +       for_each_possible_cpu(i) {
> +               char *ring = kzalloc(SEG6_HMAC_RING_SIZE, GFP_KERNEL);
> +
> +               if (!ring)
> +                       return -ENOMEM;
> +
> +               *per_cpu_ptr(hmac_ring, i) = ring;
> +       }
> +
> +       return 0;
> +}
> +
> +static int seg6_hmac_init_algo(void)
> +{
> +       struct seg6_hmac_algo *algo;
> +       struct crypto_shash *tfm;
> +       struct shash_desc *shash;
> +       int i, alg_count, cpu;
> +
> +       alg_count = sizeof(hmac_algos) / sizeof(struct seg6_hmac_algo);
> +
> +       for (i = 0; i < alg_count; i++) {
> +               struct crypto_shash **p_tfm;
> +               int shsize;
> +
> +               algo = &hmac_algos[i];
> +               algo->tfms = alloc_percpu(struct crypto_shash *);
> +               if (!algo->tfms)
> +                       return -ENOMEM;
> +
> +               for_each_possible_cpu(cpu) {
> +                       tfm = crypto_alloc_shash(algo->name, 0, GFP_KERNEL);
> +                       if (IS_ERR(tfm))
> +                               return PTR_ERR(tfm);
> +                       p_tfm = per_cpu_ptr(algo->tfms, cpu);
> +                       *p_tfm = tfm;
> +               }
> +
> +               p_tfm = this_cpu_ptr(algo->tfms);
> +               tfm = *p_tfm;
> +
> +               shsize = sizeof(*shash) + crypto_shash_descsize(tfm);
> +
> +               algo->shashs = alloc_percpu(struct shash_desc *);
> +               if (!algo->shashs)
> +                       return -ENOMEM;
> +
> +               for_each_possible_cpu(cpu) {
> +                       shash = kzalloc(shsize, GFP_KERNEL);
> +                       if (!shash)
> +                               return -ENOMEM;
> +                       *per_cpu_ptr(algo->shashs, cpu) = shash;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +int __init seg6_hmac_init(void)
> +{
> +       int ret;
> +
> +       ret = seg6_hmac_init_ring();
> +       if (ret < 0)
> +               goto out;
> +
> +       ret = seg6_hmac_init_algo();
> +
> +out:
> +       return ret;
> +}
> +
> +int __net_init seg6_hmac_net_init(struct net *net)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +
> +       INIT_LIST_HEAD(&sdata->hmac_infos);
> +       return 0;
> +}
> +
> +void __exit seg6_hmac_exit(void)
> +{
> +       struct seg6_hmac_algo *algo = NULL;
> +       int i, alg_count, cpu;
> +
> +       for_each_possible_cpu(i) {
> +               char *ring = *per_cpu_ptr(hmac_ring, i);
> +
> +               kfree(ring);
> +       }
> +       free_percpu(hmac_ring);
> +
> +       alg_count = sizeof(hmac_algos) / sizeof(struct seg6_hmac_algo);
> +       for (i = 0; i < alg_count; i++) {
> +               algo = &hmac_algos[i];
> +               for_each_possible_cpu(cpu) {
> +                       struct crypto_shash *tfm;
> +                       struct shash_desc *shash;
> +
> +                       shash = *per_cpu_ptr(algo->shashs, cpu);
> +                       kfree(shash);
> +                       tfm = *per_cpu_ptr(algo->tfms, cpu);
> +                       crypto_free_shash(tfm);
> +               }
> +               free_percpu(algo->tfms);
> +               free_percpu(algo->shashs);
> +       }
> +}
> +
> +void __net_exit seg6_hmac_net_exit(struct net *net)
> +{
> +       seg6_hmac_info_flush(net);
> +}

This is pretty complex stuff. It would be great to generalize this
somehow in a library (maybe a future task). I am updating GUE to use
the same algorithm for HMAC so would be nice to share.

> --
> 2.7.3
>

^ permalink raw reply

* Re: [PATCH v2 1/5] kconfig: introduce the "imply" keyword
From: Nicolas Pitre @ 2016-10-28  3:10 UTC (permalink / raw)
  To: Paul Bolle
  Cc: John Stultz, Richard Cochran, Michal Marek, Thomas Gleixner,
	Josh Triplett, Edward Cree, netdev, linux-kbuild, linux-kernel
In-Reply-To: <1477613871.2121.92.camel@tiscali.nl>

[-- Attachment #1: Type: text/plain, Size: 4925 bytes --]

On Fri, 28 Oct 2016, Paul Bolle wrote:

> On Tue, 2016-10-25 at 22:28 -0400, Nicolas Pitre wrote:
> > The "imply" keyword is a weak version of "select" where the target
> > config symbol can still be turned off, avoiding those pitfalls that come
> > with the "select" keyword.
> > 
> > This is useful e.g. with multiple drivers that want to indicate their
> > ability to hook into a given subsystem
> 
> "hook into a [...] subsystem" is rather vague.

You could say: benefit from, contribute to, register with, or any 
combination of those. At some point there is no good way to remain 
generic. At least none came to my mind.

> >  while still being able to configure that subsystem out
> 
> s/being able to/allowing the user to/, correct? 

Correct.

> > and keep those drivers selected.
> 
> Perhaps replace that with: "without also having to unset these
> drivers"?

Sure. I currently have:

  This is useful e.g. with multiple drivers that want to indicate their
  ability to hook into an important secondary subsystem while allowing
  the user to configure that subsystem out without also having to unset
  these drivers.

> > +- weak reverse dependencies: "imply" <symbol> ["if" <expr>]
> 
> You probably got "["if" <expr>]" for free by copying what's there for
> select. But this series doesn't use it, so perhaps it would be better
> to not document it yet. But that is rather sneaky. Dunno.

If it is not documented then the chance that someone uses it are slim. 
And since it comes "for free" I don't see the point of making the tool 
less flexible. And not having this flexibility could make some 
transitions from "select" to "imply" needlessly difficult.

> > +  This is similar to "select" as it enforces a lower limit on another
> > +  symbol except that the "implied" config symbol's value may still be
> > +  set to n from a direct dependency or with a visible prompt.
> 
> This is seriously hard to parse. But it's late here, so it might just
> be me.

I tried to follow the existing style. I removed the word "config" from 
that paragraph as it looked redundant. Other than that, any improvements 
from someone more inspired than myself is welcome.

> > +  Given the following example:
> > +
> > +  config FOO
> > +	tristate
> > +	imply BAZ
> > +
> > +  config BAZ
> > +	tristate
> > +	depends on BAR
> > +
> > +  The following values are possible:
> > +
> > +	FOO		BAR		BAZ's default	choice for BAZ
> > +	---		---		-------------	--------------
> > +	n		y		n		N/m/y
> > +	m		y		m		M/y/n
> > +	y		y		y		Y/n
> 
> Also
> 	n		n		*		N
> 	m		n		*		N
> 
> Is that right?

Right.  Is it clearer if I list all combinations, or maybe:

	*		n		*		N

> > +	y		n		*		N
> 
> But what does '*' mean?

It's a wildcard meaning either of n, m, or y.

> What happens when a tristate symbol is implied by a symbol set to 'y'
> and by a symbol set to 'm'?

That's respectively the third and second rows in the table above.

> And in your example BAR is bool, right? Does the above get more
> complicated if BAR would be tristate?

If BAR=m then implying BAZ from FOO=y will force BAZ to y or n, 
bypassing the restriction provided by BAR like "select" does.  This is 
somewhat questionable for "select" to do that, and the code emits a 
warning when "select" bypasses a direct dependency set to n, but not 
when set to m. For now "imply" simply tries to be consistent with 
the "select" behavior.

> How does setting a direct default for BAZ interfere with the implied
> values?

It doesn't. An implied symbol may be promoted to a higher value than the 
default, not a lower value. So if the direct default is higher than the 
implied value then the default wins.

> >    b) Match dependency semantics:
> >  	b1) Swap all "select FOO" to "depends on FOO" or,
> >  	b2) Swap all "depends on FOO" to "select FOO"
> > +  c) Consider the use of "imply" instead of "select"
> 
> If memory serves me right this text was added after a long discussion
> with Luis Rodriguez. Luis might want to have a look at any 

The "imply" statement doesn't create the kind of dependency conflicts as 
"select" does. So I think it is worth mentioning as a possibility here.

> Haven't looked at the code yet, sorry. I'm still trying to see whether
> I can wrap my mind around this. It looks like just setting a default on
> another symbol, but there could be a twist I missed.

Setting a default was the purpose of my "suggest" patch. The "imply" 
statement still imposes a restriction similar to "select" where the 
implied symbol cannot be m if implied with y.

Some people didn't like the fact that you could turn a driver from m to
y and silently lose some features if they were provided by a subsystem
that also used to be m, which arguably is not the same as being
explicitly disabled.  With "select" this is not a problem as the target
symbol is also promoted to y in that case, so I wanted to preserve that
property with "imply".


Nicolas

^ permalink raw reply

* [v13, 0/8] Fix eSDHC host version register bug
From: Yangbo Lu @ 2016-10-28  3:32 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A, Scott Wood, Arnd Bergmann
  Cc: Mark Rutland, Greg Kroah-Hartman, Xiaobo Xie, Minghuan Lian,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, Qiang Zhao, Russell King,
	Bhupesh Sharma, Jochen Friedrich, Claudiu Manoil,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Yangbo Lu, Rob Herring,
	Santosh Shilimkar,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Leo Li,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Kumar Gala,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ

This patchset is used to fix a host version register bug in the T4240-R1.0-R2.0
eSDHC controller. To match the SoC version and revision, 10 previous version
patchsets had tried many methods but all of them were rejected by reviewers.
Such as
	- dts compatible method
	- syscon method
	- ifdef PPC method
	- GUTS driver getting SVR method
Anrd suggested a soc_device_match method in v10, and this is the only available
method left now. This v11 patchset introduces the soc_device_match interface in
soc driver.

The first six patches of Yangbo are to add the GUTS driver. This is used to
register a soc device which contain soc version and revision information.
The other two patches introduce the soc_device_match method in soc driver
and apply it on esdhc driver to fix this bug.

Arnd Bergmann (1):
  base: soc: introduce soc_device_match() interface

Yangbo Lu (7):
  dt: bindings: update Freescale DCFG compatible
  ARM64: dts: ls2080a: add device configuration node
  dt: bindings: move guts devicetree doc out of powerpc directory
  powerpc/fsl: move mpc85xx.h to include/linux/fsl
  soc: fsl: add GUTS driver for QorIQ platforms
  MAINTAINERS: add entry for Freescale SoC drivers
  mmc: sdhci-of-esdhc: fix host version for T4240-R1.0-R2.0

 Documentation/devicetree/bindings/arm/fsl.txt      |   6 +-
 .../bindings/{powerpc => soc}/fsl/guts.txt         |   3 +
 MAINTAINERS                                        |  11 +-
 arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi     |   6 +
 arch/powerpc/kernel/cpu_setup_fsl_booke.S          |   2 +-
 arch/powerpc/sysdev/fsl_pci.c                      |   2 +-
 drivers/base/Kconfig                               |   1 +
 drivers/base/soc.c                                 |  66 ++++++
 drivers/clk/clk-qoriq.c                            |   3 +-
 drivers/i2c/busses/i2c-mpc.c                       |   2 +-
 drivers/iommu/fsl_pamu.c                           |   3 +-
 drivers/mmc/host/Kconfig                           |   1 +
 drivers/mmc/host/sdhci-of-esdhc.c                  |  20 ++
 drivers/net/ethernet/freescale/gianfar.c           |   2 +-
 drivers/soc/Kconfig                                |   3 +-
 drivers/soc/fsl/Kconfig                            |  18 ++
 drivers/soc/fsl/Makefile                           |   1 +
 drivers/soc/fsl/guts.c                             | 236 +++++++++++++++++++++
 include/linux/fsl/guts.h                           | 125 ++++++-----
 .../asm/mpc85xx.h => include/linux/fsl/svr.h       |   4 +-
 include/linux/sys_soc.h                            |   3 +
 21 files changed, 456 insertions(+), 62 deletions(-)
 rename Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt (91%)
 create mode 100644 drivers/soc/fsl/Kconfig
 create mode 100644 drivers/soc/fsl/guts.c
 rename arch/powerpc/include/asm/mpc85xx.h => include/linux/fsl/svr.h (97%)

-- 
2.1.0.27.g96db324

^ permalink raw reply

* [v13, 1/8] dt: bindings: update Freescale DCFG compatible
From: Yangbo Lu @ 2016-10-28  3:32 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A, Scott Wood, Arnd Bergmann
  Cc: Mark Rutland, Greg Kroah-Hartman, Xiaobo Xie, Minghuan Lian,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, Qiang Zhao, Russell King,
	Bhupesh Sharma, Jochen Friedrich, Claudiu Manoil,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Yangbo Lu, Rob Herring,
	Santosh Shilimkar,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Leo Li,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Kumar Gala,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
In-Reply-To: <1477625554-46700-1-git-send-email-yangbo.lu-3arQi8VN3Tc@public.gmane.org>

Update Freescale DCFG compatible with 'fsl,<chip>-dcfg' instead
of 'fsl,ls1021a-dcfg' to include more chips such as ls1021a,
ls1043a, and ls2080a.

Signed-off-by: Yangbo Lu <yangbo.lu-3arQi8VN3Tc@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Scott Wood <oss-fOR+EgIDQEHk1uMJSBkQmQ@public.gmane.org>
---
Changes for v8:
	- Added this patch
Changes for v9:
	- Added a list for the possible compatibles
Changes for v10:
	- None
Changes for v11:
	- Added 'Acked-by: Rob Herring'
	- Updated commit message by Scott
Changes for v12:
	- None
Changes for v13:
	- None
---
 Documentation/devicetree/bindings/arm/fsl.txt | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index dbbc095..713c1ae 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -119,7 +119,11 @@ Freescale DCFG
 configuration and status for the device. Such as setting the secondary
 core start address and release the secondary core from holdoff and startup.
   Required properties:
-  - compatible: should be "fsl,ls1021a-dcfg"
+  - compatible: should be "fsl,<chip>-dcfg"
+    Possible compatibles:
+	"fsl,ls1021a-dcfg"
+	"fsl,ls1043a-dcfg"
+	"fsl,ls2080a-dcfg"
   - reg : should contain base address and length of DCFG memory-mapped registers
 
 Example:
-- 
2.1.0.27.g96db324

^ permalink raw reply related

* [v13, 2/8] ARM64: dts: ls2080a: add device configuration node
From: Yangbo Lu @ 2016-10-28  3:32 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A, Scott Wood, Arnd Bergmann
  Cc: Mark Rutland, Greg Kroah-Hartman, Xiaobo Xie, Minghuan Lian,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, Qiang Zhao, Russell King,
	Bhupesh Sharma, Jochen Friedrich, Claudiu Manoil,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Yangbo Lu, Rob Herring,
	Santosh Shilimkar,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Leo Li,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Kumar Gala,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
In-Reply-To: <1477625554-46700-1-git-send-email-yangbo.lu-3arQi8VN3Tc@public.gmane.org>

Add the dts node for device configuration unit that provides
general purpose configuration and status for the device.

Signed-off-by: Yangbo Lu <yangbo.lu-3arQi8VN3Tc@public.gmane.org>
Acked-by: Scott Wood <oss-fOR+EgIDQEHk1uMJSBkQmQ@public.gmane.org>
---
Changes for v5:
	- Added this patch
Changes for v6:
	- None
Changes for v7:
	- None
Changes for v8:
	- Added 'Acked-by: Scott Wood'
Changes for v9:
	- None
Changes for v10:
	- None
Changes for v11:
	- None
Changes for v12:
	- None
Changes for v13:
	- None
---
 arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
index 337da90..c03b099 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
@@ -215,6 +215,12 @@
 			clocks = <&sysclk>;
 		};
 
+		dcfg: dcfg@1e00000 {
+			compatible = "fsl,ls2080a-dcfg", "syscon";
+			reg = <0x0 0x1e00000 0x0 0x10000>;
+			little-endian;
+		};
+
 		serial0: serial@21c0500 {
 			compatible = "fsl,ns16550", "ns16550a";
 			reg = <0x0 0x21c0500 0x0 0x100>;
-- 
2.1.0.27.g96db324

^ permalink raw reply related

* [v13, 3/8] dt: bindings: move guts devicetree doc out of powerpc directory
From: Yangbo Lu @ 2016-10-28  3:32 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A, Scott Wood, Arnd Bergmann
  Cc: Mark Rutland, Greg Kroah-Hartman, Xiaobo Xie, Minghuan Lian,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, Qiang Zhao, Russell King,
	Bhupesh Sharma, Jochen Friedrich, Claudiu Manoil,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Yangbo Lu, Rob Herring,
	Santosh Shilimkar,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Leo Li,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Kumar Gala,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
In-Reply-To: <1477625554-46700-1-git-send-email-yangbo.lu-3arQi8VN3Tc@public.gmane.org>

Move guts devicetree doc to Documentation/devicetree/bindings/soc/fsl/
since it's used by not only PowerPC but also ARM. And add a specification
for 'little-endian' property.

Signed-off-by: Yangbo Lu <yangbo.lu-3arQi8VN3Tc@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Scott Wood <oss-fOR+EgIDQEHk1uMJSBkQmQ@public.gmane.org>
---
Changes for v4:
	- Added this patch
Changes for v5:
	- Modified the description for little-endian property
Changes for v6:
	- None
Changes for v7:
	- None
Changes for v8:
	- Added 'Acked-by: Scott Wood'
	- Added 'Acked-by: Rob Herring'
Changes for v9:
	- None
Changes for v10:
	- None
Changes for v11:
	- None
Changes for v12:
	- None
Changes for v13:
	- None
---
 Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt | 3 +++
 1 file changed, 3 insertions(+)
 rename Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt (91%)

diff --git a/Documentation/devicetree/bindings/powerpc/fsl/guts.txt b/Documentation/devicetree/bindings/soc/fsl/guts.txt
similarity index 91%
rename from Documentation/devicetree/bindings/powerpc/fsl/guts.txt
rename to Documentation/devicetree/bindings/soc/fsl/guts.txt
index b71b203..07adca9 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/guts.txt
+++ b/Documentation/devicetree/bindings/soc/fsl/guts.txt
@@ -25,6 +25,9 @@ Recommended properties:
  - fsl,liodn-bits : Indicates the number of defined bits in the LIODN
    registers, for those SOCs that have a PAMU device.
 
+ - little-endian : Indicates that the global utilities block is little
+   endian. The default is big endian.
+
 Examples:
 	global-utilities@e0000 {	/* global utilities block */
 		compatible = "fsl,mpc8548-guts";
-- 
2.1.0.27.g96db324

^ permalink raw reply related

* [v13, 4/8] powerpc/fsl: move mpc85xx.h to include/linux/fsl
From: Yangbo Lu @ 2016-10-28  3:32 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A, Scott Wood, Arnd Bergmann
  Cc: Mark Rutland, Greg Kroah-Hartman, Xiaobo Xie, Minghuan Lian,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, Qiang Zhao, Russell King,
	Bhupesh Sharma, Jochen Friedrich, Claudiu Manoil,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Yangbo Lu, Rob Herring,
	Santosh Shilimkar,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Leo Li,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Kumar Gala,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
In-Reply-To: <1477625554-46700-1-git-send-email-yangbo.lu-3arQi8VN3Tc@public.gmane.org>

Move mpc85xx.h to include/linux/fsl and rename it to svr.h as a common
header file.  This SVR numberspace is used on some ARM chips as well as
PPC, and even to check for a PPC SVR multi-arch drivers would otherwise
need to ifdef the header inclusion and all references to the SVR symbols.

Signed-off-by: Yangbo Lu <yangbo.lu-3arQi8VN3Tc@public.gmane.org>
Acked-by: Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>
Acked-by: Stephen Boyd <sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Acked-by: Joerg Roedel <jroedel-l3A5Bk7waGM@public.gmane.org>
[scottwood: update description]
Signed-off-by: Scott Wood <oss-fOR+EgIDQEHk1uMJSBkQmQ@public.gmane.org>
---
Changes for v2:
	- None
Changes for v3:
	- None
Changes for v4:
	- None
Changes for v5:
	- Changed to Move mpc85xx.h to include/linux/fsl/
	- Adjusted '#include <linux/fsl/svr.h>' position in file
Changes for v6:
	- None
Changes for v7:
	- Added 'Acked-by: Wolfram Sang' for I2C part
	- Also applied to arch/powerpc/kernel/cpu_setup_fsl_booke.S
Changes for v8:
	- Added 'Acked-by: Stephen Boyd' for clk part
	- Added 'Acked-by: Scott Wood'
	- Added 'Acked-by: Joerg Roedel' for iommu part
Changes for v9:
	- None
Changes for v10:
	- None
Changes for v11:
	- Updated description by Scott
Changes for v12:
	- None
Changes for v13:
	- None
---
 arch/powerpc/kernel/cpu_setup_fsl_booke.S                     | 2 +-
 arch/powerpc/sysdev/fsl_pci.c                                 | 2 +-
 drivers/clk/clk-qoriq.c                                       | 3 +--
 drivers/i2c/busses/i2c-mpc.c                                  | 2 +-
 drivers/iommu/fsl_pamu.c                                      | 3 +--
 drivers/net/ethernet/freescale/gianfar.c                      | 2 +-
 arch/powerpc/include/asm/mpc85xx.h => include/linux/fsl/svr.h | 4 ++--
 7 files changed, 8 insertions(+), 10 deletions(-)
 rename arch/powerpc/include/asm/mpc85xx.h => include/linux/fsl/svr.h (97%)

diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index 462aed9..2b0284e 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -13,13 +13,13 @@
  *
  */
 
+#include <linux/fsl/svr.h>
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/ppc_asm.h>
 #include <asm/mmu-book3e.h>
 #include <asm/asm-offsets.h>
-#include <asm/mpc85xx.h>
 
 _GLOBAL(__e500_icache_setup)
 	mfspr	r0, SPRN_L1CSR1
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index d3a5974..cb0efea 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/fsl/edac.h>
+#include <linux/fsl/svr.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/memblock.h>
@@ -37,7 +38,6 @@
 #include <asm/pci-bridge.h>
 #include <asm/ppc-pci.h>
 #include <asm/machdep.h>
-#include <asm/mpc85xx.h>
 #include <asm/disassemble.h>
 #include <asm/ppc-opcode.h>
 #include <sysdev/fsl_soc.h>
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
index 20b1055..dc778e8 100644
--- a/drivers/clk/clk-qoriq.c
+++ b/drivers/clk/clk-qoriq.c
@@ -13,6 +13,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/fsl/guts.h>
+#include <linux/fsl/svr.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -1153,8 +1154,6 @@ static struct clk *clockgen_clk_get(struct of_phandle_args *clkspec, void *data)
 }
 
 #ifdef CONFIG_PPC
-#include <asm/mpc85xx.h>
-
 static const u32 a4510_svrs[] __initconst = {
 	(SVR_P2040 << 8) | 0x10,	/* P2040 1.0 */
 	(SVR_P2040 << 8) | 0x11,	/* P2040 1.1 */
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 565a49a..e791c51 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -27,9 +27,9 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/fsl/svr.h>
 
 #include <asm/mpc52xx.h>
-#include <asm/mpc85xx.h>
 #include <sysdev/fsl_soc.h>
 
 #define DRV_NAME "mpc-i2c"
diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
index a34355f..af8fb27 100644
--- a/drivers/iommu/fsl_pamu.c
+++ b/drivers/iommu/fsl_pamu.c
@@ -21,11 +21,10 @@
 #include "fsl_pamu.h"
 
 #include <linux/fsl/guts.h>
+#include <linux/fsl/svr.h>
 #include <linux/interrupt.h>
 #include <linux/genalloc.h>
 
-#include <asm/mpc85xx.h>
-
 /* define indexes for each operation mapping scenario */
 #define OMI_QMAN        0x00
 #define OMI_FMAN        0x01
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 4b4f5bc..55be5ce 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -86,11 +86,11 @@
 #include <linux/udp.h>
 #include <linux/in.h>
 #include <linux/net_tstamp.h>
+#include <linux/fsl/svr.h>
 
 #include <asm/io.h>
 #ifdef CONFIG_PPC
 #include <asm/reg.h>
-#include <asm/mpc85xx.h>
 #endif
 #include <asm/irq.h>
 #include <asm/uaccess.h>
diff --git a/arch/powerpc/include/asm/mpc85xx.h b/include/linux/fsl/svr.h
similarity index 97%
rename from arch/powerpc/include/asm/mpc85xx.h
rename to include/linux/fsl/svr.h
index 213f3a8..8d13836 100644
--- a/arch/powerpc/include/asm/mpc85xx.h
+++ b/include/linux/fsl/svr.h
@@ -9,8 +9,8 @@
  * (at your option) any later version.
  */
 
-#ifndef __ASM_PPC_MPC85XX_H
-#define __ASM_PPC_MPC85XX_H
+#ifndef FSL_SVR_H
+#define FSL_SVR_H
 
 #define SVR_REV(svr)	((svr) & 0xFF)		/* SOC design resision */
 #define SVR_MAJ(svr)	(((svr) >>  4) & 0xF)	/* Major revision field*/
-- 
2.1.0.27.g96db324

^ permalink raw reply related

* [v13, 5/8] soc: fsl: add GUTS driver for QorIQ platforms
From: Yangbo Lu @ 2016-10-28  3:32 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A, Scott Wood, Arnd Bergmann
  Cc: Mark Rutland, Greg Kroah-Hartman, Xiaobo Xie, Minghuan Lian,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, Qiang Zhao, Russell King,
	Bhupesh Sharma, Jochen Friedrich, Claudiu Manoil,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Yangbo Lu, Rob Herring,
	Santosh Shilimkar,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Leo Li,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Kumar Gala,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
In-Reply-To: <1477625554-46700-1-git-send-email-yangbo.lu-3arQi8VN3Tc@public.gmane.org>

The global utilities block controls power management, I/O device
enabling, power-onreset(POR) configuration monitoring, alternate
function selection for multiplexed signals,and clock control.

This patch adds a driver to manage and access global utilities block.
Initially only reading SVR and registering soc device are supported.
Other guts accesses, such as reading RCW, should eventually be moved
into this driver as well.

Signed-off-by: Yangbo Lu <yangbo.lu-3arQi8VN3Tc@public.gmane.org>
---
Changes for v4:
	- Added this patch
Changes for v5:
	- Modified copyright info
	- Changed MODULE_LICENSE to GPL
	- Changed EXPORT_SYMBOL_GPL to EXPORT_SYMBOL
	- Made FSL_GUTS user-invisible
	- Added a complete compatible list for GUTS
	- Stored guts info in file-scope variable
	- Added mfspr() getting SVR
	- Redefined GUTS APIs
	- Called fsl_guts_init rather than using platform driver
	- Removed useless parentheses
	- Removed useless 'extern' key words
Changes for v6:
	- Made guts thread safe in fsl_guts_init
Changes for v7:
	- Removed 'ifdef' for function declaration in guts.h
Changes for v8:
	- Fixes lines longer than 80 characters checkpatch issue
	- Added 'Acked-by: Scott Wood'
Changes for v9:
	- None
Changes for v10:
	- None
Changes for v11:
	- Changed to platform driver
Changes for v12:
	- Removed "signed-off-by: Scott"
	- Defined fsl_soc_die_attr struct array instead of
	  soc_device_attribute
	- Re-designed soc_device_attribute for QorIQ SoC
	- Other minor fixes
Changes for v13:
	- Rebased
	- Removed text after 'bool' in Kconfig
	- Removed ARCH ifdefs
	- Added more bits for ls1021a mask
	- Used devm
---
 drivers/soc/Kconfig      |   3 +-
 drivers/soc/fsl/Kconfig  |  18 ++++
 drivers/soc/fsl/Makefile |   1 +
 drivers/soc/fsl/guts.c   | 236 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fsl/guts.h | 125 +++++++++++++++----------
 5 files changed, 333 insertions(+), 50 deletions(-)
 create mode 100644 drivers/soc/fsl/Kconfig
 create mode 100644 drivers/soc/fsl/guts.c

diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index e6e90e8..f31bceb 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -1,8 +1,7 @@
 menu "SOC (System On Chip) specific Drivers"
 
 source "drivers/soc/bcm/Kconfig"
-source "drivers/soc/fsl/qbman/Kconfig"
-source "drivers/soc/fsl/qe/Kconfig"
+source "drivers/soc/fsl/Kconfig"
 source "drivers/soc/mediatek/Kconfig"
 source "drivers/soc/qcom/Kconfig"
 source "drivers/soc/rockchip/Kconfig"
diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig
new file mode 100644
index 0000000..7a9fb9b
--- /dev/null
+++ b/drivers/soc/fsl/Kconfig
@@ -0,0 +1,18 @@
+#
+# Freescale SOC drivers
+#
+
+source "drivers/soc/fsl/qbman/Kconfig"
+source "drivers/soc/fsl/qe/Kconfig"
+
+config FSL_GUTS
+	bool
+	select SOC_BUS
+	help
+	  The global utilities block controls power management, I/O device
+	  enabling, power-onreset(POR) configuration monitoring, alternate
+	  function selection for multiplexed signals,and clock control.
+	  This driver is to manage and access global utilities block.
+	  Initially only reading SVR and registering soc device are supported.
+	  Other guts accesses, such as reading RCW, should eventually be moved
+	  into this driver as well.
diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile
index 75e1f53..44b3beb 100644
--- a/drivers/soc/fsl/Makefile
+++ b/drivers/soc/fsl/Makefile
@@ -5,3 +5,4 @@
 obj-$(CONFIG_FSL_DPAA)                 += qbman/
 obj-$(CONFIG_QUICC_ENGINE)		+= qe/
 obj-$(CONFIG_CPM)			+= qe/
+obj-$(CONFIG_FSL_GUTS)			+= guts.o
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
new file mode 100644
index 0000000..1f356ed
--- /dev/null
+++ b/drivers/soc/fsl/guts.c
@@ -0,0 +1,236 @@
+/*
+ * Freescale QorIQ Platforms GUTS Driver
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_fdt.h>
+#include <linux/sys_soc.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/fsl/guts.h>
+#include <linux/fsl/svr.h>
+
+struct guts {
+	struct ccsr_guts __iomem *regs;
+	bool little_endian;
+};
+
+struct fsl_soc_die_attr {
+	char	*die;
+	u32	svr;
+	u32	mask;
+};
+
+static struct guts *guts;
+static struct soc_device_attribute soc_dev_attr;
+static struct soc_device *soc_dev;
+
+
+/* SoC die attribute definition for QorIQ platform */
+static const struct fsl_soc_die_attr fsl_soc_die[] = {
+	/*
+	 * Power Architecture-based SoCs T Series
+	 */
+
+	/* Die: T4240, SoC: T4240/T4160/T4080 */
+	{ .die		= "T4240",
+	  .svr		= 0x82400000,
+	  .mask		= 0xfff00000,
+	},
+	/* Die: T1040, SoC: T1040/T1020/T1042/T1022 */
+	{ .die		= "T1040",
+	  .svr		= 0x85200000,
+	  .mask		= 0xfff00000,
+	},
+	/* Die: T2080, SoC: T2080/T2081 */
+	{ .die		= "T2080",
+	  .svr		= 0x85300000,
+	  .mask		= 0xfff00000,
+	},
+	/* Die: T1024, SoC: T1024/T1014/T1023/T1013 */
+	{ .die		= "T1024",
+	  .svr		= 0x85400000,
+	  .mask		= 0xfff00000,
+	},
+
+	/*
+	 * ARM-based SoCs LS Series
+	 */
+
+	/* Die: LS1043A, SoC: LS1043A/LS1023A */
+	{ .die		= "LS1043A",
+	  .svr		= 0x87920000,
+	  .mask		= 0xffff0000,
+	},
+	/* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */
+	{ .die		= "LS2080A",
+	  .svr		= 0x87010000,
+	  .mask		= 0xff3f0000,
+	},
+	/* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */
+	{ .die		= "LS1088A",
+	  .svr		= 0x87030000,
+	  .mask		= 0xff3f0000,
+	},
+	/* Die: LS1012A, SoC: LS1012A */
+	{ .die		= "LS1012A",
+	  .svr		= 0x87040000,
+	  .mask		= 0xffff0000,
+	},
+	/* Die: LS1046A, SoC: LS1046A/LS1026A */
+	{ .die		= "LS1046A",
+	  .svr		= 0x87070000,
+	  .mask		= 0xffff0000,
+	},
+	/* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */
+	{ .die		= "LS2088A",
+	  .svr		= 0x87090000,
+	  .mask		= 0xff3f0000,
+	},
+	/* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */
+	{ .die		= "LS1021A",
+	  .svr		= 0x87000000,
+	  .mask		= 0xfff70000,
+	},
+	{ },
+};
+
+static const struct fsl_soc_die_attr *fsl_soc_die_match(
+	u32 svr, const struct fsl_soc_die_attr *matches)
+{
+	while (matches->svr) {
+		if (matches->svr == (svr & matches->mask))
+			return matches;
+		matches++;
+	};
+	return NULL;
+}
+
+u32 fsl_guts_get_svr(void)
+{
+	u32 svr = 0;
+
+	if (!guts || !guts->regs)
+		return svr;
+
+	if (guts->little_endian)
+		svr = ioread32(&guts->regs->svr);
+	else
+		svr = ioread32be(&guts->regs->svr);
+
+	return svr;
+}
+EXPORT_SYMBOL(fsl_guts_get_svr);
+
+static int fsl_guts_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	const struct fsl_soc_die_attr *soc_die;
+	const char *machine;
+	u32 svr;
+
+	/* Initialize guts */
+	guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL);
+	if (!guts)
+		return -ENOMEM;
+
+	guts->little_endian = of_property_read_bool(np, "little-endian");
+
+	guts->regs = of_iomap(np, 0);
+	if (!guts->regs)
+		return -ENOMEM;
+
+	/* Register soc device */
+	machine = of_flat_dt_get_machine_name();
+	if (machine)
+		soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
+
+	svr = fsl_guts_get_svr();
+	soc_die = fsl_soc_die_match(svr, fsl_soc_die);
+	if (soc_die) {
+		soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
+						     "QorIQ %s", soc_die->die);
+	} else {
+		soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "QorIQ");
+	}
+	soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
+					     "svr:0x%08x", svr);
+	soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
+					       SVR_MAJ(svr), SVR_MIN(svr));
+
+	soc_dev = soc_device_register(&soc_dev_attr);
+	if (IS_ERR(soc_dev))
+		return PTR_ERR(soc_dev);
+
+	pr_info("Machine: %s\n", soc_dev_attr.machine);
+	pr_info("SoC family: %s\n", soc_dev_attr.family);
+	pr_info("SoC ID: %s, Revision: %s\n",
+		soc_dev_attr.soc_id, soc_dev_attr.revision);
+	return 0;
+}
+
+static int fsl_guts_remove(struct platform_device *dev)
+{
+	soc_device_unregister(soc_dev);
+	iounmap(guts->regs);
+	return 0;
+}
+
+/*
+ * Table for matching compatible strings, for device tree
+ * guts node, for Freescale QorIQ SOCs.
+ */
+static const struct of_device_id fsl_guts_of_match[] = {
+	{ .compatible = "fsl,qoriq-device-config-1.0", },
+	{ .compatible = "fsl,qoriq-device-config-2.0", },
+	{ .compatible = "fsl,p1010-guts", },
+	{ .compatible = "fsl,p1020-guts", },
+	{ .compatible = "fsl,p1021-guts", },
+	{ .compatible = "fsl,p1022-guts", },
+	{ .compatible = "fsl,p1023-guts", },
+	{ .compatible = "fsl,p2020-guts", },
+	{ .compatible = "fsl,bsc9131-guts", },
+	{ .compatible = "fsl,bsc9132-guts", },
+	{ .compatible = "fsl,mpc8536-guts", },
+	{ .compatible = "fsl,mpc8544-guts", },
+	{ .compatible = "fsl,mpc8548-guts", },
+	{ .compatible = "fsl,mpc8568-guts", },
+	{ .compatible = "fsl,mpc8569-guts", },
+	{ .compatible = "fsl,mpc8572-guts", },
+	{ .compatible = "fsl,ls1021a-dcfg", },
+	{ .compatible = "fsl,ls1043a-dcfg", },
+	{ .compatible = "fsl,ls2080a-dcfg", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
+
+static struct platform_driver fsl_guts_driver = {
+	.driver = {
+		.name = "fsl-guts",
+		.of_match_table = fsl_guts_of_match,
+	},
+	.probe = fsl_guts_probe,
+	.remove = fsl_guts_remove,
+};
+
+static int __init fsl_guts_init(void)
+{
+	return platform_driver_register(&fsl_guts_driver);
+}
+core_initcall(fsl_guts_init);
+
+static void __exit fsl_guts_exit(void)
+{
+	platform_driver_unregister(&fsl_guts_driver);
+}
+module_exit(fsl_guts_exit);
diff --git a/include/linux/fsl/guts.h b/include/linux/fsl/guts.h
index 649e917..3efa3b8 100644
--- a/include/linux/fsl/guts.h
+++ b/include/linux/fsl/guts.h
@@ -29,83 +29,112 @@
  * #ifdefs.
  */
 struct ccsr_guts {
-	__be32	porpllsr;	/* 0x.0000 - POR PLL Ratio Status Register */
-	__be32	porbmsr;	/* 0x.0004 - POR Boot Mode Status Register */
-	__be32	porimpscr;	/* 0x.0008 - POR I/O Impedance Status and Control Register */
-	__be32	pordevsr;	/* 0x.000c - POR I/O Device Status Register */
-	__be32	pordbgmsr;	/* 0x.0010 - POR Debug Mode Status Register */
-	__be32	pordevsr2;	/* 0x.0014 - POR device status register 2 */
+	u32	porpllsr;	/* 0x.0000 - POR PLL Ratio Status Register */
+	u32	porbmsr;	/* 0x.0004 - POR Boot Mode Status Register */
+	u32	porimpscr;	/* 0x.0008 - POR I/O Impedance Status and
+				 *           Control Register
+				 */
+	u32	pordevsr;	/* 0x.000c - POR I/O Device Status Register */
+	u32	pordbgmsr;	/* 0x.0010 - POR Debug Mode Status Register */
+	u32	pordevsr2;	/* 0x.0014 - POR device status register 2 */
 	u8	res018[0x20 - 0x18];
-	__be32	porcir;		/* 0x.0020 - POR Configuration Information Register */
+	u32	porcir;		/* 0x.0020 - POR Configuration Information
+				 *           Register
+				 */
 	u8	res024[0x30 - 0x24];
-	__be32	gpiocr;		/* 0x.0030 - GPIO Control Register */
+	u32	gpiocr;		/* 0x.0030 - GPIO Control Register */
 	u8	res034[0x40 - 0x34];
-	__be32	gpoutdr;	/* 0x.0040 - General-Purpose Output Data Register */
+	u32	gpoutdr;	/* 0x.0040 - General-Purpose Output Data
+				 *           Register
+				 */
 	u8	res044[0x50 - 0x44];
-	__be32	gpindr;		/* 0x.0050 - General-Purpose Input Data Register */
+	u32	gpindr;		/* 0x.0050 - General-Purpose Input Data
+				 *           Register
+				 */
 	u8	res054[0x60 - 0x54];
-	__be32	pmuxcr;		/* 0x.0060 - Alternate Function Signal Multiplex Control */
-        __be32  pmuxcr2;	/* 0x.0064 - Alternate function signal multiplex control 2 */
-        __be32  dmuxcr;		/* 0x.0068 - DMA Mux Control Register */
+	u32	pmuxcr;		/* 0x.0060 - Alternate Function Signal
+				 *           Multiplex Control
+				 */
+	u32	pmuxcr2;	/* 0x.0064 - Alternate function signal
+				 *           multiplex control 2
+				 */
+	u32	dmuxcr;		/* 0x.0068 - DMA Mux Control Register */
         u8	res06c[0x70 - 0x6c];
-	__be32	devdisr;	/* 0x.0070 - Device Disable Control */
+	u32	devdisr;	/* 0x.0070 - Device Disable Control */
 #define CCSR_GUTS_DEVDISR_TB1	0x00001000
 #define CCSR_GUTS_DEVDISR_TB0	0x00004000
-	__be32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
+	u32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
 	u8	res078[0x7c - 0x78];
-	__be32  pmjcr;		/* 0x.007c - 4 Power Management Jog Control Register */
-	__be32	powmgtcsr;	/* 0x.0080 - Power Management Status and Control Register */
-	__be32  pmrccr;		/* 0x.0084 - Power Management Reset Counter Configuration Register */
-	__be32  pmpdccr;	/* 0x.0088 - Power Management Power Down Counter Configuration Register */
-	__be32  pmcdr;		/* 0x.008c - 4Power management clock disable register */
-	__be32	mcpsumr;	/* 0x.0090 - Machine Check Summary Register */
-	__be32	rstrscr;	/* 0x.0094 - Reset Request Status and Control Register */
-	__be32  ectrstcr;	/* 0x.0098 - Exception reset control register */
-	__be32  autorstsr;	/* 0x.009c - Automatic reset status register */
-	__be32	pvr;		/* 0x.00a0 - Processor Version Register */
-	__be32	svr;		/* 0x.00a4 - System Version Register */
+	u32	pmjcr;		/* 0x.007c - 4 Power Management Jog Control
+				 *           Register
+				 */
+	u32	powmgtcsr;	/* 0x.0080 - Power Management Status and
+				 *           Control Register
+				 */
+	u32	pmrccr;		/* 0x.0084 - Power Management Reset Counter
+				 *           Configuration Register
+				 */
+	u32	pmpdccr;	/* 0x.0088 - Power Management Power Down Counter
+				 *           Configuration Register
+				 */
+	u32	pmcdr;		/* 0x.008c - 4Power management clock disable
+				 *           register
+				 */
+	u32	mcpsumr;	/* 0x.0090 - Machine Check Summary Register */
+	u32	rstrscr;	/* 0x.0094 - Reset Request Status and
+				 *           Control Register
+				 */
+	u32	ectrstcr;	/* 0x.0098 - Exception reset control register */
+	u32	autorstsr;	/* 0x.009c - Automatic reset status register */
+	u32	pvr;		/* 0x.00a0 - Processor Version Register */
+	u32	svr;		/* 0x.00a4 - System Version Register */
 	u8	res0a8[0xb0 - 0xa8];
-	__be32	rstcr;		/* 0x.00b0 - Reset Control Register */
+	u32	rstcr;		/* 0x.00b0 - Reset Control Register */
 	u8	res0b4[0xc0 - 0xb4];
-	__be32  iovselsr;	/* 0x.00c0 - I/O voltage select status register
+	u32	iovselsr;	/* 0x.00c0 - I/O voltage select status register
 					     Called 'elbcvselcr' on 86xx SOCs */
 	u8	res0c4[0x100 - 0xc4];
-	__be32	rcwsr[16];	/* 0x.0100 - Reset Control Word Status registers
+	u32	rcwsr[16];	/* 0x.0100 - Reset Control Word Status registers
 					     There are 16 registers */
 	u8	res140[0x224 - 0x140];
-	__be32  iodelay1;	/* 0x.0224 - IO delay control register 1 */
-	__be32  iodelay2;	/* 0x.0228 - IO delay control register 2 */
+	u32	iodelay1;	/* 0x.0224 - IO delay control register 1 */
+	u32	iodelay2;	/* 0x.0228 - IO delay control register 2 */
 	u8	res22c[0x604 - 0x22c];
-	__be32	pamubypenr; 	/* 0x.604 - PAMU bypass enable register */
+	u32	pamubypenr;	/* 0x.604 - PAMU bypass enable register */
 	u8	res608[0x800 - 0x608];
-	__be32	clkdvdr;	/* 0x.0800 - Clock Divide Register */
+	u32	clkdvdr;	/* 0x.0800 - Clock Divide Register */
 	u8	res804[0x900 - 0x804];
-	__be32	ircr;		/* 0x.0900 - Infrared Control Register */
+	u32	ircr;		/* 0x.0900 - Infrared Control Register */
 	u8	res904[0x908 - 0x904];
-	__be32	dmacr;		/* 0x.0908 - DMA Control Register */
+	u32	dmacr;		/* 0x.0908 - DMA Control Register */
 	u8	res90c[0x914 - 0x90c];
-	__be32	elbccr;		/* 0x.0914 - eLBC Control Register */
+	u32	elbccr;		/* 0x.0914 - eLBC Control Register */
 	u8	res918[0xb20 - 0x918];
-	__be32	ddr1clkdr;	/* 0x.0b20 - DDR1 Clock Disable Register */
-	__be32	ddr2clkdr;	/* 0x.0b24 - DDR2 Clock Disable Register */
-	__be32	ddrclkdr;	/* 0x.0b28 - DDR Clock Disable Register */
+	u32	ddr1clkdr;	/* 0x.0b20 - DDR1 Clock Disable Register */
+	u32	ddr2clkdr;	/* 0x.0b24 - DDR2 Clock Disable Register */
+	u32	ddrclkdr;	/* 0x.0b28 - DDR Clock Disable Register */
 	u8	resb2c[0xe00 - 0xb2c];
-	__be32	clkocr;		/* 0x.0e00 - Clock Out Select Register */
+	u32	clkocr;		/* 0x.0e00 - Clock Out Select Register */
 	u8	rese04[0xe10 - 0xe04];
-	__be32	ddrdllcr;	/* 0x.0e10 - DDR DLL Control Register */
+	u32	ddrdllcr;	/* 0x.0e10 - DDR DLL Control Register */
 	u8	rese14[0xe20 - 0xe14];
-	__be32	lbcdllcr;	/* 0x.0e20 - LBC DLL Control Register */
-	__be32  cpfor;		/* 0x.0e24 - L2 charge pump fuse override register */
+	u32	lbcdllcr;	/* 0x.0e20 - LBC DLL Control Register */
+	u32	cpfor;		/* 0x.0e24 - L2 charge pump fuse override
+				 *           register
+				 */
 	u8	rese28[0xf04 - 0xe28];
-	__be32	srds1cr0;	/* 0x.0f04 - SerDes1 Control Register 0 */
-	__be32	srds1cr1;	/* 0x.0f08 - SerDes1 Control Register 0 */
+	u32	srds1cr0;	/* 0x.0f04 - SerDes1 Control Register 0 */
+	u32	srds1cr1;	/* 0x.0f08 - SerDes1 Control Register 0 */
 	u8	resf0c[0xf2c - 0xf0c];
-	__be32  itcr;		/* 0x.0f2c - Internal transaction control register */
+	u32	itcr;		/* 0x.0f2c - Internal transaction control
+				 *           register
+				 */
 	u8	resf30[0xf40 - 0xf30];
-	__be32	srds2cr0;	/* 0x.0f40 - SerDes2 Control Register 0 */
-	__be32	srds2cr1;	/* 0x.0f44 - SerDes2 Control Register 0 */
+	u32	srds2cr0;	/* 0x.0f40 - SerDes2 Control Register 0 */
+	u32	srds2cr1;	/* 0x.0f44 - SerDes2 Control Register 0 */
 } __attribute__ ((packed));
 
+u32 fsl_guts_get_svr(void);
 
 /* Alternate function signal multiplex control */
 #define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x))
-- 
2.1.0.27.g96db324

^ permalink raw reply related

* [v13, 6/8] MAINTAINERS: add entry for Freescale SoC drivers
From: Yangbo Lu @ 2016-10-28  3:32 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A, Scott Wood, Arnd Bergmann
  Cc: Mark Rutland, Greg Kroah-Hartman, Xiaobo Xie, Minghuan Lian,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, Qiang Zhao, Russell King,
	Bhupesh Sharma, Jochen Friedrich, Claudiu Manoil,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Yangbo Lu, Rob Herring,
	Santosh Shilimkar,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Leo Li,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Kumar Gala,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
In-Reply-To: <1477625554-46700-1-git-send-email-yangbo.lu-3arQi8VN3Tc@public.gmane.org>

Add maintainer entry for Freescale SoC drivers including
the QE library and the GUTS driver now. Also add maintainer
for QE library.

Signed-off-by: Yangbo Lu <yangbo.lu-3arQi8VN3Tc@public.gmane.org>
Acked-by: Scott Wood <oss-fOR+EgIDQEHk1uMJSBkQmQ@public.gmane.org>
Acked-by: Qiang Zhao <qiang.zhao-3arQi8VN3Tc@public.gmane.org>
---
Changes for v8:
	- Added this patch
Changes for v9:
	- Added linux-arm mail list
	- Removed GUTS driver entry
Changes for v10:
	- Changed 'DRIVER' to 'DRIVERS'
	- Added 'Acked-by' of Scott and Qiang
Changes for v11:
	- None
Changes for v12:
	- None
Changes for v13:
	- None
---
 MAINTAINERS | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index c72fa18..cf3aaee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5037,9 +5037,18 @@ S:	Maintained
 F:	drivers/net/ethernet/freescale/fman
 F:	Documentation/devicetree/bindings/powerpc/fsl/fman.txt
 
+FREESCALE SOC DRIVERS
+M:	Scott Wood <oss-fOR+EgIDQEHk1uMJSBkQmQ@public.gmane.org>
+L:	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
+L:	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
+S:	Maintained
+F:	drivers/soc/fsl/
+F:	include/linux/fsl/
+
 FREESCALE QUICC ENGINE LIBRARY
+M:	Qiang Zhao <qiang.zhao-3arQi8VN3Tc@public.gmane.org>
 L:	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
-S:	Orphan
+S:	Maintained
 F:	drivers/soc/fsl/qe/
 F:	include/soc/fsl/*qe*.h
 F:	include/soc/fsl/*ucc*.h
-- 
2.1.0.27.g96db324

^ permalink raw reply related

* [v13, 7/8] base: soc: introduce soc_device_match() interface
From: Yangbo Lu @ 2016-10-28  3:32 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A, Scott Wood, Arnd Bergmann
  Cc: Mark Rutland, Greg Kroah-Hartman, Xiaobo Xie, Minghuan Lian,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, Qiang Zhao, Russell King,
	Bhupesh Sharma, Jochen Friedrich, Claudiu Manoil,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Yangbo Lu, Rob Herring,
	Santosh Shilimkar,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Leo Li,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Kumar Gala,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
In-Reply-To: <1477625554-46700-1-git-send-email-yangbo.lu-3arQi8VN3Tc@public.gmane.org>

From: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>

We keep running into cases where device drivers want to know the exact
version of the a SoC they are currently running on. In the past, this has
usually been done through a vendor specific API that can be called by a
driver, or by directly accessing some kind of version register that is
not part of the device itself but that belongs to a global register area
of the chip.

Common reasons for doing this include:

- A machine is not using devicetree or similar for passing data about
  on-chip devices, but just announces their presence using boot-time
  platform devices, and the machine code itself does not care about the
  revision.

- There is existing firmware or boot loaders with existing DT binaries
  with generic compatible strings that do not identify the particular
  revision of each device, but the driver knows which SoC revisions
  include which part.

- A prerelease version of a chip has some quirks and we are using the same
  version of the bootloader and the DT blob on both the prerelease and the
  final version. An update of the DT binding seems inappropriate because
  that would involve maintaining multiple copies of the dts and/or
  bootloader.

This patch introduces the soc_device_match() interface that is meant to
work like of_match_node() but instead of identifying the version of a
device, it identifies the SoC itself using a vendor-agnostic interface.

Unlike of_match_node(), we do not do an exact string compare but instead
use glob_match() to allow wildcards in strings.

Signed-off-by: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>
Signed-off-by: Yangbo Lu <yangbo.lu-3arQi8VN3Tc@public.gmane.org>
Acked-by: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>
---
Changes for v11:
	- Added this patch for soc match
Changes for v12:
	- Corrected the author
	- Rewrited soc_device_match with while loop
Changes for v13:
	- Added ack from Greg
---
 drivers/base/Kconfig    |  1 +
 drivers/base/soc.c      | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/sys_soc.h |  3 +++
 3 files changed, 70 insertions(+)

diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index fdf44ca..991b21e 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -235,6 +235,7 @@ config GENERIC_CPU_AUTOPROBE
 
 config SOC_BUS
 	bool
+	select GLOB
 
 source "drivers/base/regmap/Kconfig"
 
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index b63f23e..0c5cf87 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <linux/sys_soc.h>
 #include <linux/err.h>
+#include <linux/glob.h>
 
 static DEFINE_IDA(soc_ida);
 
@@ -159,3 +160,68 @@ static int __init soc_bus_register(void)
 	return bus_register(&soc_bus_type);
 }
 core_initcall(soc_bus_register);
+
+static int soc_device_match_one(struct device *dev, void *arg)
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+	const struct soc_device_attribute *match = arg;
+
+	if (match->machine &&
+	    !glob_match(match->machine, soc_dev->attr->machine))
+		return 0;
+
+	if (match->family &&
+	    !glob_match(match->family, soc_dev->attr->family))
+		return 0;
+
+	if (match->revision &&
+	    !glob_match(match->revision, soc_dev->attr->revision))
+		return 0;
+
+	if (match->soc_id &&
+	    !glob_match(match->soc_id, soc_dev->attr->soc_id))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * soc_device_match - identify the SoC in the machine
+ * @matches: zero-terminated array of possible matches
+ *
+ * returns the first matching entry of the argument array, or NULL
+ * if none of them match.
+ *
+ * This function is meant as a helper in place of of_match_node()
+ * in cases where either no device tree is available or the information
+ * in a device node is insufficient to identify a particular variant
+ * by its compatible strings or other properties. For new devices,
+ * the DT binding should always provide unique compatible strings
+ * that allow the use of of_match_node() instead.
+ *
+ * The calling function can use the .data entry of the
+ * soc_device_attribute to pass a structure or function pointer for
+ * each entry.
+ */
+const struct soc_device_attribute *soc_device_match(
+	const struct soc_device_attribute *matches)
+{
+	int ret = 0;
+
+	if (!matches)
+		return NULL;
+
+	while (!ret) {
+		if (!(matches->machine || matches->family ||
+		      matches->revision || matches->soc_id))
+			break;
+		ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
+				       soc_device_match_one);
+		if (!ret)
+			matches++;
+		else
+			return matches;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(soc_device_match);
diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h
index 2739ccb..9f5eb06 100644
--- a/include/linux/sys_soc.h
+++ b/include/linux/sys_soc.h
@@ -13,6 +13,7 @@ struct soc_device_attribute {
 	const char *family;
 	const char *revision;
 	const char *soc_id;
+	const void *data;
 };
 
 /**
@@ -34,4 +35,6 @@ void soc_device_unregister(struct soc_device *soc_dev);
  */
 struct device *soc_device_to_device(struct soc_device *soc);
 
+const struct soc_device_attribute *soc_device_match(
+	const struct soc_device_attribute *matches);
 #endif /* __SOC_BUS_H */
-- 
2.1.0.27.g96db324

^ permalink raw reply related

* [v13, 8/8] mmc: sdhci-of-esdhc: fix host version for T4240-R1.0-R2.0
From: Yangbo Lu @ 2016-10-28  3:32 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A, Scott Wood, Arnd Bergmann
  Cc: Mark Rutland, Greg Kroah-Hartman, Xiaobo Xie, Minghuan Lian,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, Qiang Zhao, Russell King,
	Bhupesh Sharma, Jochen Friedrich, Claudiu Manoil,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Yangbo Lu, Rob Herring,
	Santosh Shilimkar,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Leo Li,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Kumar Gala,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
In-Reply-To: <1477625554-46700-1-git-send-email-yangbo.lu-3arQi8VN3Tc@public.gmane.org>

The eSDHC of T4240-R1.0-R2.0 has incorrect vender version and spec version.
Acturally the right version numbers should be VVN=0x13 and SVN = 0x1.
This patch adds the GUTS driver support for eSDHC driver to match SoC.
And fix host version to avoid that incorrect version numbers break down
the ADMA data transfer.

Signed-off-by: Yangbo Lu <yangbo.lu-3arQi8VN3Tc@public.gmane.org>
Acked-by: Ulf Hansson <ulf.hansson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Acked-by: Scott Wood <oss-fOR+EgIDQEHk1uMJSBkQmQ@public.gmane.org>
---
Changes for v2:
	- Got SVR through iomap instead of dts
Changes for v3:
	- Managed GUTS through syscon instead of iomap in eSDHC driver
Changes for v4:
	- Got SVR by GUTS driver instead of SYSCON
Changes for v5:
	- Changed to get SVR through API fsl_guts_get_svr()
	- Combined patch 4, patch 5 and patch 6 into one
Changes for v6:
	- Added 'Acked-by: Ulf Hansson'
Changes for v7:
	- None
Changes for v8:
	- Added 'Acked-by: Scott Wood'
Changes for v9:
	- None
Changes for v10:
	- None
Changes for v11:
	- Changed to use soc_device_match
Changes for v12:
	- Matched soc through .family field instead of .soc_id
Changes for v13:
	- None
---
 drivers/mmc/host/Kconfig          |  1 +
 drivers/mmc/host/sdhci-of-esdhc.c | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5274f50..a1135a9 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -144,6 +144,7 @@ config MMC_SDHCI_OF_ESDHC
 	depends on MMC_SDHCI_PLTFM
 	depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE
 	select MMC_SDHCI_IO_ACCESSORS
+	select FSL_GUTS
 	help
 	  This selects the Freescale eSDHC controller support.
 
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index fb71c86..57bdb9e 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -18,6 +18,7 @@
 #include <linux/of.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/sys_soc.h>
 #include <linux/mmc/host.h>
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
@@ -28,6 +29,7 @@
 struct sdhci_esdhc {
 	u8 vendor_ver;
 	u8 spec_ver;
+	bool quirk_incorrect_hostver;
 };
 
 /**
@@ -73,6 +75,8 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,
 static u16 esdhc_readw_fixup(struct sdhci_host *host,
 				     int spec_reg, u32 value)
 {
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
 	u16 ret;
 	int shift = (spec_reg & 0x2) * 8;
 
@@ -80,6 +84,12 @@ static u16 esdhc_readw_fixup(struct sdhci_host *host,
 		ret = value & 0xffff;
 	else
 		ret = (value >> shift) & 0xffff;
+	/* Workaround for T4240-R1.0-R2.0 eSDHC which has incorrect
+	 * vendor version and spec version information.
+	 */
+	if ((spec_reg == SDHCI_HOST_VERSION) &&
+	    (esdhc->quirk_incorrect_hostver))
+		ret = (VENDOR_V_23 << SDHCI_VENDOR_VER_SHIFT) | SDHCI_SPEC_200;
 	return ret;
 }
 
@@ -558,6 +568,12 @@ static const struct sdhci_pltfm_data sdhci_esdhc_le_pdata = {
 	.ops = &sdhci_esdhc_le_ops,
 };
 
+static struct soc_device_attribute soc_incorrect_hostver[] = {
+	{ .family = "QorIQ T4240", .revision = "1.0", },
+	{ .family = "QorIQ T4240", .revision = "2.0", },
+	{ },
+};
+
 static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
 {
 	struct sdhci_pltfm_host *pltfm_host;
@@ -571,6 +587,10 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
 	esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >>
 			     SDHCI_VENDOR_VER_SHIFT;
 	esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK;
+	if (soc_device_match(soc_incorrect_hostver))
+		esdhc->quirk_incorrect_hostver = true;
+	else
+		esdhc->quirk_incorrect_hostver = false;
 }
 
 static int sdhci_esdhc_probe(struct platform_device *pdev)
-- 
2.1.0.27.g96db324

^ permalink raw reply related

* Re: [PATCH v2 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
From: Tom Herbert @ 2016-10-28  2:52 UTC (permalink / raw)
  To: David Lebrun; +Cc: Linux Kernel Network Developers
In-Reply-To: <1477497292-22155-3-git-send-email-david.lebrun@uclouvain.be>

On Wed, Oct 26, 2016 at 8:54 AM, David Lebrun <david.lebrun@uclouvain.be> wrote:
> This patch adds the necessary hooks and structures to provide support
> for SR-IPv6 control plane, essentially the Generic Netlink commands
> that will be used for userspace control over the Segment Routing
> kernel structures.
>
> The genetlink commands provide control over two different structures:
> tunnel source and HMAC data. The tunnel source is the source address
> that will be used by default when encapsulating packets into an
> outer IPv6 header + SRH. If the tunnel source is set to :: then an
> address of the outgoing interface will be selected as the source.
>
> The HMAC commands currently just return ENOTSUPP and will be implemented
> in a future patch.
>
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
> ---
>  include/linux/seg6_genl.h      |   6 ++
>  include/net/netns/ipv6.h       |   1 +
>  include/net/seg6.h             |  30 ++++++
>  include/uapi/linux/seg6_genl.h |  32 ++++++
>  net/ipv6/Makefile              |   2 +-
>  net/ipv6/seg6.c                | 214 +++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 284 insertions(+), 1 deletion(-)
>  create mode 100644 include/linux/seg6_genl.h
>  create mode 100644 include/net/seg6.h
>  create mode 100644 include/uapi/linux/seg6_genl.h
>  create mode 100644 net/ipv6/seg6.c
>
> diff --git a/include/linux/seg6_genl.h b/include/linux/seg6_genl.h
> new file mode 100644
> index 0000000..d6c3fb4f
> --- /dev/null
> +++ b/include/linux/seg6_genl.h
> @@ -0,0 +1,6 @@
> +#ifndef _LINUX_SEG6_GENL_H
> +#define _LINUX_SEG6_GENL_H
> +
> +#include <uapi/linux/seg6_genl.h>
> +
> +#endif
> diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
> index 10d0848..de7745e 100644
> --- a/include/net/netns/ipv6.h
> +++ b/include/net/netns/ipv6.h
> @@ -85,6 +85,7 @@ struct netns_ipv6 {
>  #endif
>         atomic_t                dev_addr_genid;
>         atomic_t                fib6_sernum;
> +       struct seg6_pernet_data *seg6_data;
>  };
>
>  #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
> diff --git a/include/net/seg6.h b/include/net/seg6.h
> new file mode 100644
> index 0000000..a9d9a9b
> --- /dev/null
> +++ b/include/net/seg6.h
> @@ -0,0 +1,30 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  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.
> + */
> +
> +#ifndef _NET_SEG6_H
> +#define _NET_SEG6_H
> +
> +#include <linux/net.h>
> +#include <linux/ipv6.h>
> +
> +struct seg6_pernet_data {
> +       struct mutex lock;
> +       struct in6_addr __rcu *tun_src;
> +};
> +
> +static inline struct seg6_pernet_data *seg6_pernet(struct net *net)
> +{
> +       return net->ipv6.seg6_data;
> +}
> +
> +#endif
> diff --git a/include/uapi/linux/seg6_genl.h b/include/uapi/linux/seg6_genl.h
> new file mode 100644
> index 0000000..fcf1c60
> --- /dev/null
> +++ b/include/uapi/linux/seg6_genl.h
> @@ -0,0 +1,32 @@
> +#ifndef _UAPI_LINUX_SEG6_GENL_H
> +#define _UAPI_LINUX_SEG6_GENL_H
> +
> +#define SEG6_GENL_NAME         "SEG6"
> +#define SEG6_GENL_VERSION      0x1
> +
> +enum {
> +       SEG6_ATTR_UNSPEC,
> +       SEG6_ATTR_DST,
> +       SEG6_ATTR_DSTLEN,
> +       SEG6_ATTR_HMACKEYID,
> +       SEG6_ATTR_SECRET,
> +       SEG6_ATTR_SECRETLEN,
> +       SEG6_ATTR_ALGID,
> +       SEG6_ATTR_HMACINFO,
> +       __SEG6_ATTR_MAX,
> +};
> +
> +#define SEG6_ATTR_MAX (__SEG6_ATTR_MAX - 1)
> +
> +enum {
> +       SEG6_CMD_UNSPEC,
> +       SEG6_CMD_SETHMAC,
> +       SEG6_CMD_DUMPHMAC,
> +       SEG6_CMD_SET_TUNSRC,
> +       SEG6_CMD_GET_TUNSRC,
> +       __SEG6_CMD_MAX,
> +};
> +
> +#define SEG6_CMD_MAX (__SEG6_CMD_MAX - 1)
> +
> +#endif
> diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
> index c174ccb..29a77d3 100644
> --- a/net/ipv6/Makefile
> +++ b/net/ipv6/Makefile
> @@ -45,7 +45,7 @@ obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
>  obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
>  obj-$(CONFIG_IPV6_FOU) += fou6.o
>
> -obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o
> +obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o seg6.o
>  obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
>
>  obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
> diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c
> new file mode 100644
> index 0000000..24111662
> --- /dev/null
> +++ b/net/ipv6/seg6.c
> @@ -0,0 +1,214 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  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.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/socket.h>
> +#include <linux/net.h>
> +#include <linux/in6.h>
> +#include <linux/slab.h>
> +
> +#include <net/ipv6.h>
> +#include <net/protocol.h>
> +
> +#include <net/seg6.h>
> +#include <net/genetlink.h>
> +#include <linux/seg6.h>
> +#include <linux/seg6_genl.h>
> +
> +static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
> +       [SEG6_ATTR_DST]                         = { .type = NLA_BINARY,
> +               .len = sizeof(struct in6_addr) },
> +       [SEG6_ATTR_DSTLEN]                      = { .type = NLA_S32, },
> +       [SEG6_ATTR_HMACKEYID]           = { .type = NLA_U32, },
> +       [SEG6_ATTR_SECRET]                      = { .type = NLA_BINARY, },
> +       [SEG6_ATTR_SECRETLEN]           = { .type = NLA_U8, },
> +       [SEG6_ATTR_ALGID]                       = { .type = NLA_U8, },
> +       [SEG6_ATTR_HMACINFO]            = { .type = NLA_NESTED, },
> +};
> +
> +static struct genl_family seg6_genl_family = {
> +       .id = GENL_ID_GENERATE,
> +       .hdrsize = 0,
> +       .name = SEG6_GENL_NAME,
> +       .version = SEG6_GENL_VERSION,
> +       .maxattr = SEG6_ATTR_MAX,
> +       .netnsok = true,
> +};
> +
> +static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
> +{
> +       return -ENOTSUPP;
> +}
> +
> +static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
> +{
> +       struct net *net = genl_info_net(info);
> +       struct in6_addr *val, *t_old, *t_new;
> +       struct seg6_pernet_data *sdata;
> +
> +       sdata = seg6_pernet(net);
> +
> +       if (!info->attrs[SEG6_ATTR_DST])
> +               return -EINVAL;
> +
> +       val = nla_data(info->attrs[SEG6_ATTR_DST]);
> +       t_new = kmemdup(val, sizeof(*val), GFP_KERNEL);
> +
> +       mutex_lock(&sdata->lock);
> +
> +       t_old = sdata->tun_src;
> +       rcu_assign_pointer(sdata->tun_src, t_new);
> +
> +       mutex_unlock(&sdata->lock);
> +
> +       synchronize_net();
> +       kfree(t_old);
> +
> +       return 0;
> +}
> +
> +static int seg6_genl_get_tunsrc(struct sk_buff *skb, struct genl_info *info)
> +{
> +       struct net *net = genl_info_net(info);
> +       struct in6_addr *tun_src;
> +       struct sk_buff *msg;
> +       void *hdr;
> +
> +       msg = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +
> +       hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
> +                         &seg6_genl_family, 0, SEG6_CMD_GET_TUNSRC);
> +       if (!hdr)
> +               goto free_msg;
> +
> +       rcu_read_lock();
> +       tun_src = rcu_dereference(seg6_pernet(net)->tun_src);
> +
> +       if (nla_put(msg, SEG6_ATTR_DST, sizeof(struct in6_addr), tun_src))
> +               goto nla_put_failure;
> +
> +       rcu_read_unlock();
> +
> +       genlmsg_end(msg, hdr);
> +       genlmsg_reply(msg, info);
> +
> +       return 0;
> +
> +nla_put_failure:
> +       rcu_read_unlock();
> +       genlmsg_cancel(msg, hdr);
> +free_msg:
> +       nlmsg_free(msg);
> +       return -ENOMEM;
> +}
> +
> +static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +       return -ENOTSUPP;
> +}
> +
> +static const struct genl_ops seg6_genl_ops[] = {
> +       {
> +               .cmd    = SEG6_CMD_SETHMAC,
> +               .doit   = seg6_genl_sethmac,
> +               .policy = seg6_genl_policy,
> +               .flags  = GENL_ADMIN_PERM,
> +       },
> +       {
> +               .cmd    = SEG6_CMD_DUMPHMAC,
> +               .dumpit = seg6_genl_dumphmac,
> +               .policy = seg6_genl_policy,
> +               .flags  = GENL_ADMIN_PERM,
> +       },
> +       {
> +               .cmd    = SEG6_CMD_SET_TUNSRC,
> +               .doit   = seg6_genl_set_tunsrc,
> +               .policy = seg6_genl_policy,
> +               .flags  = GENL_ADMIN_PERM,
> +       },
> +       {
> +               .cmd    = SEG6_CMD_GET_TUNSRC,
> +               .doit   = seg6_genl_get_tunsrc,
> +               .policy = seg6_genl_policy,
> +               .flags  = GENL_ADMIN_PERM,
> +       },
> +};
> +
> +static int __net_init seg6_net_init(struct net *net)
> +{
> +       struct seg6_pernet_data *sdata;
> +
> +       sdata = kzalloc(sizeof(*sdata), GFP_KERNEL);
> +       if (!sdata)
> +               return -ENOMEM;
> +
> +       mutex_init(&sdata->lock);
> +
> +       sdata->tun_src = kzalloc(sizeof(*sdata->tun_src), GFP_KERNEL);
> +       if (!sdata->tun_src) {
> +               kfree(sdata);
> +               return -ENOMEM;
> +       }
> +
> +       net->ipv6.seg6_data = sdata;
> +
> +       return 0;
> +}
> +
> +static void __net_exit seg6_net_exit(struct net *net)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +
> +       kfree(sdata->tun_src);
> +       kfree(sdata);
> +}
> +
> +static struct pernet_operations ip6_segments_ops = {
> +       .init = seg6_net_init,
> +       .exit = seg6_net_exit,
> +};
> +
> +static int __init seg6_init(void)
> +{
> +       int err = -ENOMEM;
> +
> +       err = genl_register_family_with_ops(&seg6_genl_family, seg6_genl_ops);
> +       if (err)
> +               goto out;
> +
> +       err = register_pernet_subsys(&ip6_segments_ops);
> +       if (err)
> +               goto out_unregister_genl;
> +
> +       pr_info("Segment Routing with IPv6\n");
> +
> +out:
> +       return err;
> +out_unregister_genl:
> +       genl_unregister_family(&seg6_genl_family);
> +       goto out;
> +}
> +module_init(seg6_init);
> +
> +static void __exit seg6_exit(void)
> +{
> +       unregister_pernet_subsys(&ip6_segments_ops);
> +       genl_unregister_family(&seg6_genl_family);
> +}
> +module_exit(seg6_exit);
> +
> +MODULE_DESCRIPTION("Segment Routing with IPv6");
> +MODULE_LICENSE("GPL v2");
> --
> 2.7.3
>

Acked-by: Tom Herbert <tom@herbertland.com>

^ permalink raw reply

* Hope you received my message
From: Friedrich Mayrhofer @ 2016-10-28  4:14 UTC (permalink / raw)




-- 
This is the second time i am sending you this mail.
I, Friedrich Mayrhofer Donate $ 1,000,000.00 to You, Email  Me personally for more details.
Regards.Friedrich Mayrhofer

^ permalink raw reply

* Re: [v13, 5/8] soc: fsl: add GUTS driver for QorIQ platforms
From: Scott Wood @ 2016-10-28  4:45 UTC (permalink / raw)
  To: Yangbo Lu, linux-mmc, ulf.hansson, Arnd Bergmann
  Cc: linuxppc-dev, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, linux-i2c, iommu, netdev, Greg Kroah-Hartman,
	Mark Rutland, Rob Herring, Russell King, Jochen Friedrich,
	Joerg Roedel, Claudiu Manoil, Bhupesh Sharma, Qiang Zhao,
	Kumar Gala, Santosh Shilimkar, Leo Li, Xiaobo Xie, Minghuan Lian
In-Reply-To: <1477625554-46700-6-git-send-email-yangbo.lu@nxp.com>

On Fri, 2016-10-28 at 11:32 +0800, Yangbo Lu wrote:
> +	guts->regs = of_iomap(np, 0);
> +	if (!guts->regs)
> +		return -ENOMEM;
> +
> +	/* Register soc device */
> +	machine = of_flat_dt_get_machine_name();
> +	if (machine)
> +		soc_dev_attr.machine = devm_kstrdup(dev, machine,
> GFP_KERNEL);
> +
> +	svr = fsl_guts_get_svr();
> +	soc_die = fsl_soc_die_match(svr, fsl_soc_die);
> +	if (soc_die) {
> +		soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
> +						     "QorIQ %s", soc_die-
> >die);
> +	} else {
> +		soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
> "QorIQ");
> +	}
> +	soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
> +					     "svr:0x%08x", svr);
> +	soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
> +					       SVR_MAJ(svr), SVR_MIN(svr));
> +
> +	soc_dev = soc_device_register(&soc_dev_attr);
> +	if (IS_ERR(soc_dev))
> +		return PTR_ERR(soc_dev);

ioremap leaks on this error path.  Use devm_ioremap_resource().

-Scott

^ permalink raw reply

* Did You Get My Message This Time?
From: Friedrich Mayrhofer @ 2016-10-28  4:15 UTC (permalink / raw)





This is the second time i am sending you this mail.I, Friedrich Mayrhofer Donate $ 1,000,000.00 to You, Email  Me personally for more details.

Regards.
Friedrich Mayrhofer

^ permalink raw reply

* Re: [PATCH v2] ip6_tunnel: Clear IP6CB in ip6_tnl_xmit() after encapsulation
From: Eli Cooper @ 2016-10-28  5:13 UTC (permalink / raw)
  To: Tom Herbert; +Cc: Linux Kernel Network Developers, David S . Miller
In-Reply-To: <CALx6S36O_MUQw4vWKUoW-ZgCTg9PJrPjNHwuEWTDG9t=BxQv3w@mail.gmail.com>

On 2016/10/28 10:17, Tom Herbert wrote:
> On Thu, Oct 27, 2016 at 6:52 PM, Eli Cooper <elicooper@gmx.com> wrote:
>> > skb->cb may contain data from previous layers. In the observed scenario,
>> > the garbage data were misinterpreted as IP6CB(skb)->frag_max_size, so
>> > that small packets sent through the tunnel are mistakenly fragmented.
>> >
>> > This patch clears the control buffer for the next layer, after an IPv6
>> > header is installed.
>> >
> Nice catch, but can you rectify this with what udp_tunnel6_xmit_skb is
> doing. udp_tunnel6_xmit_skb calls ip6tunnel_xmit directly. Looks like
> we do
>
> memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
> IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED
>                             | IPSKB_REROUTED);
>
> Is this what we should be doing in ip6_tnl_xmit also, or is
> udp_tunnel6_xmit_skb broken because it doesn't zero all the cb?

udp_tunnel6_xmit_skb() is also broken, I can confirm. Actually I found
it pretty easy to reproduce by having a netns or router forwarding
between two tunnels established with another two namespaces or hosts.
The router sends out packets with IPv6 Fragment headers, even when the
packet is too small to really get fragmented.

The control buffer, by definition, is private to the layer having the
skb queued at the moment. As David has pointed out in v1 of this patch,
cb is either interpreted as IPCB or as IP6CB, and in this case, it will
be IP6CB after ip6tunnel_xmit(). So I think it is best that all the
IP6CB gets cleared before it is pushed to the next layer. Maybe we
should clear IP6CB in ip6tunnel_xmit(), rather than in every tunnel's codes?

By the way, I don't see any point in setting IPCB(skb)->flags in
udp_tunnel6_xmit_skb(). It will not be interpreted as IPCB any further
past ip6tunnel_xmit(), even if it were not cleared. Plus, nothing seems
to use these flags anyway.

Thanks,
Eli

^ permalink raw reply

* [v14, 0/8] Fix eSDHC host version register bug
From: Yangbo Lu @ 2016-10-28  5:45 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A, Scott Wood, Arnd Bergmann
  Cc: Mark Rutland, Greg Kroah-Hartman, Xiaobo Xie, Minghuan Lian,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA, Qiang Zhao, Russell King,
	Bhupesh Sharma, Jochen Friedrich, Claudiu Manoil,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Yangbo Lu, Rob Herring,
	Santosh Shilimkar,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Leo Li,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Kumar Gala,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ

This patchset is used to fix a host version register bug in the T4240-R1.0-R2.0
eSDHC controller. To match the SoC version and revision, 10 previous version
patchsets had tried many methods but all of them were rejected by reviewers.
Such as
	- dts compatible method
	- syscon method
	- ifdef PPC method
	- GUTS driver getting SVR method
Anrd suggested a soc_device_match method in v10, and this is the only available
method left now. This v11 patchset introduces the soc_device_match interface in
soc driver.

The first six patches of Yangbo are to add the GUTS driver. This is used to
register a soc device which contain soc version and revision information.
The other two patches introduce the soc_device_match method in soc driver
and apply it on esdhc driver to fix this bug.

Arnd Bergmann (1):
  base: soc: introduce soc_device_match() interface

Yangbo Lu (7):
  dt: bindings: update Freescale DCFG compatible
  ARM64: dts: ls2080a: add device configuration node
  dt: bindings: move guts devicetree doc out of powerpc directory
  powerpc/fsl: move mpc85xx.h to include/linux/fsl
  soc: fsl: add GUTS driver for QorIQ platforms
  MAINTAINERS: add entry for Freescale SoC drivers
  mmc: sdhci-of-esdhc: fix host version for T4240-R1.0-R2.0

 Documentation/devicetree/bindings/arm/fsl.txt      |   6 +-
 .../bindings/{powerpc => soc}/fsl/guts.txt         |   3 +
 MAINTAINERS                                        |  11 +-
 arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi     |   6 +
 arch/powerpc/kernel/cpu_setup_fsl_booke.S          |   2 +-
 arch/powerpc/sysdev/fsl_pci.c                      |   2 +-
 drivers/base/Kconfig                               |   1 +
 drivers/base/soc.c                                 |  66 ++++++
 drivers/clk/clk-qoriq.c                            |   3 +-
 drivers/i2c/busses/i2c-mpc.c                       |   2 +-
 drivers/iommu/fsl_pamu.c                           |   3 +-
 drivers/mmc/host/Kconfig                           |   1 +
 drivers/mmc/host/sdhci-of-esdhc.c                  |  20 ++
 drivers/net/ethernet/freescale/gianfar.c           |   2 +-
 drivers/soc/Kconfig                                |   3 +-
 drivers/soc/fsl/Kconfig                            |  18 ++
 drivers/soc/fsl/Makefile                           |   1 +
 drivers/soc/fsl/guts.c                             | 238 +++++++++++++++++++++
 include/linux/fsl/guts.h                           | 125 ++++++-----
 .../asm/mpc85xx.h => include/linux/fsl/svr.h       |   4 +-
 include/linux/sys_soc.h                            |   3 +
 21 files changed, 458 insertions(+), 62 deletions(-)
 rename Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt (91%)
 create mode 100644 drivers/soc/fsl/Kconfig
 create mode 100644 drivers/soc/fsl/guts.c
 rename arch/powerpc/include/asm/mpc85xx.h => include/linux/fsl/svr.h (97%)

-- 
2.1.0.27.g96db324

^ permalink raw reply

* [v14, 1/8] dt: bindings: update Freescale DCFG compatible
From: Yangbo Lu @ 2016-10-28  5:45 UTC (permalink / raw)
  To: linux-mmc, ulf.hansson, Scott Wood, Arnd Bergmann
  Cc: linuxppc-dev, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, linux-i2c, iommu, netdev, Greg Kroah-Hartman,
	Mark Rutland, Rob Herring, Russell King, Jochen Friedrich,
	Joerg Roedel, Claudiu Manoil, Bhupesh Sharma, Qiang Zhao,
	Kumar Gala, Santosh Shilimkar, Leo Li, Xiaobo Xie, Minghuan 
In-Reply-To: <1477633521-7391-1-git-send-email-yangbo.lu@nxp.com>

Update Freescale DCFG compatible with 'fsl,<chip>-dcfg' instead
of 'fsl,ls1021a-dcfg' to include more chips such as ls1021a,
ls1043a, and ls2080a.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Scott Wood <oss@buserror.net>
---
Changes for v8:
	- Added this patch
Changes for v9:
	- Added a list for the possible compatibles
Changes for v10:
	- None
Changes for v11:
	- Added 'Acked-by: Rob Herring'
	- Updated commit message by Scott
Changes for v12:
	- None
Changes for v13:
	- None
Changes for v14:
	- None
---
 Documentation/devicetree/bindings/arm/fsl.txt | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index dbbc095..713c1ae 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -119,7 +119,11 @@ Freescale DCFG
 configuration and status for the device. Such as setting the secondary
 core start address and release the secondary core from holdoff and startup.
   Required properties:
-  - compatible: should be "fsl,ls1021a-dcfg"
+  - compatible: should be "fsl,<chip>-dcfg"
+    Possible compatibles:
+	"fsl,ls1021a-dcfg"
+	"fsl,ls1043a-dcfg"
+	"fsl,ls2080a-dcfg"
   - reg : should contain base address and length of DCFG memory-mapped registers
 
 Example:
-- 
2.1.0.27.g96db324

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox