Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2019 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
0004  */
0005 
0006 
0007 #include <linux/bitfield.h>
0008 #include <linux/etherdevice.h>
0009 
0010 #include "dsa_priv.h"
0011 
0012 #define AR9331_HDR_LEN          2
0013 #define AR9331_HDR_VERSION      1
0014 
0015 #define AR9331_HDR_VERSION_MASK     GENMASK(15, 14)
0016 #define AR9331_HDR_PRIORITY_MASK    GENMASK(13, 12)
0017 #define AR9331_HDR_TYPE_MASK        GENMASK(10, 8)
0018 #define AR9331_HDR_BROADCAST        BIT(7)
0019 #define AR9331_HDR_FROM_CPU     BIT(6)
0020 /* AR9331_HDR_RESERVED - not used or may be version field.
0021  * According to the AR8216 doc it should 0b10. On AR9331 it is 0b11 on RX path
0022  * and should be set to 0b11 to make it work.
0023  */
0024 #define AR9331_HDR_RESERVED_MASK    GENMASK(5, 4)
0025 #define AR9331_HDR_PORT_NUM_MASK    GENMASK(3, 0)
0026 
0027 static struct sk_buff *ar9331_tag_xmit(struct sk_buff *skb,
0028                        struct net_device *dev)
0029 {
0030     struct dsa_port *dp = dsa_slave_to_port(dev);
0031     __le16 *phdr;
0032     u16 hdr;
0033 
0034     phdr = skb_push(skb, AR9331_HDR_LEN);
0035 
0036     hdr = FIELD_PREP(AR9331_HDR_VERSION_MASK, AR9331_HDR_VERSION);
0037     hdr |= AR9331_HDR_FROM_CPU | dp->index;
0038     /* 0b10 for AR8216 and 0b11 for AR9331 */
0039     hdr |= AR9331_HDR_RESERVED_MASK;
0040 
0041     phdr[0] = cpu_to_le16(hdr);
0042 
0043     return skb;
0044 }
0045 
0046 static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
0047                       struct net_device *ndev)
0048 {
0049     u8 ver, port;
0050     u16 hdr;
0051 
0052     if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN)))
0053         return NULL;
0054 
0055     hdr = le16_to_cpu(*(__le16 *)skb_mac_header(skb));
0056 
0057     ver = FIELD_GET(AR9331_HDR_VERSION_MASK, hdr);
0058     if (unlikely(ver != AR9331_HDR_VERSION)) {
0059         netdev_warn_once(ndev, "%s:%i wrong header version 0x%2x\n",
0060                  __func__, __LINE__, hdr);
0061         return NULL;
0062     }
0063 
0064     if (unlikely(hdr & AR9331_HDR_FROM_CPU)) {
0065         netdev_warn_once(ndev, "%s:%i packet should not be from cpu 0x%2x\n",
0066                  __func__, __LINE__, hdr);
0067         return NULL;
0068     }
0069 
0070     skb_pull_rcsum(skb, AR9331_HDR_LEN);
0071 
0072     /* Get source port information */
0073     port = FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr);
0074 
0075     skb->dev = dsa_master_find_slave(ndev, 0, port);
0076     if (!skb->dev)
0077         return NULL;
0078 
0079     return skb;
0080 }
0081 
0082 static const struct dsa_device_ops ar9331_netdev_ops = {
0083     .name   = "ar9331",
0084     .proto  = DSA_TAG_PROTO_AR9331,
0085     .xmit   = ar9331_tag_xmit,
0086     .rcv    = ar9331_tag_rcv,
0087     .needed_headroom = AR9331_HDR_LEN,
0088 };
0089 
0090 MODULE_LICENSE("GPL v2");
0091 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_AR9331);
0092 module_dsa_tag_driver(ar9331_netdev_ops);