net/smc: Replace zero-length array with flexible-array member
[platform/kernel/linux-starfive.git] / net / dsa / tag_ocelot.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2019 NXP Semiconductors
3  */
4 #include <soc/mscc/ocelot.h>
5 #include <linux/packing.h>
6 #include "dsa_priv.h"
7
8 /* The CPU injection header and the CPU extraction header can have 3 types of
9  * prefixes: long, short and no prefix. The format of the header itself is the
10  * same in all 3 cases.
11  *
12  * Extraction with long prefix:
13  *
14  * +-------------------+-------------------+------+------+------------+-------+
15  * | ff:ff:ff:ff:ff:ff | ff:ff:ff:ff:ff:ff | 8880 | 000a | extraction | frame |
16  * |                   |                   |      |      |   header   |       |
17  * +-------------------+-------------------+------+------+------------+-------+
18  *        48 bits             48 bits      16 bits 16 bits  128 bits
19  *
20  * Extraction with short prefix:
21  *
22  *                                         +------+------+------------+-------+
23  *                                         | 8880 | 000a | extraction | frame |
24  *                                         |      |      |   header   |       |
25  *                                         +------+------+------------+-------+
26  *                                         16 bits 16 bits  128 bits
27  *
28  * Extraction with no prefix:
29  *
30  *                                                       +------------+-------+
31  *                                                       | extraction | frame |
32  *                                                       |   header   |       |
33  *                                                       +------------+-------+
34  *                                                          128 bits
35  *
36  *
37  * Injection with long prefix:
38  *
39  * +-------------------+-------------------+------+------+------------+-------+
40  * |      any dmac     |      any smac     | 8880 | 000a | injection  | frame |
41  * |                   |                   |      |      |   header   |       |
42  * +-------------------+-------------------+------+------+------------+-------+
43  *        48 bits             48 bits      16 bits 16 bits  128 bits
44  *
45  * Injection with short prefix:
46  *
47  *                                         +------+------+------------+-------+
48  *                                         | 8880 | 000a | injection  | frame |
49  *                                         |      |      |   header   |       |
50  *                                         +------+------+------------+-------+
51  *                                         16 bits 16 bits  128 bits
52  *
53  * Injection with no prefix:
54  *
55  *                                                       +------------+-------+
56  *                                                       | injection  | frame |
57  *                                                       |   header   |       |
58  *                                                       +------------+-------+
59  *                                                          128 bits
60  *
61  * The injection header looks like this (network byte order, bit 127
62  * is part of lowest address byte in memory, bit 0 is part of highest
63  * address byte):
64  *
65  *         +------+------+------+------+------+------+------+------+
66  * 127:120 |BYPASS| MASQ |          MASQ_PORT        |REW_OP|REW_OP|
67  *         +------+------+------+------+------+------+------+------+
68  * 119:112 |                         REW_OP                        |
69  *         +------+------+------+------+------+------+------+------+
70  * 111:104 |                         REW_VAL                       |
71  *         +------+------+------+------+------+------+------+------+
72  * 103: 96 |                         REW_VAL                       |
73  *         +------+------+------+------+------+------+------+------+
74  *  95: 88 |                         REW_VAL                       |
75  *         +------+------+------+------+------+------+------+------+
76  *  87: 80 |                         REW_VAL                       |
77  *         +------+------+------+------+------+------+------+------+
78  *  79: 72 |                          RSV                          |
79  *         +------+------+------+------+------+------+------+------+
80  *  71: 64 |            RSV            |           DEST            |
81  *         +------+------+------+------+------+------+------+------+
82  *  63: 56 |                         DEST                          |
83  *         +------+------+------+------+------+------+------+------+
84  *  55: 48 |                          RSV                          |
85  *         +------+------+------+------+------+------+------+------+
86  *  47: 40 |  RSV |         SRC_PORT          |     RSV     |TFRM_TIMER|
87  *         +------+------+------+------+------+------+------+------+
88  *  39: 32 |     TFRM_TIMER     |               RSV                |
89  *         +------+------+------+------+------+------+------+------+
90  *  31: 24 |  RSV |  DP  |   POP_CNT   |           CPUQ            |
91  *         +------+------+------+------+------+------+------+------+
92  *  23: 16 |           CPUQ            |      QOS_CLASS     |TAG_TYPE|
93  *         +------+------+------+------+------+------+------+------+
94  *  15:  8 |         PCP        |  DEI |            VID            |
95  *         +------+------+------+------+------+------+------+------+
96  *   7:  0 |                          VID                          |
97  *         +------+------+------+------+------+------+------+------+
98  *
99  * And the extraction header looks like this:
100  *
101  *         +------+------+------+------+------+------+------+------+
102  * 127:120 |  RSV |                  REW_OP                        |
103  *         +------+------+------+------+------+------+------+------+
104  * 119:112 |       REW_OP       |              REW_VAL             |
105  *         +------+------+------+------+------+------+------+------+
106  * 111:104 |                         REW_VAL                       |
107  *         +------+------+------+------+------+------+------+------+
108  * 103: 96 |                         REW_VAL                       |
109  *         +------+------+------+------+------+------+------+------+
110  *  95: 88 |                         REW_VAL                       |
111  *         +------+------+------+------+------+------+------+------+
112  *  87: 80 |       REW_VAL      |               LLEN               |
113  *         +------+------+------+------+------+------+------+------+
114  *  79: 72 | LLEN |                      WLEN                      |
115  *         +------+------+------+------+------+------+------+------+
116  *  71: 64 | WLEN |                      RSV                       |
117  *         +------+------+------+------+------+------+------+------+
118  *  63: 56 |                          RSV                          |
119  *         +------+------+------+------+------+------+------+------+
120  *  55: 48 |                          RSV                          |
121  *         +------+------+------+------+------+------+------+------+
122  *  47: 40 | RSV  |          SRC_PORT         |       ACL_ID       |
123  *         +------+------+------+------+------+------+------+------+
124  *  39: 32 |       ACL_ID       |  RSV |         SFLOW_ID          |
125  *         +------+------+------+------+------+------+------+------+
126  *  31: 24 |ACL_HIT| DP  |  LRN_FLAGS  |           CPUQ            |
127  *         +------+------+------+------+------+------+------+------+
128  *  23: 16 |           CPUQ            |      QOS_CLASS     |TAG_TYPE|
129  *         +------+------+------+------+------+------+------+------+
130  *  15:  8 |         PCP        |  DEI |            VID            |
131  *         +------+------+------+------+------+------+------+------+
132  *   7:  0 |                          VID                          |
133  *         +------+------+------+------+------+------+------+------+
134  */
135
136 static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
137                                    struct net_device *netdev)
138 {
139         struct dsa_port *dp = dsa_slave_to_port(netdev);
140         struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
141         struct dsa_switch *ds = dp->ds;
142         struct ocelot *ocelot = ds->priv;
143         struct ocelot_port *ocelot_port;
144         u8 *prefix, *injection;
145         u64 qos_class, rew_op;
146         int err;
147
148         err = skb_cow_head(skb, OCELOT_TOTAL_TAG_LEN);
149         if (unlikely(err < 0)) {
150                 netdev_err(netdev, "Cannot make room for tag.\n");
151                 return NULL;
152         }
153
154         ocelot_port = ocelot->ports[dp->index];
155
156         injection = skb_push(skb, OCELOT_TAG_LEN);
157
158         prefix = skb_push(skb, OCELOT_SHORT_PREFIX_LEN);
159
160         memcpy(prefix, ocelot_port->xmit_template, OCELOT_TOTAL_TAG_LEN);
161
162         /* Fix up the fields which are not statically determined
163          * in the template
164          */
165         qos_class = skb->priority;
166         packing(injection, &qos_class, 19,  17, OCELOT_TAG_LEN, PACK, 0);
167
168         /* TX timestamping was requested */
169         if (clone) {
170                 rew_op = ocelot_port->ptp_cmd;
171                 /* Retrieve timestamp ID populated inside skb->cb[0] of the
172                  * clone by ocelot_port_add_txtstamp_skb
173                  */
174                 if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
175                         rew_op |= clone->cb[0] << 3;
176
177                 packing(injection, &rew_op, 125, 117, OCELOT_TAG_LEN, PACK, 0);
178         }
179
180         return skb;
181 }
182
183 static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
184                                   struct net_device *netdev,
185                                   struct packet_type *pt)
186 {
187         struct dsa_port *cpu_dp = netdev->dsa_ptr;
188         struct dsa_switch *ds = cpu_dp->ds;
189         struct ocelot *ocelot = ds->priv;
190         u64 src_port, qos_class;
191         u64 vlan_tci, tag_type;
192         u8 *start = skb->data;
193         u8 *extraction;
194         u16 vlan_tpid;
195
196         /* Revert skb->data by the amount consumed by the DSA master,
197          * so it points to the beginning of the frame.
198          */
199         skb_push(skb, ETH_HLEN);
200         /* We don't care about the short prefix, it is just for easy entrance
201          * into the DSA master's RX filter. Discard it now by moving it into
202          * the headroom.
203          */
204         skb_pull(skb, OCELOT_SHORT_PREFIX_LEN);
205         /* And skb->data now points to the extraction frame header.
206          * Keep a pointer to it.
207          */
208         extraction = skb->data;
209         /* Now the EFH is part of the headroom as well */
210         skb_pull(skb, OCELOT_TAG_LEN);
211         /* Reset the pointer to the real MAC header */
212         skb_reset_mac_header(skb);
213         skb_reset_mac_len(skb);
214         /* And move skb->data to the correct location again */
215         skb_pull(skb, ETH_HLEN);
216
217         /* Remove from inet csum the extraction header */
218         skb_postpull_rcsum(skb, start, OCELOT_TOTAL_TAG_LEN);
219
220         packing(extraction, &src_port,  46, 43, OCELOT_TAG_LEN, UNPACK, 0);
221         packing(extraction, &qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
222         packing(extraction, &tag_type,  16, 16, OCELOT_TAG_LEN, UNPACK, 0);
223         packing(extraction, &vlan_tci,  15,  0, OCELOT_TAG_LEN, UNPACK, 0);
224
225         skb->dev = dsa_master_find_slave(netdev, 0, src_port);
226         if (!skb->dev)
227                 /* The switch will reflect back some frames sent through
228                  * sockets opened on the bare DSA master. These will come back
229                  * with src_port equal to the index of the CPU port, for which
230                  * there is no slave registered. So don't print any error
231                  * message here (ignore and drop those frames).
232                  */
233                 return NULL;
234
235         skb->offload_fwd_mark = 1;
236         skb->priority = qos_class;
237
238         /* Ocelot switches copy frames unmodified to the CPU. However, it is
239          * possible for the user to request a VLAN modification through
240          * VCAP_IS1_ACT_VID_REPLACE_ENA. In this case, what will happen is that
241          * the VLAN ID field from the Extraction Header gets updated, but the
242          * 802.1Q header does not (the classified VLAN only becomes visible on
243          * egress through the "port tag" of front-panel ports).
244          * So, for traffic extracted by the CPU, we want to pick up the
245          * classified VLAN and manually replace the existing 802.1Q header from
246          * the packet with it, so that the operating system is always up to
247          * date with the result of tc-vlan actions.
248          * NOTE: In VLAN-unaware mode, we don't want to do that, we want the
249          * frame to remain unmodified, because the classified VLAN is always
250          * equal to the pvid of the ingress port and should not be used for
251          * processing.
252          */
253         vlan_tpid = tag_type ? ETH_P_8021AD : ETH_P_8021Q;
254
255         if (ocelot->ports[src_port]->vlan_aware &&
256             eth_hdr(skb)->h_proto == htons(vlan_tpid)) {
257                 u16 dummy_vlan_tci;
258
259                 skb_push_rcsum(skb, ETH_HLEN);
260                 __skb_vlan_pop(skb, &dummy_vlan_tci);
261                 skb_pull_rcsum(skb, ETH_HLEN);
262                 __vlan_hwaccel_put_tag(skb, htons(vlan_tpid), vlan_tci);
263         }
264
265         return skb;
266 }
267
268 static const struct dsa_device_ops ocelot_netdev_ops = {
269         .name                   = "ocelot",
270         .proto                  = DSA_TAG_PROTO_OCELOT,
271         .xmit                   = ocelot_xmit,
272         .rcv                    = ocelot_rcv,
273         .overhead               = OCELOT_TOTAL_TAG_LEN,
274         .promisc_on_master      = true,
275 };
276
277 MODULE_LICENSE("GPL v2");
278 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT);
279
280 module_dsa_tag_driver(ocelot_netdev_ops);