linux/net/dsa/tag_qca.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
   4 */
   5
   6#include <linux/etherdevice.h>
   7
   8#include "dsa_priv.h"
   9
  10#define QCA_HDR_LEN     2
  11#define QCA_HDR_VERSION 0x2
  12
  13#define QCA_HDR_RECV_VERSION_MASK       GENMASK(15, 14)
  14#define QCA_HDR_RECV_VERSION_S          14
  15#define QCA_HDR_RECV_PRIORITY_MASK      GENMASK(13, 11)
  16#define QCA_HDR_RECV_PRIORITY_S         11
  17#define QCA_HDR_RECV_TYPE_MASK          GENMASK(10, 6)
  18#define QCA_HDR_RECV_TYPE_S             6
  19#define QCA_HDR_RECV_FRAME_IS_TAGGED    BIT(3)
  20#define QCA_HDR_RECV_SOURCE_PORT_MASK   GENMASK(2, 0)
  21
  22#define QCA_HDR_XMIT_VERSION_MASK       GENMASK(15, 14)
  23#define QCA_HDR_XMIT_VERSION_S          14
  24#define QCA_HDR_XMIT_PRIORITY_MASK      GENMASK(13, 11)
  25#define QCA_HDR_XMIT_PRIORITY_S         11
  26#define QCA_HDR_XMIT_CONTROL_MASK       GENMASK(10, 8)
  27#define QCA_HDR_XMIT_CONTROL_S          8
  28#define QCA_HDR_XMIT_FROM_CPU           BIT(7)
  29#define QCA_HDR_XMIT_DP_BIT_MASK        GENMASK(6, 0)
  30
  31static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
  32{
  33        struct dsa_port *dp = dsa_slave_to_port(dev);
  34        __be16 *phdr;
  35        u16 hdr;
  36
  37        skb_push(skb, QCA_HDR_LEN);
  38
  39        dsa_alloc_etype_header(skb, QCA_HDR_LEN);
  40        phdr = dsa_etype_header_pos_tx(skb);
  41
  42        /* Set the version field, and set destination port information */
  43        hdr = QCA_HDR_VERSION << QCA_HDR_XMIT_VERSION_S |
  44                QCA_HDR_XMIT_FROM_CPU | BIT(dp->index);
  45
  46        *phdr = htons(hdr);
  47
  48        return skb;
  49}
  50
  51static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
  52{
  53        u8 ver;
  54        u16  hdr;
  55        int port;
  56        __be16 *phdr;
  57
  58        if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN)))
  59                return NULL;
  60
  61        phdr = dsa_etype_header_pos_rx(skb);
  62        hdr = ntohs(*phdr);
  63
  64        /* Make sure the version is correct */
  65        ver = (hdr & QCA_HDR_RECV_VERSION_MASK) >> QCA_HDR_RECV_VERSION_S;
  66        if (unlikely(ver != QCA_HDR_VERSION))
  67                return NULL;
  68
  69        /* Remove QCA tag and recalculate checksum */
  70        skb_pull_rcsum(skb, QCA_HDR_LEN);
  71        dsa_strip_etype_header(skb, QCA_HDR_LEN);
  72
  73        /* Get source port information */
  74        port = (hdr & QCA_HDR_RECV_SOURCE_PORT_MASK);
  75
  76        skb->dev = dsa_master_find_slave(dev, 0, port);
  77        if (!skb->dev)
  78                return NULL;
  79
  80        return skb;
  81}
  82
  83static const struct dsa_device_ops qca_netdev_ops = {
  84        .name   = "qca",
  85        .proto  = DSA_TAG_PROTO_QCA,
  86        .xmit   = qca_tag_xmit,
  87        .rcv    = qca_tag_rcv,
  88        .needed_headroom = QCA_HDR_LEN,
  89};
  90
  91MODULE_LICENSE("GPL");
  92MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_QCA);
  93
  94module_dsa_tag_driver(qca_netdev_ops);
  95