linux/net/dsa/tag_ksz.c
<<
>>
Prefs
   1/*
   2 * net/dsa/tag_ksz.c - Microchip KSZ Switch tag format handling
   3 * Copyright (c) 2017 Microchip Technology
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 */
  10
  11#include <linux/etherdevice.h>
  12#include <linux/list.h>
  13#include <linux/slab.h>
  14#include <net/dsa.h>
  15#include "dsa_priv.h"
  16
  17/* Typically only one byte is used for tail tag. */
  18#define KSZ_EGRESS_TAG_LEN              1
  19
  20static struct sk_buff *ksz_common_xmit(struct sk_buff *skb,
  21                                       struct net_device *dev, int len)
  22{
  23        struct sk_buff *nskb;
  24        int padlen;
  25
  26        padlen = (skb->len >= ETH_ZLEN) ? 0 : ETH_ZLEN - skb->len;
  27
  28        if (skb_tailroom(skb) >= padlen + len) {
  29                /* Let dsa_slave_xmit() free skb */
  30                if (__skb_put_padto(skb, skb->len + padlen, false))
  31                        return NULL;
  32
  33                nskb = skb;
  34        } else {
  35                nskb = alloc_skb(NET_IP_ALIGN + skb->len +
  36                                 padlen + len, GFP_ATOMIC);
  37                if (!nskb)
  38                        return NULL;
  39                skb_reserve(nskb, NET_IP_ALIGN);
  40
  41                skb_reset_mac_header(nskb);
  42                skb_set_network_header(nskb,
  43                                       skb_network_header(skb) - skb->head);
  44                skb_set_transport_header(nskb,
  45                                         skb_transport_header(skb) - skb->head);
  46                skb_copy_and_csum_dev(skb, skb_put(nskb, skb->len));
  47
  48                /* Let skb_put_padto() free nskb, and let dsa_slave_xmit() free
  49                 * skb
  50                 */
  51                if (skb_put_padto(nskb, nskb->len + padlen))
  52                        return NULL;
  53
  54                consume_skb(skb);
  55        }
  56
  57        return nskb;
  58}
  59
  60static struct sk_buff *ksz_common_rcv(struct sk_buff *skb,
  61                                      struct net_device *dev,
  62                                      unsigned int port, unsigned int len)
  63{
  64        skb->dev = dsa_master_find_slave(dev, 0, port);
  65        if (!skb->dev)
  66                return NULL;
  67
  68        pskb_trim_rcsum(skb, skb->len - len);
  69
  70        return skb;
  71}
  72
  73/*
  74 * For Ingress (Host -> KSZ9477), 2 bytes are added before FCS.
  75 * ---------------------------------------------------------------------------
  76 * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes)
  77 * ---------------------------------------------------------------------------
  78 * tag0 : Prioritization (not used now)
  79 * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5)
  80 *
  81 * For Egress (KSZ9477 -> Host), 1 byte is added before FCS.
  82 * ---------------------------------------------------------------------------
  83 * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes)
  84 * ---------------------------------------------------------------------------
  85 * tag0 : zero-based value represents port
  86 *        (eg, 0x00=port1, 0x02=port3, 0x06=port7)
  87 */
  88
  89#define KSZ9477_INGRESS_TAG_LEN         2
  90#define KSZ9477_PTP_TAG_LEN             4
  91#define KSZ9477_PTP_TAG_INDICATION      0x80
  92
  93#define KSZ9477_TAIL_TAG_OVERRIDE       BIT(9)
  94#define KSZ9477_TAIL_TAG_LOOKUP         BIT(10)
  95
  96static struct sk_buff *ksz9477_xmit(struct sk_buff *skb,
  97                                    struct net_device *dev)
  98{
  99        struct dsa_port *dp = dsa_slave_to_port(dev);
 100        struct sk_buff *nskb;
 101        u16 *tag;
 102        u8 *addr;
 103
 104        nskb = ksz_common_xmit(skb, dev, KSZ9477_INGRESS_TAG_LEN);
 105        if (!nskb)
 106                return NULL;
 107
 108        /* Tag encoding */
 109        tag = skb_put(nskb, KSZ9477_INGRESS_TAG_LEN);
 110        addr = skb_mac_header(nskb);
 111
 112        *tag = BIT(dp->index);
 113
 114        if (is_link_local_ether_addr(addr))
 115                *tag |= KSZ9477_TAIL_TAG_OVERRIDE;
 116
 117        *tag = cpu_to_be16(*tag);
 118
 119        return nskb;
 120}
 121
 122static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev,
 123                                   struct packet_type *pt)
 124{
 125        /* Tag decoding */
 126        u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
 127        unsigned int port = tag[0] & 7;
 128        unsigned int len = KSZ_EGRESS_TAG_LEN;
 129
 130        /* Extra 4-bytes PTP timestamp */
 131        if (tag[0] & KSZ9477_PTP_TAG_INDICATION)
 132                len += KSZ9477_PTP_TAG_LEN;
 133
 134        return ksz_common_rcv(skb, dev, port, len);
 135}
 136
 137const struct dsa_device_ops ksz9477_netdev_ops = {
 138        .xmit   = ksz9477_xmit,
 139        .rcv    = ksz9477_rcv,
 140        .overhead = KSZ9477_INGRESS_TAG_LEN,
 141};
 142