1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2019 NXP Semiconductors
4 #include <soc/mscc/ocelot.h>
5 #include <linux/packing.h>
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.
12 * Extraction with long prefix:
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
20 * Extraction with short prefix:
22 * +------+------+------------+-------+
23 * | 8880 | 000a | extraction | frame |
25 * +------+------+------------+-------+
26 * 16 bits 16 bits 128 bits
28 * Extraction with no prefix:
30 * +------------+-------+
31 * | extraction | frame |
33 * +------------+-------+
37 * Injection with long prefix:
39 * +-------------------+-------------------+------+------+------------+-------+
40 * | any dmac | any smac | 8880 | 000a | injection | frame |
41 * | | | | | header | |
42 * +-------------------+-------------------+------+------+------------+-------+
43 * 48 bits 48 bits 16 bits 16 bits 128 bits
45 * Injection with short prefix:
47 * +------+------+------------+-------+
48 * | 8880 | 000a | injection | frame |
50 * +------+------+------------+-------+
51 * 16 bits 16 bits 128 bits
53 * Injection with no prefix:
55 * +------------+-------+
56 * | injection | frame |
58 * +------------+-------+
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
65 * +------+------+------+------+------+------+------+------+
66 * 127:120 |BYPASS| MASQ | MASQ_PORT |REW_OP|REW_OP|
67 * +------+------+------+------+------+------+------+------+
69 * +------+------+------+------+------+------+------+------+
71 * +------+------+------+------+------+------+------+------+
73 * +------+------+------+------+------+------+------+------+
75 * +------+------+------+------+------+------+------+------+
77 * +------+------+------+------+------+------+------+------+
79 * +------+------+------+------+------+------+------+------+
80 * 71: 64 | RSV | DEST |
81 * +------+------+------+------+------+------+------+------+
83 * +------+------+------+------+------+------+------+------+
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 * +------+------+------+------+------+------+------+------+
97 * +------+------+------+------+------+------+------+------+
99 * And the extraction header looks like this:
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 * +------+------+------+------+------+------+------+------+
111 * +------+------+------+------+------+------+------+------+
112 * 87: 80 | REW_VAL | LLEN |
113 * +------+------+------+------+------+------+------+------+
114 * 79: 72 | LLEN | WLEN |
115 * +------+------+------+------+------+------+------+------+
116 * 71: 64 | WLEN | RSV |
117 * +------+------+------+------+------+------+------+------+
119 * +------+------+------+------+------+------+------+------+
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 * +------+------+------+------+------+------+------+------+
133 * +------+------+------+------+------+------+------+------+
136 static struct sk_buff
*ocelot_xmit(struct sk_buff
*skb
,
137 struct net_device
*netdev
)
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
;
147 ocelot_port
= ocelot
->ports
[dp
->index
];
149 injection
= skb_push(skb
, OCELOT_TAG_LEN
);
151 prefix
= skb_push(skb
, OCELOT_SHORT_PREFIX_LEN
);
153 memcpy(prefix
, ocelot_port
->xmit_template
, OCELOT_TOTAL_TAG_LEN
);
155 /* Fix up the fields which are not statically determined
158 qos_class
= skb
->priority
;
159 packing(injection
, &qos_class
, 19, 17, OCELOT_TAG_LEN
, PACK
, 0);
161 /* TX timestamping was requested */
163 rew_op
= ocelot_port
->ptp_cmd
;
164 /* Retrieve timestamp ID populated inside skb->cb[0] of the
165 * clone by ocelot_port_add_txtstamp_skb
167 if (ocelot_port
->ptp_cmd
== IFH_REW_OP_TWO_STEP_PTP
)
168 rew_op
|= clone
->cb
[0] << 3;
170 packing(injection
, &rew_op
, 125, 117, OCELOT_TAG_LEN
, PACK
, 0);
176 static struct sk_buff
*ocelot_rcv(struct sk_buff
*skb
,
177 struct net_device
*netdev
,
178 struct packet_type
*pt
)
180 struct dsa_port
*cpu_dp
= netdev
->dsa_ptr
;
181 struct dsa_switch
*ds
= cpu_dp
->ds
;
182 struct ocelot
*ocelot
= ds
->priv
;
183 u64 src_port
, qos_class
;
184 u64 vlan_tci
, tag_type
;
185 u8
*start
= skb
->data
;
189 /* Revert skb->data by the amount consumed by the DSA master,
190 * so it points to the beginning of the frame.
192 skb_push(skb
, ETH_HLEN
);
193 /* We don't care about the short prefix, it is just for easy entrance
194 * into the DSA master's RX filter. Discard it now by moving it into
197 skb_pull(skb
, OCELOT_SHORT_PREFIX_LEN
);
198 /* And skb->data now points to the extraction frame header.
199 * Keep a pointer to it.
201 extraction
= skb
->data
;
202 /* Now the EFH is part of the headroom as well */
203 skb_pull(skb
, OCELOT_TAG_LEN
);
204 /* Reset the pointer to the real MAC header */
205 skb_reset_mac_header(skb
);
206 skb_reset_mac_len(skb
);
207 /* And move skb->data to the correct location again */
208 skb_pull(skb
, ETH_HLEN
);
210 /* Remove from inet csum the extraction header */
211 skb_postpull_rcsum(skb
, start
, OCELOT_TOTAL_TAG_LEN
);
213 packing(extraction
, &src_port
, 46, 43, OCELOT_TAG_LEN
, UNPACK
, 0);
214 packing(extraction
, &qos_class
, 19, 17, OCELOT_TAG_LEN
, UNPACK
, 0);
215 packing(extraction
, &tag_type
, 16, 16, OCELOT_TAG_LEN
, UNPACK
, 0);
216 packing(extraction
, &vlan_tci
, 15, 0, OCELOT_TAG_LEN
, UNPACK
, 0);
218 skb
->dev
= dsa_master_find_slave(netdev
, 0, src_port
);
220 /* The switch will reflect back some frames sent through
221 * sockets opened on the bare DSA master. These will come back
222 * with src_port equal to the index of the CPU port, for which
223 * there is no slave registered. So don't print any error
224 * message here (ignore and drop those frames).
228 skb
->offload_fwd_mark
= 1;
229 skb
->priority
= qos_class
;
231 /* Ocelot switches copy frames unmodified to the CPU. However, it is
232 * possible for the user to request a VLAN modification through
233 * VCAP_IS1_ACT_VID_REPLACE_ENA. In this case, what will happen is that
234 * the VLAN ID field from the Extraction Header gets updated, but the
235 * 802.1Q header does not (the classified VLAN only becomes visible on
236 * egress through the "port tag" of front-panel ports).
237 * So, for traffic extracted by the CPU, we want to pick up the
238 * classified VLAN and manually replace the existing 802.1Q header from
239 * the packet with it, so that the operating system is always up to
240 * date with the result of tc-vlan actions.
241 * NOTE: In VLAN-unaware mode, we don't want to do that, we want the
242 * frame to remain unmodified, because the classified VLAN is always
243 * equal to the pvid of the ingress port and should not be used for
246 vlan_tpid
= tag_type
? ETH_P_8021AD
: ETH_P_8021Q
;
248 if (ocelot
->ports
[src_port
]->vlan_aware
&&
249 eth_hdr(skb
)->h_proto
== htons(vlan_tpid
)) {
252 skb_push_rcsum(skb
, ETH_HLEN
);
253 __skb_vlan_pop(skb
, &dummy_vlan_tci
);
254 skb_pull_rcsum(skb
, ETH_HLEN
);
255 __vlan_hwaccel_put_tag(skb
, htons(vlan_tpid
), vlan_tci
);
261 static const struct dsa_device_ops ocelot_netdev_ops
= {
263 .proto
= DSA_TAG_PROTO_OCELOT
,
266 .overhead
= OCELOT_TOTAL_TAG_LEN
,
267 .promisc_on_master
= true,
270 MODULE_LICENSE("GPL v2");
271 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT
);
273 module_dsa_tag_driver(ocelot_netdev_ops
);