Merge tag 'char-misc-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
[linux-2.6-microblaze.git] / net / dsa / tag_sja1105.c
index 9c2df9e..c054f48 100644 (file)
@@ -115,56 +115,117 @@ static inline bool sja1105_is_meta_frame(const struct sk_buff *skb)
        return true;
 }
 
-static bool sja1105_can_use_vlan_as_tags(const struct sk_buff *skb)
+/* Calls sja1105_port_deferred_xmit in sja1105_main.c */
+static struct sk_buff *sja1105_defer_xmit(struct dsa_port *dp,
+                                         struct sk_buff *skb)
 {
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
-       u16 vlan_tci;
-
-       if (hdr->h_vlan_proto == htons(ETH_P_SJA1105))
-               return true;
+       struct sja1105_port *sp = dp->priv;
 
-       if (hdr->h_vlan_proto != htons(ETH_P_8021Q) &&
-           !skb_vlan_tag_present(skb))
-               return false;
+       if (!dsa_port_is_sja1105(dp))
+               return skb;
 
-       if (skb_vlan_tag_present(skb))
-               vlan_tci = skb_vlan_tag_get(skb);
-       else
-               vlan_tci = ntohs(hdr->h_vlan_TCI);
+       /* Increase refcount so the kfree_skb in dsa_slave_xmit
+        * won't really free the packet.
+        */
+       skb_queue_tail(&sp->xmit_queue, skb_get(skb));
+       kthread_queue_work(sp->xmit_worker, &sp->xmit_work);
 
-       return vid_is_dsa_8021q(vlan_tci & VLAN_VID_MASK);
+       return NULL;
 }
 
-/* This is the first time the tagger sees the frame on RX.
- * Figure out if we can decode it.
+/* Send VLAN tags with a TPID that blends in with whatever VLAN protocol a
+ * bridge spanning ports of this switch might have.
  */
-static bool sja1105_filter(const struct sk_buff *skb, struct net_device *dev)
+static u16 sja1105_xmit_tpid(struct dsa_port *dp)
 {
-       if (sja1105_can_use_vlan_as_tags(skb))
-               return true;
-       if (sja1105_is_link_local(skb))
-               return true;
-       if (sja1105_is_meta_frame(skb))
-               return true;
-       return false;
+       struct dsa_switch *ds = dp->ds;
+       struct dsa_port *other_dp;
+       u16 proto;
+
+       /* Since VLAN awareness is global, then if this port is VLAN-unaware,
+        * all ports are. Use the VLAN-unaware TPID used for tag_8021q.
+        */
+       if (!dsa_port_is_vlan_filtering(dp))
+               return ETH_P_SJA1105;
+
+       /* Port is VLAN-aware, so there is a bridge somewhere (a single one,
+        * we're sure about that). It may not be on this port though, so we
+        * need to find it.
+        */
+       list_for_each_entry(other_dp, &ds->dst->ports, list) {
+               if (other_dp->ds != ds)
+                       continue;
+
+               if (!other_dp->bridge_dev)
+                       continue;
+
+               /* Error is returned only if CONFIG_BRIDGE_VLAN_FILTERING,
+                * which seems pointless to handle, as our port cannot become
+                * VLAN-aware in that case.
+                */
+               br_vlan_get_proto(other_dp->bridge_dev, &proto);
+
+               return proto;
+       }
+
+       WARN_ONCE(1, "Port is VLAN-aware but cannot find associated bridge!\n");
+
+       return ETH_P_SJA1105;
 }
 
-/* Calls sja1105_port_deferred_xmit in sja1105_main.c */
-static struct sk_buff *sja1105_defer_xmit(struct sja1105_port *sp,
-                                         struct sk_buff *skb)
+static struct sk_buff *sja1105_imprecise_xmit(struct sk_buff *skb,
+                                             struct net_device *netdev)
 {
-       /* Increase refcount so the kfree_skb in dsa_slave_xmit
-        * won't really free the packet.
+       struct dsa_port *dp = dsa_slave_to_port(netdev);
+       struct net_device *br = dp->bridge_dev;
+       u16 tx_vid;
+
+       /* If the port is under a VLAN-aware bridge, just slide the
+        * VLAN-tagged packet into the FDB and hope for the best.
+        * This works because we support a single VLAN-aware bridge
+        * across the entire dst, and its VLANs cannot be shared with
+        * any standalone port.
         */
-       skb_queue_tail(&sp->xmit_queue, skb_get(skb));
-       kthread_queue_work(sp->xmit_worker, &sp->xmit_work);
+       if (br_vlan_enabled(br))
+               return skb;
 
-       return NULL;
+       /* If the port is under a VLAN-unaware bridge, use an imprecise
+        * TX VLAN that targets the bridge's entire broadcast domain,
+        * instead of just the specific port.
+        */
+       tx_vid = dsa_8021q_bridge_tx_fwd_offload_vid(dp->bridge_num);
+
+       return dsa_8021q_xmit(skb, netdev, sja1105_xmit_tpid(dp), tx_vid);
 }
 
-static u16 sja1105_xmit_tpid(struct sja1105_port *sp)
+/* Transform untagged control packets into pvid-tagged control packets so that
+ * all packets sent by this tagger are VLAN-tagged and we can configure the
+ * switch to drop untagged packets coming from the DSA master.
+ */
+static struct sk_buff *sja1105_pvid_tag_control_pkt(struct dsa_port *dp,
+                                                   struct sk_buff *skb, u8 pcp)
 {
-       return sp->xmit_tpid;
+       __be16 xmit_tpid = htons(sja1105_xmit_tpid(dp));
+       struct vlan_ethhdr *hdr;
+
+       /* If VLAN tag is in hwaccel area, move it to the payload
+        * to deal with both cases uniformly and to ensure that
+        * the VLANs are added in the right order.
+        */
+       if (unlikely(skb_vlan_tag_present(skb))) {
+               skb = __vlan_hwaccel_push_inside(skb);
+               if (!skb)
+                       return NULL;
+       }
+
+       hdr = (struct vlan_ethhdr *)skb_mac_header(skb);
+
+       /* If skb is already VLAN-tagged, leave that VLAN ID in place */
+       if (hdr->h_vlan_proto == xmit_tpid)
+               return skb;
+
+       return vlan_insert_tag(skb, xmit_tpid, (pcp << VLAN_PRIO_SHIFT) |
+                              SJA1105_DEFAULT_VLAN);
 }
 
 static struct sk_buff *sja1105_xmit(struct sk_buff *skb,
@@ -175,14 +236,22 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb,
        u16 queue_mapping = skb_get_queue_mapping(skb);
        u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
 
+       if (skb->offload_fwd_mark)
+               return sja1105_imprecise_xmit(skb, netdev);
+
        /* Transmitting management traffic does not rely upon switch tagging,
         * but instead SPI-installed management routes. Part 2 of this
         * is the .port_deferred_xmit driver callback.
         */
-       if (unlikely(sja1105_is_link_local(skb)))
-               return sja1105_defer_xmit(dp->priv, skb);
+       if (unlikely(sja1105_is_link_local(skb))) {
+               skb = sja1105_pvid_tag_control_pkt(dp, skb, pcp);
+               if (!skb)
+                       return NULL;
+
+               return sja1105_defer_xmit(dp, skb);
+       }
 
-       return dsa_8021q_xmit(skb, netdev, sja1105_xmit_tpid(dp->priv),
+       return dsa_8021q_xmit(skb, netdev, sja1105_xmit_tpid(dp),
                             ((pcp << VLAN_PRIO_SHIFT) | tx_vid));
 }
 
@@ -194,43 +263,45 @@ static struct sk_buff *sja1110_xmit(struct sk_buff *skb,
        u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
        u16 queue_mapping = skb_get_queue_mapping(skb);
        u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
-       struct ethhdr *eth_hdr;
        __be32 *tx_trailer;
        __be16 *tx_header;
        int trailer_pos;
 
+       if (skb->offload_fwd_mark)
+               return sja1105_imprecise_xmit(skb, netdev);
+
        /* Transmitting control packets is done using in-band control
         * extensions, while data packets are transmitted using
         * tag_8021q TX VLANs.
         */
        if (likely(!sja1105_is_link_local(skb)))
-               return dsa_8021q_xmit(skb, netdev, sja1105_xmit_tpid(dp->priv),
+               return dsa_8021q_xmit(skb, netdev, sja1105_xmit_tpid(dp),
                                     ((pcp << VLAN_PRIO_SHIFT) | tx_vid));
 
+       skb = sja1105_pvid_tag_control_pkt(dp, skb, pcp);
+       if (!skb)
+               return NULL;
+
        skb_push(skb, SJA1110_HEADER_LEN);
 
-       /* Move Ethernet header to the left, making space for DSA tag */
-       memmove(skb->data, skb->data + SJA1110_HEADER_LEN, 2 * ETH_ALEN);
+       dsa_alloc_etype_header(skb, SJA1110_HEADER_LEN);
 
        trailer_pos = skb->len;
 
-       /* On TX, skb->data points to skb_mac_header(skb) */
-       eth_hdr = (struct ethhdr *)skb->data;
-       tx_header = (__be16 *)(eth_hdr + 1);
+       tx_header = dsa_etype_header_pos_tx(skb);
        tx_trailer = skb_put(skb, SJA1110_TX_TRAILER_LEN);
 
-       eth_hdr->h_proto = htons(ETH_P_SJA1110);
-
-       *tx_header = htons(SJA1110_HEADER_HOST_TO_SWITCH |
-                          SJA1110_TX_HEADER_HAS_TRAILER |
-                          SJA1110_TX_HEADER_TRAILER_POS(trailer_pos));
+       tx_header[0] = htons(ETH_P_SJA1110);
+       tx_header[1] = htons(SJA1110_HEADER_HOST_TO_SWITCH |
+                            SJA1110_TX_HEADER_HAS_TRAILER |
+                            SJA1110_TX_HEADER_TRAILER_POS(trailer_pos));
        *tx_trailer = cpu_to_be32(SJA1110_TX_TRAILER_PRIO(pcp) |
                                  SJA1110_TX_TRAILER_SWITCHID(dp->ds->index) |
                                  SJA1110_TX_TRAILER_DESTPORTS(BIT(dp->index)));
        if (clone) {
                u8 ts_id = SJA1105_SKB_CB(clone)->ts_id;
 
-               *tx_header |= htons(SJA1110_TX_HEADER_TAKE_TS);
+               tx_header[1] |= htons(SJA1110_TX_HEADER_TAKE_TS);
                *tx_trailer |= cpu_to_be32(SJA1110_TX_TRAILER_TSTAMP_ID(ts_id));
        }
 
@@ -273,16 +344,16 @@ static struct sk_buff
                                bool is_link_local,
                                bool is_meta)
 {
-       struct sja1105_port *sp;
-       struct dsa_port *dp;
-
-       dp = dsa_slave_to_port(skb->dev);
-       sp = dp->priv;
-
        /* Step 1: A timestampable frame was received.
         * Buffer it until we get its meta frame.
         */
        if (is_link_local) {
+               struct dsa_port *dp = dsa_slave_to_port(skb->dev);
+               struct sja1105_port *sp = dp->priv;
+
+               if (unlikely(!dsa_port_is_sja1105(dp)))
+                       return skb;
+
                if (!test_bit(SJA1105_HWTS_RX_EN, &sp->data->state))
                        /* Do normal processing. */
                        return skb;
@@ -315,8 +386,13 @@ static struct sk_buff
         * frame, which serves no further purpose).
         */
        } else if (is_meta) {
+               struct dsa_port *dp = dsa_slave_to_port(skb->dev);
+               struct sja1105_port *sp = dp->priv;
                struct sk_buff *stampable_skb;
 
+               if (unlikely(!dsa_port_is_sja1105(dp)))
+                       return skb;
+
                /* Drop the meta frame if we're not in the right state
                 * to process it.
                 */
@@ -358,20 +434,6 @@ static struct sk_buff
        return skb;
 }
 
-static void sja1105_decode_subvlan(struct sk_buff *skb, u16 subvlan)
-{
-       struct dsa_port *dp = dsa_slave_to_port(skb->dev);
-       struct sja1105_port *sp = dp->priv;
-       u16 vid = sp->subvlan_map[subvlan];
-       u16 vlan_tci;
-
-       if (vid == VLAN_N_VID)
-               return;
-
-       vlan_tci = (skb->priority << VLAN_PRIO_SHIFT) | vid;
-       __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
-}
-
 static bool sja1105_skb_has_tag_8021q(const struct sk_buff *skb)
 {
        u16 tpid = ntohs(eth_hdr(skb)->h_proto);
@@ -385,25 +447,45 @@ static bool sja1110_skb_has_inband_control_extension(const struct sk_buff *skb)
        return ntohs(eth_hdr(skb)->h_proto) == ETH_P_SJA1110;
 }
 
+/* If the VLAN in the packet is a tag_8021q one, set @source_port and
+ * @switch_id and strip the header. Otherwise set @vid and keep it in the
+ * packet.
+ */
+static void sja1105_vlan_rcv(struct sk_buff *skb, int *source_port,
+                            int *switch_id, u16 *vid)
+{
+       struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)skb_mac_header(skb);
+       u16 vlan_tci;
+
+       if (skb_vlan_tag_present(skb))
+               vlan_tci = skb_vlan_tag_get(skb);
+       else
+               vlan_tci = ntohs(hdr->h_vlan_TCI);
+
+       if (vid_is_dsa_8021q_rxvlan(vlan_tci & VLAN_VID_MASK))
+               return dsa_8021q_rcv(skb, source_port, switch_id);
+
+       /* Try our best with imprecise RX */
+       *vid = vlan_tci & VLAN_VID_MASK;
+}
+
 static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
-                                  struct net_device *netdev,
-                                  struct packet_type *pt)
+                                  struct net_device *netdev)
 {
-       int source_port, switch_id, subvlan = 0;
+       int source_port = -1, switch_id = -1;
        struct sja1105_meta meta = {0};
        struct ethhdr *hdr;
        bool is_link_local;
        bool is_meta;
+       u16 vid;
 
        hdr = eth_hdr(skb);
        is_link_local = sja1105_is_link_local(skb);
        is_meta = sja1105_is_meta_frame(skb);
 
-       skb->offload_fwd_mark = 1;
-
        if (sja1105_skb_has_tag_8021q(skb)) {
                /* Normal traffic path. */
-               dsa_8021q_rcv(skb, &source_port, &switch_id, &subvlan);
+               sja1105_vlan_rcv(skb, &source_port, &switch_id, &vid);
        } else if (is_link_local) {
                /* Management traffic path. Switch embeds the switch ID and
                 * port ID into bytes of the destination MAC, courtesy of
@@ -422,14 +504,17 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
                return NULL;
        }
 
-       skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);
+       if (source_port == -1 || switch_id == -1)
+               skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid);
+       else
+               skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);
        if (!skb->dev) {
                netdev_warn(netdev, "Couldn't decode source port\n");
                return NULL;
        }
 
-       if (subvlan)
-               sja1105_decode_subvlan(skb, subvlan);
+       if (!is_link_local)
+               dsa_default_offload_fwd_mark(skb);
 
        return sja1105_rcv_meta_state_machine(skb, &meta, is_link_local,
                                              is_meta);
@@ -437,11 +522,11 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
 
 static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header)
 {
+       u8 *buf = dsa_etype_header_pos_rx(skb) + SJA1110_HEADER_LEN;
        int switch_id = SJA1110_RX_HEADER_SWITCH_ID(rx_header);
        int n_ts = SJA1110_RX_HEADER_N_TS(rx_header);
        struct net_device *master = skb->dev;
        struct dsa_port *cpu_dp;
-       u8 *buf = skb->data + 2;
        struct dsa_switch *ds;
        int i;
 
@@ -474,7 +559,8 @@ static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header)
 
 static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
                                                            int *source_port,
-                                                           int *switch_id)
+                                                           int *switch_id,
+                                                           bool *host_only)
 {
        u16 rx_header;
 
@@ -488,6 +574,9 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
         */
        rx_header = ntohs(*(__be16 *)skb->data);
 
+       if (rx_header & SJA1110_RX_HEADER_HOST_ONLY)
+               *host_only = true;
+
        if (rx_header & SJA1110_RX_HEADER_IS_METADATA)
                return sja1110_rcv_meta(skb, rx_header);
 
@@ -522,9 +611,7 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
        /* Advance skb->data past the DSA header */
        skb_pull_rcsum(skb, SJA1110_HEADER_LEN);
 
-       /* Remove the DSA header */
-       memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - SJA1110_HEADER_LEN,
-               2 * ETH_ALEN);
+       dsa_strip_etype_header(skb, SJA1110_HEADER_LEN);
 
        /* With skb->data in its final place, update the MAC header
         * so that eth_hdr() continues to works properly.
@@ -535,34 +622,35 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
 }
 
 static struct sk_buff *sja1110_rcv(struct sk_buff *skb,
-                                  struct net_device *netdev,
-                                  struct packet_type *pt)
+                                  struct net_device *netdev)
 {
-       int source_port = -1, switch_id = -1, subvlan = 0;
-
-       skb->offload_fwd_mark = 1;
+       int source_port = -1, switch_id = -1;
+       bool host_only = false;
+       u16 vid = 0;
 
        if (sja1110_skb_has_inband_control_extension(skb)) {
                skb = sja1110_rcv_inband_control_extension(skb, &source_port,
-                                                          &switch_id);
+                                                          &switch_id,
+                                                          &host_only);
                if (!skb)
                        return NULL;
        }
 
        /* Packets with in-band control extensions might still have RX VLANs */
        if (likely(sja1105_skb_has_tag_8021q(skb)))
-               dsa_8021q_rcv(skb, &source_port, &switch_id, &subvlan);
+               sja1105_vlan_rcv(skb, &source_port, &switch_id, &vid);
 
-       skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);
+       if (source_port == -1 || switch_id == -1)
+               skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid);
+       else
+               skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);
        if (!skb->dev) {
-               netdev_warn(netdev,
-                           "Couldn't decode source port %d and switch id %d\n",
-                           source_port, switch_id);
+               netdev_warn(netdev, "Couldn't decode source port\n");
                return NULL;
        }
 
-       if (subvlan)
-               sja1105_decode_subvlan(skb, subvlan);
+       if (!host_only)
+               dsa_default_offload_fwd_mark(skb);
 
        return skb;
 }
@@ -596,7 +684,6 @@ static const struct dsa_device_ops sja1105_netdev_ops = {
        .proto = DSA_TAG_PROTO_SJA1105,
        .xmit = sja1105_xmit,
        .rcv = sja1105_rcv,
-       .filter = sja1105_filter,
        .needed_headroom = VLAN_HLEN,
        .flow_dissect = sja1105_flow_dissect,
        .promisc_on_master = true,
@@ -610,7 +697,6 @@ static const struct dsa_device_ops sja1110_netdev_ops = {
        .proto = DSA_TAG_PROTO_SJA1110,
        .xmit = sja1110_xmit,
        .rcv = sja1110_rcv,
-       .filter = sja1105_filter,
        .flow_dissect = sja1110_flow_dissect,
        .needed_headroom = SJA1110_HEADER_LEN + VLAN_HLEN,
        .needed_tailroom = SJA1110_RX_TRAILER_LEN + SJA1110_MAX_PADDING_LEN,