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 #include <linux/bitfield.h> 8 #include <net/dsa.h> 9 #include <linux/dsa/tag_qca.h> 10 11 #include "tag.h" 12 13 #define QCA_NAME "qca" 14 15 static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev) 16 { 17 __be16 *phdr; 18 u16 hdr; 19 20 skb_push(skb, QCA_HDR_LEN); 21 22 dsa_alloc_etype_header(skb, QCA_HDR_LEN); 23 phdr = dsa_etype_header_pos_tx(skb); 24 25 /* Set the version field, and set destination port information */ 26 hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); 27 hdr |= QCA_HDR_XMIT_FROM_CPU; 28 hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, dsa_xmit_port_mask(skb, dev)); 29 30 *phdr = htons(hdr); 31 32 return skb; 33 } 34 35 static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev) 36 { 37 struct qca_tagger_data *tagger_data; 38 struct dsa_port *dp = dev->dsa_ptr; 39 struct dsa_switch *ds = dp->ds; 40 u8 ver, pk_type; 41 __be16 *phdr; 42 int port; 43 u16 hdr; 44 45 BUILD_BUG_ON(sizeof(struct qca_mgmt_ethhdr) != QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); 46 47 tagger_data = ds->tagger_data; 48 49 if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN))) 50 return NULL; 51 52 phdr = dsa_etype_header_pos_rx(skb); 53 hdr = ntohs(*phdr); 54 55 /* Make sure the version is correct */ 56 ver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr); 57 if (unlikely(ver != QCA_HDR_VERSION)) 58 return NULL; 59 60 /* Get pk type */ 61 pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr); 62 63 /* Ethernet mgmt read/write packet */ 64 if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) { 65 if (likely(tagger_data->rw_reg_ack_handler)) 66 tagger_data->rw_reg_ack_handler(ds, skb); 67 return NULL; 68 } 69 70 /* Ethernet MIB counter packet */ 71 if (pk_type == QCA_HDR_RECV_TYPE_MIB) { 72 if (likely(tagger_data->mib_autocast_handler)) 73 tagger_data->mib_autocast_handler(ds, skb); 74 return NULL; 75 } 76 77 /* Get source port information */ 78 port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, hdr); 79 80 skb->dev = dsa_conduit_find_user(dev, 0, port); 81 if (!skb->dev) 82 return NULL; 83 84 /* Remove QCA tag and recalculate checksum */ 85 skb_pull_rcsum(skb, QCA_HDR_LEN); 86 dsa_strip_etype_header(skb, QCA_HDR_LEN); 87 88 return skb; 89 } 90 91 static int qca_tag_connect(struct dsa_switch *ds) 92 { 93 struct qca_tagger_data *tagger_data; 94 95 tagger_data = kzalloc(sizeof(*tagger_data), GFP_KERNEL); 96 if (!tagger_data) 97 return -ENOMEM; 98 99 ds->tagger_data = tagger_data; 100 101 return 0; 102 } 103 104 static void qca_tag_disconnect(struct dsa_switch *ds) 105 { 106 kfree(ds->tagger_data); 107 ds->tagger_data = NULL; 108 } 109 110 static const struct dsa_device_ops qca_netdev_ops = { 111 .name = QCA_NAME, 112 .proto = DSA_TAG_PROTO_QCA, 113 .connect = qca_tag_connect, 114 .disconnect = qca_tag_disconnect, 115 .xmit = qca_tag_xmit, 116 .rcv = qca_tag_rcv, 117 .needed_headroom = QCA_HDR_LEN, 118 .promisc_on_conduit = true, 119 }; 120 121 MODULE_DESCRIPTION("DSA tag driver for Qualcomm Atheros QCA8K switches"); 122 MODULE_LICENSE("GPL"); 123 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_QCA, QCA_NAME); 124 125 module_dsa_tag_driver(qca_netdev_ops); 126