<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">I'm also very interested in
      implementing a switchdev driver (seems to be a good direction for
      this type of work), so I'd like to see any efforts in this
      direction so far which I can use as a base for my driver. I was
      waiting for the switch to Linux 3.19 for the initial code be be
      easily available.<br>
      <br>
      Charlie<br>
      <br>
      <br>
      On 26/02/15 19:58, Alexandru Ardelean wrote:<br>
    </div>
    <blockquote
cite="mid:CA+U=Dsocz-yTA6fGn8h16-OrGN8Hz_y9N7s3TD-2xMsbQseEew@mail.gmail.com"
      type="cite">
      <meta http-equiv="Content-Type" content="text/html;
        charset=windows-1252">
      <div dir="ltr">
        <div>
          <div>
            <div>
              <div>Fully agree on converging.<br>
              </div>
              I missed Rafal's switchdev effort.<br>
              <br>
            </div>
            Before starting on this work, I first tried to look into
            net/dsa in the Linux kernel.<br>
          </div>
          I did notice your patches there and started on that.<br>
        </div>
        I got to a decent point, but then I was stuck at some issues.<br>
        I later found out that I needed to adjust the MTU and manually
        pad potential runt packets.<br>
        <div>
          <div><br>
          </div>
          <div>I also found out the switchdev API, which seems like it's
            in an rather infant state.<br>
          </div>
          <div><br>
          </div>
          <div>In any case, I think DSA is the better approach, so my
            vote is for b53 + DSA (or DSA-like) in the kernel.<br>
          </div>
          <div><br>
          </div>
          <div>For this swconfig effort, the reasoning is that our
            current firmware is @ kernel 3.10, and most of our current
            target setup logic relies on swconfig; I backported DSA, but
            because of time/effort constraints to also port, test &
            validate any b53 PHY setup logic in DSA, we decided that
            it's easier to adapt the current b53 driver, and later
            re-visit DSA.<br>
          </div>
          <div>And because we have time constraints, there's no telling
            if we'll have the time to port b53 to DSA, so this patchset
            is at least meant to share our effort/findings regarding the
            b53 + LAN ports + Broadcom tag.<br>
          </div>
          <div>If things get settled/more calm, I might try to do an
            effort to do b53 + DSA (if nobody does that before me).<br>
          </div>
          <div><br>
          </div>
          <div>Regarding this patchset, I have no objections regarding
            whether it gets accepted/dropped.<br>
          </div>
          <div>Either way, we'll keep it in our tree for a while, and
            re-evaluate any other DSA (or DSA-like) frameworks later.<br>
          </div>
          <div>
            <div><br>
            </div>
            <div>Thanks<br>
            </div>
            <div>Alex<br>
            </div>
          </div>
        </div>
        <div class="gmail_extra"><br>
          <div class="gmail_quote">On Thu, Feb 26, 2015 at 8:24 PM,
            Florian Fainelli <span dir="ltr"><<a
                moz-do-not-send="true"
                href="mailto:f.fainelli@gmail.com" target="_blank">f.fainelli@gmail.com</a>></span>
            wrote:<br>
            <blockquote class="gmail_quote" style="margin:0 0 0
              .8ex;border-left:1px #ccc solid;padding-left:1ex"><span
                class="">On 25/02/15 07:24, Alexandru Ardelean wrote:<br>
                > Feature implemented and tested on BCM53128.<br>
                ><br>
                > Slave devices logic copied from the Linux kernel
                from Marvell's DSA<br>
                > driver ( linux/net/dsa/ ).<br>
                > Also the logic for the Broadcom tag processing has
                been copied from there.<br>
                <br>
              </span>There are different efforts here going on, and I
              would like to at least<br>
              3 different people (you, Rafal and myself) can converge to
              an identical<br>
              solution that fits everybody here.<br>
              <br>
              What net-next supports today is:<br>
              <br>
              - broadcom tags in net/dsa/tag_brcm.c, 4-bytes format,
              identical to<br>
              yours AFAICT<br>
              - HW bridging support for bcm_sf2 (roboswitch successor)<br>
              <br>
              What's missing:<br>
              - adding VLAN configuration, which is what Rafal has been
              doing using<br>
              here: <a moz-do-not-send="true"
                href="http://thread.gmane.org/gmane.linux.network/351503"
                target="_blank">http://thread.gmane.org/gmane.linux.network/351503</a><br>
              <br>
              There are a number of things that I want to rework in DSA
              such that we<br>
              can almost immediately leverage OpenWrt's switch drivers,
              where the<br>
              entry point is a phy_driver, and have them register as
              switches (DSA or<br>
              something wider) eventually [1], such that DSA handles the
              slave devices<br>
              creation, and also handles the transmission/reception of
              Broadcom tags<br>
              for us. This is work in progress, but I expect the patches
              would be<br>
              ready by the end of this week.<br>
              <br>
              [1]: <a moz-do-not-send="true"
                href="http://www.spinics.net/lists/netdev/msg295942.html"
                target="_blank">http://www.spinics.net/lists/netdev/msg295942.html</a><br>
              <div class="HOEnZb">
                <div class="h5"><br>
                  ><br>
                  > OpenWRT's eth_mangle_rx/tx() patch/code is being
                  used to tap into<br>
                  > the packets to/from the ethernet chip since it's
                  convenient.<br>
                  ><br>
                  > This code will create lanX (X = 1..B53_N_PORTS)
                  devices.<br>
                  > All traffic from the ethX device will be
                  forwarded the proper lanX device.<br>
                  > So, sw_port0_traffic == lan1_traffic and so on.<br>
                  ><br>
                  > The slave devices logic has been put into it's
                  own file.<br>
                  > Should this logic be desired to be extended to
                  swconfig or other<br>
                  > switch chips, it should be convenient to just
                  move the slave.c/h files.<br>
                  ><br>
                  > Note: if enable_vlan == 1, be sure to configure
                  VLAN per lanX device<br>
                  >       in '/etc/config/network'<br>
                  ><br>
                  > Signed-off-by: Alexandru Ardelean <<a
                    moz-do-not-send="true"
                    href="mailto:ardeleanalex@gmail.com">ardeleanalex@gmail.com</a>><br>
                  > ---<br>
                  >  .../generic/files/drivers/net/phy/b53/Makefile 
                     |   2 +-<br>
                  > 
                  .../generic/files/drivers/net/phy/b53/b53_common.c | 
                   3 +<br>
                  >  .../generic/files/drivers/net/phy/b53/b53_hdr.c 
                    | 114 +++++++++++-<br>
                  > 
                  .../generic/files/drivers/net/phy/b53/b53_priv.h   | 
                   2 +<br>
                  >  .../generic/files/drivers/net/phy/b53/slave.c   
                    | 196 +++++++++++++++++++++<br>
                  >  .../generic/files/drivers/net/phy/b53/slave.h   
                    |  38 ++++<br>
                  >  6 files changed, 352 insertions(+), 3
                  deletions(-)<br>
                  >  create mode 100644
                  target/linux/generic/files/drivers/net/phy/b53/slave.c<br>
                  >  create mode 100644
                  target/linux/generic/files/drivers/net/phy/b53/slave.h<br>
                  ><br>
                  > diff --git
                  a/target/linux/generic/files/drivers/net/phy/b53/Makefile
b/target/linux/generic/files/drivers/net/phy/b53/Makefile<br>
                  > index 6c809f9..c74f82b 100644<br>
                  > ---
                  a/target/linux/generic/files/drivers/net/phy/b53/Makefile<br>
                  > +++
                  b/target/linux/generic/files/drivers/net/phy/b53/Makefile<br>
                  > @@ -1,5 +1,5 @@<br>
                  >  obj-$(CONFIG_B53)            += b53_common.o<br>
                  > -obj-$(CONFIG_B53_HDR)                +=
                  b53_hdr.o<br>
                  > +obj-$(CONFIG_B53_HDR)                +=
                  b53_hdr.o slave.o<br>
                  ><br>
                  >  obj-$(CONFIG_B53_PHY_FIXUP)  += b53_phy_fixup.o<br>
                  ><br>
                  > diff --git
                  a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c<br>
                  > index 9459b22..3da9efe 100644<br>
                  > ---
                  a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c<br>
                  > +++
                  b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c<br>
                  > @@ -1377,6 +1377,9 @@ static int
                  b53_global_reset_switch(struct switch_dev *dev)<br>
                  >       priv->enable_management = 0;<br>
                  >  #ifdef CONFIG_B53_HDR<br>
                  >       priv->enable_brcm_hdr = 0;<br>
                  > +     /* Call this function before the memset on
                  the priv->ports,<br>
                  > +      * otherwise we may leak devices */<br>
                  > +     b53_unregister_netdevs(priv);<br>
                  >  #endif<br>
                  ><br>
                  >       memset(priv->vlans, 0,
                  sizeof(priv->vlans) * dev->vlans);<br>
                  > diff --git
                  a/target/linux/generic/files/drivers/net/phy/b53/b53_hdr.c
b/target/linux/generic/files/drivers/net/phy/b53/b53_hdr.c<br>
                  > index 2a562a9..8fa7929 100644<br>
                  > ---
                  a/target/linux/generic/files/drivers/net/phy/b53/b53_hdr.c<br>
                  > +++
                  b/target/linux/generic/files/drivers/net/phy/b53/b53_hdr.c<br>
                  > @@ -21,14 +21,32 @@<br>
                  ><br>
                  >  #include "b53_regs.h"<br>
                  >  #include "b53_priv.h"<br>
                  > +#include "slave.h"<br>
                  ><br>
                  >  /* This tag length is 4 bytes, older ones were 6
                  bytes, we do not<br>
                  >   * handle them<br>
                  >   */<br>
                  >  #define BRCM_HDR_LEN    4<br>
                  >  #define MIN_FRAME_LEN   64<br>
                  > +#define BRCM_IG_DSTMAP2_MASK 1<br>
                  > +#define BRCM_IG_DSTMAP1_MASK 0xff<br>
                  > +#define BRCM_EG_PID_MASK     0x1f<br>
                  ><br>
                  > -static struct sk_buff *b53_mangle_tx(struct
                  net_device *dev, struct sk_buff *skb)<br>
                  > +/* Ingress and egress opcodes */<br>
                  > +#define BRCM_OPCODE_SHIFT   5<br>
                  > +<br>
                  > +static inline void b53_brcm_tag_set(struct
                  sk_buff *skb, int port_idx)<br>
                  > +{<br>
                  > +     u8 *brcm_tag = skb->data + 2 * ETH_ALEN;<br>
                  > +<br>
                  > +     brcm_tag[0] = (1 <<
                  BRCM_OPCODE_SHIFT);<br>
                  > +     brcm_tag[1] = 0;<br>
                  > +     brcm_tag[2] = (port_idx == 8) ?
                  BRCM_IG_DSTMAP2_MASK : 0;<br>
                  > +     brcm_tag[3] = (1 << port_idx) &
                  BRCM_IG_DSTMAP1_MASK;<br>
                  > +}<br>
                  > +<br>
                  > +static struct sk_buff *b53_mangle_tx_port(struct
                  net_device *dev,<br>
                  > +                     struct sk_buff *skb, struct
                  slave_priv* p)<br>
                  >  {<br>
                  >       if (unlikely(skb_headroom(skb) <
                  BRCM_HDR_LEN)) {<br>
                  >               if (pskb_expand_head(skb,
                  BRCM_HDR_LEN, 0, GFP_ATOMIC) < 0)<br>
                  > @@ -40,7 +58,20 @@ static struct sk_buff
                  *b53_mangle_tx(struct net_device *dev, struct sk_buff
                  *skb<br>
                  >       memmove(skb->data, skb->data +
                  BRCM_HDR_LEN, 2 * ETH_ALEN);<br>
                  ><br>
                  >       /* Build the tag after the MAC Source
                  Address */<br>
                  > -     memset(skb->data + 2 * ETH_ALEN, 0,
                  BRCM_HDR_LEN);<br>
                  > +     if (!p) {<br>
                  > +             memset(skb->data + 2 * ETH_ALEN,
                  0, BRCM_HDR_LEN);<br>
                  > +     } else {<br>
                  > +             /* Register some TX stats for this
                  device before<br>
                  > +              * passing the skb to the parent
                  device */<br>
                  > +             dev->stats.tx_packets++;<br>
                  > +             dev->stats.tx_bytes +=
                  skb->len;<br>
                  > +<br>
                  > +             b53_brcm_tag_set(skb,
                  p->port_idx);<br>
                  > +<br>
                  > +             skb->dev = p->parent_dev;<br>
                  > +             skb->protocol =
                  htons(ETH_P_DSA);<br>
                  > +     }<br>
                  > +<br>
                  >  #ifdef CONFIG_B53_HDR_TX_SW_PADDING<br>
                  >       /* FIXME: we're doing some padding here for
                  runt ( < 64 bytes) packets;<br>
                  >        *        some drivers/hw refuse to add hw
                  padding for us after we add<br>
                  > @@ -64,12 +95,88 @@ out_err:<br>
                  >       return NULL;<br>
                  >  }<br>
                  ><br>
                  > +static struct sk_buff *b53_mangle_tx(struct
                  net_device *dev, struct sk_buff *skb)<br>
                  > +{<br>
                  > +     /* The b53_mangle_tx() function can get
                  called twice now that there are<br>
                  > +      * slave devices: once for the lanX device,
                  and one for the ethY device<br>
                  > +      * which means that the Broadcom Header
                  would get added twice.<br>
                  > +      * Which is why the packet type has been
                  marked by the slave lanX device<br>
                  > +      * to tell us that we've tagged this packet
                  already. */<br>
                  > +     if (unlikely(skb->protocol ==
                  htons(ETH_P_DSA)))<br>
                  > +             return skb;<br>
                  > +     return b53_mangle_tx_port(dev, skb, NULL);<br>
                  > +}<br>
                  > +<br>
                  >  static void b53_mangle_rx(struct net_device
                  *dev, struct sk_buff *skb)<br>
                  >  {<br>
                  > +     struct b53_device *p = dev->phy_ptr;<br>
                  > +     u8 *brcm_tag;<br>
                  > +     u8 source_port;<br>
                  > +<br>
                  > +     /* We're only interested in the 4th byte of
                  the Broadcom Header right now */<br>
                  > +     brcm_tag = skb->data + (2 * ETH_ALEN) +
                  3;<br>
                  > +     source_port = *brcm_tag &
                  BRCM_EG_PID_MASK;<br>
                  > +<br>
                  >       skb_pull(skb, BRCM_HDR_LEN);<br>
                  >       memmove(skb->data,<br>
                  >               skb->data - BRCM_HDR_LEN,<br>
                  >               2 * ETH_ALEN);<br>
                  > +<br>
                  > +     if ((source_port < B53_N_PORTS)
                  && (p->ports[source_port].port_dev)) {<br>
                  > +             skb->dev =
                  p->ports[source_port].port_dev;<br>
                  > +             skb->dev->stats.rx_packets++;<br>
                  > +             skb->dev->stats.rx_bytes +=
                  skb->len;<br>
                  > +     }<br>
                  > +}<br>
                  > +<br>
                  > +static void b53_register_netdevs(struct
                  b53_device *dev)<br>
                  > +{<br>
                  > +     int i;<br>
                  > +     bool unlock = false;<br>
                  > +<br>
                  > +     if (!rtnl_is_locked()) {<br>
                  > +             rtnl_lock();<br>
                  > +             unlock = true;<br>
                  > +     }<br>
                  > +     b53_for_each_port(dev, i) {<br>
                  > +             if (is_cpu_port(dev, i))<br>
                  > +                     continue;<br>
                  > +             if (!(dev->enabled_ports &
                  BIT(i))) {<br>
                  > +                     if
                  (dev->ports[i].port_dev) {<br>
                  > +                           
                   unregister_netdevice(dev->ports[i].port_dev);<br>
                  > +                           
                   dev->ports[i].port_dev = NULL;<br>
                  > +                     }<br>
                  > +                     continue;<br>
                  > +             }<br>
                  > +             /* Check if devices already exist
                  for these devices */<br>
                  > +             if (!dev->ports[i].port_dev
                  &&<br>
                  > +                 !(dev->ports[i].port_dev =
                  slave_create(dev->eth_dev, i, b53_mangle_tx_port)))
                  {<br>
                  > +                     pr_warn("%s: can't create
                  slave device for port %d\n",<br>
                  > +                             dev-><a
                    moz-do-not-send="true" href="http://sw_dev.name"
                    target="_blank">sw_dev.name</a>, i);<br>
                  > +                     continue;<br>
                  > +             }<br>
                  > +     }<br>
                  > +     if (unlock)<br>
                  > +             rtnl_unlock();<br>
                  > +}<br>
                  > +<br>
                  > +void b53_unregister_netdevs(struct b53_device
                  *dev)<br>
                  > +{<br>
                  > +     int i;<br>
                  > +     bool unlock = false;<br>
                  > +<br>
                  > +     if (!rtnl_is_locked()) {<br>
                  > +             rtnl_lock();<br>
                  > +             unlock = true;<br>
                  > +     }<br>
                  > +     b53_for_each_port(dev, i) {<br>
                  > +             if (!dev->ports[i].port_dev)<br>
                  > +                     continue;<br>
                  > +           
                   unregister_netdevice(dev->ports[i].port_dev);<br>
                  > +             dev->ports[i].port_dev = NULL;<br>
                  > +     }<br>
                  > +     if (unlock)<br>
                  > +             rtnl_unlock();<br>
                  >  }<br>
                  ><br>
                  >  void b53_enable_brcm_hdr(struct b53_device *dev)<br>
                  > @@ -86,6 +193,7 @@ void
                  b53_enable_brcm_hdr(struct b53_device *dev)<br>
                  >       }<br>
                  >       brcm_hdr_ctrl &= ~B53_BRCM_HDR_EN;<br>
                  >       if (!dev->eth_dev) {<br>
                  > +             b53_unregister_netdevs(dev);<br>
                  >               goto out;<br>
                  >       }<br>
                  ><br>
                  > @@ -93,6 +201,8 @@ void
                  b53_enable_brcm_hdr(struct b53_device *dev)<br>
                  >       if (!dev->enable_management)<br>
                  >               goto out;<br>
                  ><br>
                  > +     pr_info("%s: registering lan devices\n",
                  dev-><a moz-do-not-send="true"
                    href="http://sw_dev.name" target="_blank">sw_dev.name</a>);<br>
                  > +     b53_register_netdevs(dev);<br>
                  >       dev->eth_dev->phy_ptr = dev;<br>
                  >       dev->eth_dev->priv_flags |=
                  IFF_NO_IP_ALIGN;<br>
                  >       dev->eth_dev->eth_mangle_rx =
                  b53_mangle_rx;<br>
                  > diff --git
                  a/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
b/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h<br>
                  > index f487bf2..167e042 100644<br>
                  > ---
                  a/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h<br>
                  > +++
                  b/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h<br>
                  > @@ -359,8 +359,10 @@ int
                  b53_global_get_brcm_hdr(struct switch_dev *dev,<br>
                  >  int b53_global_set_brcm_hdr(struct switch_dev
                  *dev,<br>
                  >               const struct switch_attr *attr,<br>
                  >               struct switch_val *val);<br>
                  > +void b53_unregister_netdevs(struct b53_device
                  *dev);<br>
                  >  #else<br>
                  >  #define b53_enable_brcm_hdr(x)<br>
                  > +#define b53_unregister_netdevs(x)<br>
                  >  #endif<br>
                  ><br>
                  >  #ifdef CONFIG_BCM47XX<br>
                  > diff --git
                  a/target/linux/generic/files/drivers/net/phy/b53/slave.c
b/target/linux/generic/files/drivers/net/phy/b53/slave.c<br>
                  > new file mode 100644<br>
                  > index 0000000..b8cd2dc<br>
                  > --- /dev/null<br>
                  > +++
                  b/target/linux/generic/files/drivers/net/phy/b53/slave.c<br>
                  > @@ -0,0 +1,196 @@<br>
                  > +/*<br>
                  > + * Slave devices logic.<br>
                  > + * Adapted/copied from the Linux kernel DSA
                  driver (net/dsa).<br>
                  > + *<br>
                  > + * Permission to use, copy, modify, and/or
                  distribute this software for any<br>
                  > + * purpose with or without fee is hereby
                  granted, provided that the above<br>
                  > + * copyright notice and this permission notice
                  appear in all copies.<br>
                  > + *<br>
                  > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE
                  AUTHOR DISCLAIMS ALL WARRANTIES<br>
                  > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL
                  IMPLIED WARRANTIES OF<br>
                  > + * MERCHANTABILITY AND FITNESS. IN NO EVENT
                  SHALL THE AUTHOR BE LIABLE FOR<br>
                  > + * ANY SPECIAL, DIRECT, INDIRECT, OR
                  CONSEQUENTIAL DAMAGES OR ANY DAMAGES<br>
                  > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA
                  OR PROFITS, WHETHER IN AN<br>
                  > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER
                  TORTIOUS ACTION, ARISING OUT OF<br>
                  > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE
                  OF THIS SOFTWARE.<br>
                  > + */<br>
                  > +<br>
                  > +#include <linux/rtnetlink.h><br>
                  > +#include <linux/etherdevice.h><br>
                  > +<br>
                  > +#include "slave.h"<br>
                  > +<br>
                  > +static int slave_init(struct net_device *dev)<br>
                  > +{<br>
                  > +     struct slave_priv *p = netdev_priv(dev);<br>
                  > +     dev->iflink =
                  p->parent_dev->ifindex;<br>
                  > +     return 0;<br>
                  > +}<br>
                  > +<br>
                  > +static int slave_open(struct net_device *dev)<br>
                  > +{<br>
                  > +     struct slave_priv *p = netdev_priv(dev);<br>
                  > +     struct net_device *parent =
                  p->parent_dev;<br>
                  > +     int err;<br>
                  > +<br>
                  > +     if (!(parent->flags & IFF_UP))<br>
                  > +             return -ENETDOWN;<br>
                  > +<br>
                  > +     if (!ether_addr_equal(dev->dev_addr,
                  parent->dev_addr)) {<br>
                  > +             err = dev_uc_add(parent,
                  dev->dev_addr);<br>
                  > +             if (err < 0)<br>
                  > +                     goto out;<br>
                  > +     }<br>
                  > +<br>
                  > +     if (dev->flags & IFF_ALLMULTI) {<br>
                  > +             err = dev_set_allmulti(parent, 1);<br>
                  > +             if (err < 0)<br>
                  > +                     goto del_unicast;<br>
                  > +     }<br>
                  > +     if (dev->flags & IFF_PROMISC) {<br>
                  > +             err = dev_set_promiscuity(parent,
                  1);<br>
                  > +             if (err < 0)<br>
                  > +                     goto clear_allmulti;<br>
                  > +     }<br>
                  > +<br>
                  > +     return 0;<br>
                  > +<br>
                  > +clear_allmulti:<br>
                  > +     if (dev->flags & IFF_ALLMULTI)<br>
                  > +             dev_set_allmulti(parent, -1);<br>
                  > +del_unicast:<br>
                  > +     if (!ether_addr_equal(dev->dev_addr,
                  parent->dev_addr))<br>
                  > +             dev_uc_del(parent,
                  dev->dev_addr);<br>
                  > +out:<br>
                  > +     return err;<br>
                  > +}<br>
                  > +<br>
                  > +static int slave_close(struct net_device *dev)<br>
                  > +{<br>
                  > +     struct slave_priv *p = netdev_priv(dev);<br>
                  > +     struct net_device *parent =
                  p->parent_dev;<br>
                  > +<br>
                  > +     dev_mc_unsync(parent, dev);<br>
                  > +     dev_uc_unsync(parent, dev);<br>
                  > +     if (dev->flags & IFF_ALLMULTI)<br>
                  > +             dev_set_allmulti(parent, -1);<br>
                  > +     if (dev->flags & IFF_PROMISC)<br>
                  > +             dev_set_promiscuity(parent, -1);<br>
                  > +<br>
                  > +     if (!ether_addr_equal(dev->dev_addr,
                  parent->dev_addr))<br>
                  > +             dev_uc_del(parent,
                  dev->dev_addr);<br>
                  > +<br>
                  > +     return 0;<br>
                  > +}<br>
                  > +<br>
                  > +static void slave_change_rx_flags(struct
                  net_device *dev, int change)<br>
                  > +{<br>
                  > +    struct slave_priv *p = netdev_priv(dev);<br>
                  > +     struct net_device *parent =
                  p->parent_dev;<br>
                  > +<br>
                  > +     if (change & IFF_ALLMULTI)<br>
                  > +             dev_set_allmulti(parent,
                  dev->flags & IFF_ALLMULTI ? 1 : -1);<br>
                  > +     if (change & IFF_PROMISC)<br>
                  > +             dev_set_promiscuity(parent,
                  dev->flags & IFF_PROMISC ? 1 : -1);<br>
                  > +}<br>
                  > +<br>
                  > +static void slave_set_rx_mode(struct net_device
                  *dev)<br>
                  > +{<br>
                  > +     struct slave_priv *p = netdev_priv(dev);<br>
                  > +     struct net_device *parent =
                  p->parent_dev;<br>
                  > +<br>
                  > +     dev_mc_sync(parent, dev);<br>
                  > +     dev_uc_sync(parent, dev);<br>
                  > +}<br>
                  > +<br>
                  > +static int slave_set_mac_address(struct
                  net_device *dev, void *a)<br>
                  > +{<br>
                  > +     struct slave_priv *p = netdev_priv(dev);<br>
                  > +     struct net_device *parent =
                  p->parent_dev;<br>
                  > +     struct sockaddr *addr = a;<br>
                  > +     int err;<br>
                  > +<br>
                  > +     if (!is_valid_ether_addr(addr->sa_data))<br>
                  > +             return -EADDRNOTAVAIL;<br>
                  > +<br>
                  > +     if (!(dev->flags & IFF_UP))<br>
                  > +             goto out;<br>
                  > +<br>
                  > +     if (!ether_addr_equal(addr->sa_data,
                  parent->dev_addr)) {<br>
                  > +             err = dev_uc_add(parent,
                  addr->sa_data);<br>
                  > +             if (err < 0)<br>
                  > +                     return err;<br>
                  > +     }<br>
                  > +<br>
                  > +     if (!ether_addr_equal(dev->dev_addr,
                  parent->dev_addr))<br>
                  > +             dev_uc_del(parent,
                  dev->dev_addr);<br>
                  > +<br>
                  > +out:<br>
                  > +     memcpy(dev->dev_addr, addr->sa_data,
                  ETH_ALEN);<br>
                  > +<br>
                  > +     return 0;<br>
                  > +}<br>
                  > +<br>
                  > +static netdev_tx_t slave_xmit(struct sk_buff
                  *skb, struct net_device *dev)<br>
                  > +{<br>
                  > +     struct slave_priv *p = netdev_priv(dev);<br>
                  > +<br>
                  > +     skb->dev = p->parent_dev;<br>
                  > +     skb = p->eth_mangle_tx_port(dev, skb,
                  p);<br>
                  > +     dev_queue_xmit(skb);<br>
                  > +<br>
                  > +     return NETDEV_TX_OK;<br>
                  > +}<br>
                  > +<br>
                  > +static const struct net_device_ops
                  slave_netdev_ops = {<br>
                  > +     .ndo_init               = slave_init,<br>
                  > +     .ndo_open               = slave_open,<br>
                  > +     .ndo_stop               = slave_close,<br>
                  > +     .ndo_start_xmit         = slave_xmit,<br>
                  > +     .ndo_change_rx_flags    =
                  slave_change_rx_flags,<br>
                  > +     .ndo_set_rx_mode        =
                  slave_set_rx_mode,<br>
                  > +     .ndo_set_mac_address    =
                  slave_set_mac_address,<br>
                  > +};<br>
                  > +<br>
                  > +struct net_device *slave_create(struct
                  net_device *parent, int port,<br>
                  > +             eth_mangle_tx_port_t
                  eth_mangle_tx_port)<br>
                  > +{<br>
                  > +     /* Parent dev should not be null according
                  to the code path below */<br>
                  > +     struct net_device *slave_dev = NULL;<br>
                  > +     struct slave_priv *p;<br>
                  > +     char port_name[] = "lan1000";<br>
                  > +<br>
                  > +     snprintf(port_name, sizeof(port_name),
                  "lan%d", (port + 1));<br>
                  > +     slave_dev = alloc_netdev(sizeof(struct
                  slave_priv),<br>
                  > +                 port_name, ether_setup);<br>
                  > +     if (!slave_dev) {<br>
                  > +             pr_err("Failed to allocate memory
                  for slave device");<br>
                  > +             goto out;<br>
                  > +     }<br>
                  > +<br>
                  > +     slave_dev->features =
                  parent->vlan_features;<br>
                  > +     eth_hw_addr_inherit(slave_dev, parent);<br>
                  > +     slave_dev->tx_queue_len = 0;<br>
                  > +     slave_dev->netdev_ops =
                  &slave_netdev_ops;<br>
                  > +<br>
                  > +     SET_NETDEV_DEV(slave_dev,
                  &parent->dev);<br>
                  > +     slave_dev->vlan_features =
                  parent->vlan_features;<br>
                  > +<br>
                  > +     p = netdev_priv(slave_dev);<br>
                  > +     p->parent_dev = parent;<br>
                  > +     p->port_dev   = slave_dev;<br>
                  > +     p->port_idx   = port;<br>
                  > +     p->eth_mangle_tx_port =
                  eth_mangle_tx_port;<br>
                  > +<br>
                  > +     if (register_netdevice(slave_dev)) {<br>
                  > +             free_netdev(slave_dev);<br>
                  > +             slave_dev = NULL;<br>
                  > +             goto out;<br>
                  > +     }<br>
                  > +<br>
                  > +     netif_carrier_on(slave_dev);<br>
                  > +<br>
                  > +out:<br>
                  > +     return slave_dev;<br>
                  > +}<br>
                  > +<br>
                  > diff --git
                  a/target/linux/generic/files/drivers/net/phy/b53/slave.h
b/target/linux/generic/files/drivers/net/phy/b53/slave.h<br>
                  > new file mode 100644<br>
                  > index 0000000..3cfe7c7<br>
                  > --- /dev/null<br>
                  > +++
                  b/target/linux/generic/files/drivers/net/phy/b53/slave.h<br>
                  > @@ -0,0 +1,38 @@<br>
                  > +/*<br>
                  > + * Slave devices logic.<br>
                  > + * Adapted/copied from the Linux kernel DSA
                  driver (net/dsa).<br>
                  > + *<br>
                  > + * Permission to use, copy, modify, and/or
                  distribute this software for any<br>
                  > + * purpose with or without fee is hereby
                  granted, provided that the above<br>
                  > + * copyright notice and this permission notice
                  appear in all copies.<br>
                  > + *<br>
                  > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE
                  AUTHOR DISCLAIMS ALL WARRANTIES<br>
                  > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL
                  IMPLIED WARRANTIES OF<br>
                  > + * MERCHANTABILITY AND FITNESS. IN NO EVENT
                  SHALL THE AUTHOR BE LIABLE FOR<br>
                  > + * ANY SPECIAL, DIRECT, INDIRECT, OR
                  CONSEQUENTIAL DAMAGES OR ANY DAMAGES<br>
                  > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA
                  OR PROFITS, WHETHER IN AN<br>
                  > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER
                  TORTIOUS ACTION, ARISING OUT OF<br>
                  > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE
                  OF THIS SOFTWARE.<br>
                  > + */<br>
                  > +<br>
                  > +#ifndef __SLAVE_H__<br>
                  > +#define __SLAVE_H__<br>
                  > +<br>
                  > +#include <linux/etherdevice.h><br>
                  > +<br>
                  > +struct slave_priv;<br>
                  > +typedef struct sk_buff
                  *(*eth_mangle_tx_port_t)(struct net_device *dev,<br>
                  > +             struct sk_buff *skb, struct
                  slave_priv* p);<br>
                  > +<br>
                  > +struct slave_priv {<br>
                  > +     struct net_device *parent_dev;<br>
                  > +     struct net_device *port_dev;<br>
                  > +     eth_mangle_tx_port_t eth_mangle_tx_port;<br>
                  > +     int port_idx;<br>
                  > +};<br>
                  > +<br>
                  > +/* For the moment, the rtnl_lock() needs to be
                  called by the caller */<br>
                  > +struct net_device *slave_create(struct
                  net_device *parent, int port,<br>
                  > +             eth_mangle_tx_port_t
                  eth_mangle_tx_port);<br>
                  > +<br>
                  > +#endif /* __SLAVE_H__ */<br>
                  ><br>
                  <br>
                  <br>
                  --<br>
                </div>
              </div>
              <span class="HOEnZb"><font color="#888888">Florian<br>
                </font></span></blockquote>
          </div>
          <br>
        </div>
      </div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <br>
      <pre wrap="">_______________________________________________
openwrt-devel mailing list
<a class="moz-txt-link-abbreviated" href="mailto:openwrt-devel@lists.openwrt.org">openwrt-devel@lists.openwrt.org</a>
<a class="moz-txt-link-freetext" href="https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel">https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel</a>
</pre>
    </blockquote>
    <br>
  </body>
</html>