1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later |
2 | /* |
3 | * Copyright 2008 - 2015 Freescale Semiconductor Inc. |
4 | */ |
5 | |
6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
7 | |
8 | #include "fman_tgec.h" |
9 | #include "fman.h" |
10 | #include "mac.h" |
11 | |
12 | #include <linux/slab.h> |
13 | #include <linux/bitrev.h> |
14 | #include <linux/io.h> |
15 | #include <linux/crc32.h> |
16 | #include <linux/netdevice.h> |
17 | |
18 | /* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */ |
19 | #define TGEC_TX_IPG_LENGTH_MASK 0x000003ff |
20 | |
21 | /* Command and Configuration Register (COMMAND_CONFIG) */ |
22 | #define CMD_CFG_EN_TIMESTAMP 0x00100000 |
23 | #define CMD_CFG_NO_LEN_CHK 0x00020000 |
24 | #define CMD_CFG_PAUSE_IGNORE 0x00000100 |
25 | #define CMF_CFG_CRC_FWD 0x00000040 |
26 | #define CMD_CFG_PROMIS_EN 0x00000010 |
27 | #define CMD_CFG_RX_EN 0x00000002 |
28 | #define CMD_CFG_TX_EN 0x00000001 |
29 | |
30 | /* Interrupt Mask Register (IMASK) */ |
31 | #define TGEC_IMASK_MDIO_SCAN_EVENT 0x00010000 |
32 | #define TGEC_IMASK_MDIO_CMD_CMPL 0x00008000 |
33 | #define TGEC_IMASK_REM_FAULT 0x00004000 |
34 | #define TGEC_IMASK_LOC_FAULT 0x00002000 |
35 | #define TGEC_IMASK_TX_ECC_ER 0x00001000 |
36 | #define TGEC_IMASK_TX_FIFO_UNFL 0x00000800 |
37 | #define TGEC_IMASK_TX_FIFO_OVFL 0x00000400 |
38 | #define TGEC_IMASK_TX_ER 0x00000200 |
39 | #define TGEC_IMASK_RX_FIFO_OVFL 0x00000100 |
40 | #define TGEC_IMASK_RX_ECC_ER 0x00000080 |
41 | #define TGEC_IMASK_RX_JAB_FRM 0x00000040 |
42 | #define TGEC_IMASK_RX_OVRSZ_FRM 0x00000020 |
43 | #define TGEC_IMASK_RX_RUNT_FRM 0x00000010 |
44 | #define TGEC_IMASK_RX_FRAG_FRM 0x00000008 |
45 | #define TGEC_IMASK_RX_LEN_ER 0x00000004 |
46 | #define TGEC_IMASK_RX_CRC_ER 0x00000002 |
47 | #define TGEC_IMASK_RX_ALIGN_ER 0x00000001 |
48 | |
49 | /* Hashtable Control Register (HASHTABLE_CTRL) */ |
50 | #define TGEC_HASH_MCAST_SHIFT 23 |
51 | #define TGEC_HASH_MCAST_EN 0x00000200 |
52 | #define TGEC_HASH_ADR_MSK 0x000001ff |
53 | |
54 | #define DEFAULT_TX_IPG_LENGTH 12 |
55 | #define DEFAULT_MAX_FRAME_LENGTH 0x600 |
56 | #define DEFAULT_PAUSE_QUANT 0xf000 |
57 | |
58 | /* number of pattern match registers (entries) */ |
59 | #define TGEC_NUM_OF_PADDRS 1 |
60 | |
61 | /* Group address bit indication */ |
62 | #define GROUP_ADDRESS 0x0000010000000000LL |
63 | |
64 | /* Hash table size (= 32 bits*8 regs) */ |
65 | #define TGEC_HASH_TABLE_SIZE 512 |
66 | |
67 | /* tGEC memory map */ |
68 | struct tgec_regs { |
69 | u32 tgec_id; /* 0x000 Controller ID */ |
70 | u32 reserved001[1]; /* 0x004 */ |
71 | u32 command_config; /* 0x008 Control and configuration */ |
72 | u32 mac_addr_0; /* 0x00c Lower 32 bits of the MAC adr */ |
73 | u32 mac_addr_1; /* 0x010 Upper 16 bits of the MAC adr */ |
74 | u32 maxfrm; /* 0x014 Maximum frame length */ |
75 | u32 pause_quant; /* 0x018 Pause quanta */ |
76 | u32 rx_fifo_sections; /* 0x01c */ |
77 | u32 tx_fifo_sections; /* 0x020 */ |
78 | u32 rx_fifo_almost_f_e; /* 0x024 */ |
79 | u32 tx_fifo_almost_f_e; /* 0x028 */ |
80 | u32 hashtable_ctrl; /* 0x02c Hash table control */ |
81 | u32 mdio_cfg_status; /* 0x030 */ |
82 | u32 mdio_command; /* 0x034 */ |
83 | u32 mdio_data; /* 0x038 */ |
84 | u32 mdio_regaddr; /* 0x03c */ |
85 | u32 status; /* 0x040 */ |
86 | u32 tx_ipg_len; /* 0x044 Transmitter inter-packet-gap */ |
87 | u32 mac_addr_2; /* 0x048 Lower 32 bits of 2nd MAC adr */ |
88 | u32 mac_addr_3; /* 0x04c Upper 16 bits of 2nd MAC adr */ |
89 | u32 rx_fifo_ptr_rd; /* 0x050 */ |
90 | u32 rx_fifo_ptr_wr; /* 0x054 */ |
91 | u32 tx_fifo_ptr_rd; /* 0x058 */ |
92 | u32 tx_fifo_ptr_wr; /* 0x05c */ |
93 | u32 imask; /* 0x060 Interrupt mask */ |
94 | u32 ievent; /* 0x064 Interrupt event */ |
95 | u32 udp_port; /* 0x068 Defines a UDP Port number */ |
96 | u32 type_1588v2; /* 0x06c Type field for 1588v2 */ |
97 | u32 reserved070[4]; /* 0x070 */ |
98 | /* 10Ge Statistics Counter */ |
99 | u32 tfrm_u; /* 80 aFramesTransmittedOK */ |
100 | u32 tfrm_l; /* 84 aFramesTransmittedOK */ |
101 | u32 rfrm_u; /* 88 aFramesReceivedOK */ |
102 | u32 rfrm_l; /* 8c aFramesReceivedOK */ |
103 | u32 rfcs_u; /* 90 aFrameCheckSequenceErrors */ |
104 | u32 rfcs_l; /* 94 aFrameCheckSequenceErrors */ |
105 | u32 raln_u; /* 98 aAlignmentErrors */ |
106 | u32 raln_l; /* 9c aAlignmentErrors */ |
107 | u32 txpf_u; /* A0 aPAUSEMACCtrlFramesTransmitted */ |
108 | u32 txpf_l; /* A4 aPAUSEMACCtrlFramesTransmitted */ |
109 | u32 rxpf_u; /* A8 aPAUSEMACCtrlFramesReceived */ |
110 | u32 rxpf_l; /* Ac aPAUSEMACCtrlFramesReceived */ |
111 | u32 rlong_u; /* B0 aFrameTooLongErrors */ |
112 | u32 rlong_l; /* B4 aFrameTooLongErrors */ |
113 | u32 rflr_u; /* B8 aInRangeLengthErrors */ |
114 | u32 rflr_l; /* Bc aInRangeLengthErrors */ |
115 | u32 tvlan_u; /* C0 VLANTransmittedOK */ |
116 | u32 tvlan_l; /* C4 VLANTransmittedOK */ |
117 | u32 rvlan_u; /* C8 VLANReceivedOK */ |
118 | u32 rvlan_l; /* Cc VLANReceivedOK */ |
119 | u32 toct_u; /* D0 if_out_octets */ |
120 | u32 toct_l; /* D4 if_out_octets */ |
121 | u32 roct_u; /* D8 if_in_octets */ |
122 | u32 roct_l; /* Dc if_in_octets */ |
123 | u32 ruca_u; /* E0 if_in_ucast_pkts */ |
124 | u32 ruca_l; /* E4 if_in_ucast_pkts */ |
125 | u32 rmca_u; /* E8 ifInMulticastPkts */ |
126 | u32 rmca_l; /* Ec ifInMulticastPkts */ |
127 | u32 rbca_u; /* F0 ifInBroadcastPkts */ |
128 | u32 rbca_l; /* F4 ifInBroadcastPkts */ |
129 | u32 terr_u; /* F8 if_out_errors */ |
130 | u32 terr_l; /* Fc if_out_errors */ |
131 | u32 reserved100[2]; /* 100-108 */ |
132 | u32 tuca_u; /* 108 if_out_ucast_pkts */ |
133 | u32 tuca_l; /* 10c if_out_ucast_pkts */ |
134 | u32 tmca_u; /* 110 ifOutMulticastPkts */ |
135 | u32 tmca_l; /* 114 ifOutMulticastPkts */ |
136 | u32 tbca_u; /* 118 ifOutBroadcastPkts */ |
137 | u32 tbca_l; /* 11c ifOutBroadcastPkts */ |
138 | u32 rdrp_u; /* 120 etherStatsDropEvents */ |
139 | u32 rdrp_l; /* 124 etherStatsDropEvents */ |
140 | u32 reoct_u; /* 128 etherStatsOctets */ |
141 | u32 reoct_l; /* 12c etherStatsOctets */ |
142 | u32 rpkt_u; /* 130 etherStatsPkts */ |
143 | u32 rpkt_l; /* 134 etherStatsPkts */ |
144 | u32 trund_u; /* 138 etherStatsUndersizePkts */ |
145 | u32 trund_l; /* 13c etherStatsUndersizePkts */ |
146 | u32 r64_u; /* 140 etherStatsPkts64Octets */ |
147 | u32 r64_l; /* 144 etherStatsPkts64Octets */ |
148 | u32 r127_u; /* 148 etherStatsPkts65to127Octets */ |
149 | u32 r127_l; /* 14c etherStatsPkts65to127Octets */ |
150 | u32 r255_u; /* 150 etherStatsPkts128to255Octets */ |
151 | u32 r255_l; /* 154 etherStatsPkts128to255Octets */ |
152 | u32 r511_u; /* 158 etherStatsPkts256to511Octets */ |
153 | u32 r511_l; /* 15c etherStatsPkts256to511Octets */ |
154 | u32 r1023_u; /* 160 etherStatsPkts512to1023Octets */ |
155 | u32 r1023_l; /* 164 etherStatsPkts512to1023Octets */ |
156 | u32 r1518_u; /* 168 etherStatsPkts1024to1518Octets */ |
157 | u32 r1518_l; /* 16c etherStatsPkts1024to1518Octets */ |
158 | u32 r1519x_u; /* 170 etherStatsPkts1519toX */ |
159 | u32 r1519x_l; /* 174 etherStatsPkts1519toX */ |
160 | u32 trovr_u; /* 178 etherStatsOversizePkts */ |
161 | u32 trovr_l; /* 17c etherStatsOversizePkts */ |
162 | u32 trjbr_u; /* 180 etherStatsJabbers */ |
163 | u32 trjbr_l; /* 184 etherStatsJabbers */ |
164 | u32 trfrg_u; /* 188 etherStatsFragments */ |
165 | u32 trfrg_l; /* 18C etherStatsFragments */ |
166 | u32 rerr_u; /* 190 if_in_errors */ |
167 | u32 rerr_l; /* 194 if_in_errors */ |
168 | }; |
169 | |
170 | struct tgec_cfg { |
171 | bool pause_ignore; |
172 | bool promiscuous_mode_enable; |
173 | u16 max_frame_length; |
174 | u16 pause_quant; |
175 | u32 tx_ipg_length; |
176 | }; |
177 | |
178 | struct fman_mac { |
179 | /* Pointer to the memory mapped registers. */ |
180 | struct tgec_regs __iomem *regs; |
181 | /* MAC address of device; */ |
182 | u64 addr; |
183 | u16 max_speed; |
184 | struct mac_device *dev_id; /* device cookie used by the exception cbs */ |
185 | fman_mac_exception_cb *exception_cb; |
186 | fman_mac_exception_cb *event_cb; |
187 | /* pointer to driver's global address hash table */ |
188 | struct eth_hash_t *multicast_addr_hash; |
189 | /* pointer to driver's individual address hash table */ |
190 | struct eth_hash_t *unicast_addr_hash; |
191 | u8 mac_id; |
192 | u32 exceptions; |
193 | struct tgec_cfg *cfg; |
194 | void *fm; |
195 | struct fman_rev_info fm_rev_info; |
196 | bool allmulti_enabled; |
197 | }; |
198 | |
199 | static void set_mac_address(struct tgec_regs __iomem *regs, const u8 *adr) |
200 | { |
201 | u32 tmp0, tmp1; |
202 | |
203 | tmp0 = (u32)(adr[0] | adr[1] << 8 | adr[2] << 16 | adr[3] << 24); |
204 | tmp1 = (u32)(adr[4] | adr[5] << 8); |
205 | iowrite32be(tmp0, ®s->mac_addr_0); |
206 | iowrite32be(tmp1, ®s->mac_addr_1); |
207 | } |
208 | |
209 | static void set_dflts(struct tgec_cfg *cfg) |
210 | { |
211 | cfg->promiscuous_mode_enable = false; |
212 | cfg->pause_ignore = false; |
213 | cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH; |
214 | cfg->max_frame_length = DEFAULT_MAX_FRAME_LENGTH; |
215 | cfg->pause_quant = DEFAULT_PAUSE_QUANT; |
216 | } |
217 | |
218 | static int init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg, |
219 | u32 exception_mask) |
220 | { |
221 | u32 tmp; |
222 | |
223 | /* Config */ |
224 | tmp = CMF_CFG_CRC_FWD; |
225 | if (cfg->promiscuous_mode_enable) |
226 | tmp |= CMD_CFG_PROMIS_EN; |
227 | if (cfg->pause_ignore) |
228 | tmp |= CMD_CFG_PAUSE_IGNORE; |
229 | /* Payload length check disable */ |
230 | tmp |= CMD_CFG_NO_LEN_CHK; |
231 | iowrite32be(tmp, ®s->command_config); |
232 | |
233 | /* Max Frame Length */ |
234 | iowrite32be((u32)cfg->max_frame_length, ®s->maxfrm); |
235 | /* Pause Time */ |
236 | iowrite32be(cfg->pause_quant, ®s->pause_quant); |
237 | |
238 | /* clear all pending events and set-up interrupts */ |
239 | iowrite32be(0xffffffff, ®s->ievent); |
240 | iowrite32be(ioread32be(®s->imask) | exception_mask, ®s->imask); |
241 | |
242 | return 0; |
243 | } |
244 | |
245 | static int check_init_parameters(struct fman_mac *tgec) |
246 | { |
247 | if (!tgec->exception_cb) { |
248 | pr_err("uninitialized exception_cb\n" ); |
249 | return -EINVAL; |
250 | } |
251 | if (!tgec->event_cb) { |
252 | pr_err("uninitialized event_cb\n" ); |
253 | return -EINVAL; |
254 | } |
255 | |
256 | return 0; |
257 | } |
258 | |
259 | static int get_exception_flag(enum fman_mac_exceptions exception) |
260 | { |
261 | u32 bit_mask; |
262 | |
263 | switch (exception) { |
264 | case FM_MAC_EX_10G_MDIO_SCAN_EVENT: |
265 | bit_mask = TGEC_IMASK_MDIO_SCAN_EVENT; |
266 | break; |
267 | case FM_MAC_EX_10G_MDIO_CMD_CMPL: |
268 | bit_mask = TGEC_IMASK_MDIO_CMD_CMPL; |
269 | break; |
270 | case FM_MAC_EX_10G_REM_FAULT: |
271 | bit_mask = TGEC_IMASK_REM_FAULT; |
272 | break; |
273 | case FM_MAC_EX_10G_LOC_FAULT: |
274 | bit_mask = TGEC_IMASK_LOC_FAULT; |
275 | break; |
276 | case FM_MAC_EX_10G_TX_ECC_ER: |
277 | bit_mask = TGEC_IMASK_TX_ECC_ER; |
278 | break; |
279 | case FM_MAC_EX_10G_TX_FIFO_UNFL: |
280 | bit_mask = TGEC_IMASK_TX_FIFO_UNFL; |
281 | break; |
282 | case FM_MAC_EX_10G_TX_FIFO_OVFL: |
283 | bit_mask = TGEC_IMASK_TX_FIFO_OVFL; |
284 | break; |
285 | case FM_MAC_EX_10G_TX_ER: |
286 | bit_mask = TGEC_IMASK_TX_ER; |
287 | break; |
288 | case FM_MAC_EX_10G_RX_FIFO_OVFL: |
289 | bit_mask = TGEC_IMASK_RX_FIFO_OVFL; |
290 | break; |
291 | case FM_MAC_EX_10G_RX_ECC_ER: |
292 | bit_mask = TGEC_IMASK_RX_ECC_ER; |
293 | break; |
294 | case FM_MAC_EX_10G_RX_JAB_FRM: |
295 | bit_mask = TGEC_IMASK_RX_JAB_FRM; |
296 | break; |
297 | case FM_MAC_EX_10G_RX_OVRSZ_FRM: |
298 | bit_mask = TGEC_IMASK_RX_OVRSZ_FRM; |
299 | break; |
300 | case FM_MAC_EX_10G_RX_RUNT_FRM: |
301 | bit_mask = TGEC_IMASK_RX_RUNT_FRM; |
302 | break; |
303 | case FM_MAC_EX_10G_RX_FRAG_FRM: |
304 | bit_mask = TGEC_IMASK_RX_FRAG_FRM; |
305 | break; |
306 | case FM_MAC_EX_10G_RX_LEN_ER: |
307 | bit_mask = TGEC_IMASK_RX_LEN_ER; |
308 | break; |
309 | case FM_MAC_EX_10G_RX_CRC_ER: |
310 | bit_mask = TGEC_IMASK_RX_CRC_ER; |
311 | break; |
312 | case FM_MAC_EX_10G_RX_ALIGN_ER: |
313 | bit_mask = TGEC_IMASK_RX_ALIGN_ER; |
314 | break; |
315 | default: |
316 | bit_mask = 0; |
317 | break; |
318 | } |
319 | |
320 | return bit_mask; |
321 | } |
322 | |
323 | static void tgec_err_exception(void *handle) |
324 | { |
325 | struct fman_mac *tgec = (struct fman_mac *)handle; |
326 | struct tgec_regs __iomem *regs = tgec->regs; |
327 | u32 event; |
328 | |
329 | /* do not handle MDIO events */ |
330 | event = ioread32be(®s->ievent) & |
331 | ~(TGEC_IMASK_MDIO_SCAN_EVENT | |
332 | TGEC_IMASK_MDIO_CMD_CMPL); |
333 | |
334 | event &= ioread32be(®s->imask); |
335 | |
336 | iowrite32be(event, ®s->ievent); |
337 | |
338 | if (event & TGEC_IMASK_REM_FAULT) |
339 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_REM_FAULT); |
340 | if (event & TGEC_IMASK_LOC_FAULT) |
341 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_LOC_FAULT); |
342 | if (event & TGEC_IMASK_TX_ECC_ER) |
343 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_ECC_ER); |
344 | if (event & TGEC_IMASK_TX_FIFO_UNFL) |
345 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_FIFO_UNFL); |
346 | if (event & TGEC_IMASK_TX_FIFO_OVFL) |
347 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_FIFO_OVFL); |
348 | if (event & TGEC_IMASK_TX_ER) |
349 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_TX_ER); |
350 | if (event & TGEC_IMASK_RX_FIFO_OVFL) |
351 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_FIFO_OVFL); |
352 | if (event & TGEC_IMASK_RX_ECC_ER) |
353 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_ECC_ER); |
354 | if (event & TGEC_IMASK_RX_JAB_FRM) |
355 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_JAB_FRM); |
356 | if (event & TGEC_IMASK_RX_OVRSZ_FRM) |
357 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_OVRSZ_FRM); |
358 | if (event & TGEC_IMASK_RX_RUNT_FRM) |
359 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_RUNT_FRM); |
360 | if (event & TGEC_IMASK_RX_FRAG_FRM) |
361 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_FRAG_FRM); |
362 | if (event & TGEC_IMASK_RX_LEN_ER) |
363 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_LEN_ER); |
364 | if (event & TGEC_IMASK_RX_CRC_ER) |
365 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_CRC_ER); |
366 | if (event & TGEC_IMASK_RX_ALIGN_ER) |
367 | tgec->exception_cb(tgec->dev_id, FM_MAC_EX_10G_RX_ALIGN_ER); |
368 | } |
369 | |
370 | static void free_init_resources(struct fman_mac *tgec) |
371 | { |
372 | fman_unregister_intr(fman: tgec->fm, mod: FMAN_MOD_MAC, mod_id: tgec->mac_id, |
373 | intr_type: FMAN_INTR_TYPE_ERR); |
374 | |
375 | /* release the driver's group hash table */ |
376 | free_hash_table(hash: tgec->multicast_addr_hash); |
377 | tgec->multicast_addr_hash = NULL; |
378 | |
379 | /* release the driver's individual hash table */ |
380 | free_hash_table(hash: tgec->unicast_addr_hash); |
381 | tgec->unicast_addr_hash = NULL; |
382 | } |
383 | |
384 | static int tgec_enable(struct fman_mac *tgec) |
385 | { |
386 | return 0; |
387 | } |
388 | |
389 | static void tgec_disable(struct fman_mac *tgec) |
390 | { |
391 | } |
392 | |
393 | static int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val) |
394 | { |
395 | struct tgec_regs __iomem *regs = tgec->regs; |
396 | u32 tmp; |
397 | |
398 | tmp = ioread32be(®s->command_config); |
399 | if (new_val) |
400 | tmp |= CMD_CFG_PROMIS_EN; |
401 | else |
402 | tmp &= ~CMD_CFG_PROMIS_EN; |
403 | iowrite32be(tmp, ®s->command_config); |
404 | |
405 | return 0; |
406 | } |
407 | |
408 | static int tgec_set_tx_pause_frames(struct fman_mac *tgec, |
409 | u8 __maybe_unused priority, u16 pause_time, |
410 | u16 __maybe_unused thresh_time) |
411 | { |
412 | struct tgec_regs __iomem *regs = tgec->regs; |
413 | |
414 | iowrite32be((u32)pause_time, ®s->pause_quant); |
415 | |
416 | return 0; |
417 | } |
418 | |
419 | static int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en) |
420 | { |
421 | struct tgec_regs __iomem *regs = tgec->regs; |
422 | u32 tmp; |
423 | |
424 | tmp = ioread32be(®s->command_config); |
425 | if (!en) |
426 | tmp |= CMD_CFG_PAUSE_IGNORE; |
427 | else |
428 | tmp &= ~CMD_CFG_PAUSE_IGNORE; |
429 | iowrite32be(tmp, ®s->command_config); |
430 | |
431 | return 0; |
432 | } |
433 | |
434 | static void tgec_mac_config(struct phylink_config *config, unsigned int mode, |
435 | const struct phylink_link_state *state) |
436 | { |
437 | } |
438 | |
439 | static void tgec_link_up(struct phylink_config *config, struct phy_device *phy, |
440 | unsigned int mode, phy_interface_t interface, |
441 | int speed, int duplex, bool tx_pause, bool rx_pause) |
442 | { |
443 | struct mac_device *mac_dev = fman_config_to_mac(config); |
444 | struct fman_mac *tgec = mac_dev->fman_mac; |
445 | struct tgec_regs __iomem *regs = tgec->regs; |
446 | u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE : |
447 | FSL_FM_PAUSE_TIME_DISABLE; |
448 | u32 tmp; |
449 | |
450 | tgec_set_tx_pause_frames(tgec, priority: 0, pause_time, thresh_time: 0); |
451 | tgec_accept_rx_pause_frames(tgec, en: rx_pause); |
452 | mac_dev->update_speed(mac_dev, speed); |
453 | |
454 | tmp = ioread32be(®s->command_config); |
455 | tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN; |
456 | iowrite32be(tmp, ®s->command_config); |
457 | } |
458 | |
459 | static void tgec_link_down(struct phylink_config *config, unsigned int mode, |
460 | phy_interface_t interface) |
461 | { |
462 | struct fman_mac *tgec = fman_config_to_mac(config)->fman_mac; |
463 | struct tgec_regs __iomem *regs = tgec->regs; |
464 | u32 tmp; |
465 | |
466 | tmp = ioread32be(®s->command_config); |
467 | tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN); |
468 | iowrite32be(tmp, ®s->command_config); |
469 | } |
470 | |
471 | static const struct phylink_mac_ops tgec_mac_ops = { |
472 | .mac_config = tgec_mac_config, |
473 | .mac_link_up = tgec_link_up, |
474 | .mac_link_down = tgec_link_down, |
475 | }; |
476 | |
477 | static int tgec_modify_mac_address(struct fman_mac *tgec, |
478 | const enet_addr_t *p_enet_addr) |
479 | { |
480 | tgec->addr = ENET_ADDR_TO_UINT64(*p_enet_addr); |
481 | set_mac_address(regs: tgec->regs, adr: (const u8 *)(*p_enet_addr)); |
482 | |
483 | return 0; |
484 | } |
485 | |
486 | static int tgec_add_hash_mac_address(struct fman_mac *tgec, |
487 | enet_addr_t *eth_addr) |
488 | { |
489 | struct tgec_regs __iomem *regs = tgec->regs; |
490 | struct eth_hash_entry *hash_entry; |
491 | u32 crc = 0xFFFFFFFF, hash; |
492 | u64 addr; |
493 | |
494 | addr = ENET_ADDR_TO_UINT64(*eth_addr); |
495 | |
496 | if (!(addr & GROUP_ADDRESS)) { |
497 | /* Unicast addresses not supported in hash */ |
498 | pr_err("Unicast Address\n" ); |
499 | return -EINVAL; |
500 | } |
501 | /* CRC calculation */ |
502 | crc = crc32_le(crc, p: (u8 *)eth_addr, ETH_ALEN); |
503 | crc = bitrev32(crc); |
504 | /* Take 9 MSB bits */ |
505 | hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; |
506 | |
507 | /* Create element to be added to the driver hash table */ |
508 | hash_entry = kmalloc(size: sizeof(*hash_entry), GFP_ATOMIC); |
509 | if (!hash_entry) |
510 | return -ENOMEM; |
511 | hash_entry->addr = addr; |
512 | INIT_LIST_HEAD(list: &hash_entry->node); |
513 | |
514 | list_add_tail(new: &hash_entry->node, |
515 | head: &tgec->multicast_addr_hash->lsts[hash]); |
516 | iowrite32be((hash | TGEC_HASH_MCAST_EN), ®s->hashtable_ctrl); |
517 | |
518 | return 0; |
519 | } |
520 | |
521 | static int tgec_set_allmulti(struct fman_mac *tgec, bool enable) |
522 | { |
523 | u32 entry; |
524 | struct tgec_regs __iomem *regs = tgec->regs; |
525 | |
526 | if (enable) { |
527 | for (entry = 0; entry < TGEC_HASH_TABLE_SIZE; entry++) |
528 | iowrite32be(entry | TGEC_HASH_MCAST_EN, |
529 | ®s->hashtable_ctrl); |
530 | } else { |
531 | for (entry = 0; entry < TGEC_HASH_TABLE_SIZE; entry++) |
532 | iowrite32be(entry & ~TGEC_HASH_MCAST_EN, |
533 | ®s->hashtable_ctrl); |
534 | } |
535 | |
536 | tgec->allmulti_enabled = enable; |
537 | |
538 | return 0; |
539 | } |
540 | |
541 | static int tgec_set_tstamp(struct fman_mac *tgec, bool enable) |
542 | { |
543 | struct tgec_regs __iomem *regs = tgec->regs; |
544 | u32 tmp; |
545 | |
546 | tmp = ioread32be(®s->command_config); |
547 | |
548 | if (enable) |
549 | tmp |= CMD_CFG_EN_TIMESTAMP; |
550 | else |
551 | tmp &= ~CMD_CFG_EN_TIMESTAMP; |
552 | |
553 | iowrite32be(tmp, ®s->command_config); |
554 | |
555 | return 0; |
556 | } |
557 | |
558 | static int tgec_del_hash_mac_address(struct fman_mac *tgec, |
559 | enet_addr_t *eth_addr) |
560 | { |
561 | struct tgec_regs __iomem *regs = tgec->regs; |
562 | struct eth_hash_entry *hash_entry = NULL; |
563 | struct list_head *pos; |
564 | u32 crc = 0xFFFFFFFF, hash; |
565 | u64 addr; |
566 | |
567 | addr = ((*(u64 *)eth_addr) >> 16); |
568 | |
569 | /* CRC calculation */ |
570 | crc = crc32_le(crc, p: (u8 *)eth_addr, ETH_ALEN); |
571 | crc = bitrev32(crc); |
572 | /* Take 9 MSB bits */ |
573 | hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; |
574 | |
575 | list_for_each(pos, &tgec->multicast_addr_hash->lsts[hash]) { |
576 | hash_entry = ETH_HASH_ENTRY_OBJ(pos); |
577 | if (hash_entry && hash_entry->addr == addr) { |
578 | list_del_init(entry: &hash_entry->node); |
579 | kfree(objp: hash_entry); |
580 | break; |
581 | } |
582 | } |
583 | |
584 | if (!tgec->allmulti_enabled) { |
585 | if (list_empty(head: &tgec->multicast_addr_hash->lsts[hash])) |
586 | iowrite32be((hash & ~TGEC_HASH_MCAST_EN), |
587 | ®s->hashtable_ctrl); |
588 | } |
589 | |
590 | return 0; |
591 | } |
592 | |
593 | static int tgec_set_exception(struct fman_mac *tgec, |
594 | enum fman_mac_exceptions exception, bool enable) |
595 | { |
596 | struct tgec_regs __iomem *regs = tgec->regs; |
597 | u32 bit_mask = 0; |
598 | |
599 | bit_mask = get_exception_flag(exception); |
600 | if (bit_mask) { |
601 | if (enable) |
602 | tgec->exceptions |= bit_mask; |
603 | else |
604 | tgec->exceptions &= ~bit_mask; |
605 | } else { |
606 | pr_err("Undefined exception\n" ); |
607 | return -EINVAL; |
608 | } |
609 | if (enable) |
610 | iowrite32be(ioread32be(®s->imask) | bit_mask, ®s->imask); |
611 | else |
612 | iowrite32be(ioread32be(®s->imask) & ~bit_mask, ®s->imask); |
613 | |
614 | return 0; |
615 | } |
616 | |
617 | static int tgec_init(struct fman_mac *tgec) |
618 | { |
619 | struct tgec_cfg *cfg; |
620 | enet_addr_t eth_addr; |
621 | int err; |
622 | |
623 | if (DEFAULT_RESET_ON_INIT && |
624 | (fman_reset_mac(fman: tgec->fm, mac_id: tgec->mac_id) != 0)) { |
625 | pr_err("Can't reset MAC!\n" ); |
626 | return -EINVAL; |
627 | } |
628 | |
629 | err = check_init_parameters(tgec); |
630 | if (err) |
631 | return err; |
632 | |
633 | cfg = tgec->cfg; |
634 | |
635 | if (tgec->addr) { |
636 | MAKE_ENET_ADDR_FROM_UINT64(tgec->addr, eth_addr); |
637 | set_mac_address(regs: tgec->regs, adr: (const u8 *)eth_addr); |
638 | } |
639 | |
640 | /* interrupts */ |
641 | /* FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 Errata workaround */ |
642 | if (tgec->fm_rev_info.major <= 2) |
643 | tgec->exceptions &= ~(TGEC_IMASK_REM_FAULT | |
644 | TGEC_IMASK_LOC_FAULT); |
645 | |
646 | err = init(regs: tgec->regs, cfg, exception_mask: tgec->exceptions); |
647 | if (err) { |
648 | free_init_resources(tgec); |
649 | pr_err("TGEC version doesn't support this i/f mode\n" ); |
650 | return err; |
651 | } |
652 | |
653 | /* Max Frame Length */ |
654 | err = fman_set_mac_max_frame(fman: tgec->fm, mac_id: tgec->mac_id, |
655 | mfl: cfg->max_frame_length); |
656 | if (err) { |
657 | pr_err("Setting max frame length FAILED\n" ); |
658 | free_init_resources(tgec); |
659 | return -EINVAL; |
660 | } |
661 | |
662 | /* FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 Errata workaround */ |
663 | if (tgec->fm_rev_info.major == 2) { |
664 | struct tgec_regs __iomem *regs = tgec->regs; |
665 | u32 tmp; |
666 | |
667 | /* restore the default tx ipg Length */ |
668 | tmp = (ioread32be(®s->tx_ipg_len) & |
669 | ~TGEC_TX_IPG_LENGTH_MASK) | 12; |
670 | |
671 | iowrite32be(tmp, ®s->tx_ipg_len); |
672 | } |
673 | |
674 | tgec->multicast_addr_hash = alloc_hash_table(TGEC_HASH_TABLE_SIZE); |
675 | if (!tgec->multicast_addr_hash) { |
676 | free_init_resources(tgec); |
677 | pr_err("allocation hash table is FAILED\n" ); |
678 | return -ENOMEM; |
679 | } |
680 | |
681 | tgec->unicast_addr_hash = alloc_hash_table(TGEC_HASH_TABLE_SIZE); |
682 | if (!tgec->unicast_addr_hash) { |
683 | free_init_resources(tgec); |
684 | pr_err("allocation hash table is FAILED\n" ); |
685 | return -ENOMEM; |
686 | } |
687 | |
688 | fman_register_intr(fman: tgec->fm, mod: FMAN_MOD_MAC, mod_id: tgec->mac_id, |
689 | intr_type: FMAN_INTR_TYPE_ERR, f_isr: tgec_err_exception, h_src_arg: tgec); |
690 | |
691 | kfree(objp: cfg); |
692 | tgec->cfg = NULL; |
693 | |
694 | return 0; |
695 | } |
696 | |
697 | static int tgec_free(struct fman_mac *tgec) |
698 | { |
699 | free_init_resources(tgec); |
700 | |
701 | kfree(objp: tgec->cfg); |
702 | kfree(objp: tgec); |
703 | |
704 | return 0; |
705 | } |
706 | |
707 | static struct fman_mac *tgec_config(struct mac_device *mac_dev, |
708 | struct fman_mac_params *params) |
709 | { |
710 | struct fman_mac *tgec; |
711 | struct tgec_cfg *cfg; |
712 | |
713 | /* allocate memory for the UCC GETH data structure. */ |
714 | tgec = kzalloc(size: sizeof(*tgec), GFP_KERNEL); |
715 | if (!tgec) |
716 | return NULL; |
717 | |
718 | /* allocate memory for the 10G MAC driver parameters data structure. */ |
719 | cfg = kzalloc(size: sizeof(*cfg), GFP_KERNEL); |
720 | if (!cfg) { |
721 | tgec_free(tgec); |
722 | return NULL; |
723 | } |
724 | |
725 | /* Plant parameter structure pointer */ |
726 | tgec->cfg = cfg; |
727 | |
728 | set_dflts(cfg); |
729 | |
730 | tgec->regs = mac_dev->vaddr; |
731 | tgec->addr = ENET_ADDR_TO_UINT64(mac_dev->addr); |
732 | tgec->mac_id = params->mac_id; |
733 | tgec->exceptions = (TGEC_IMASK_MDIO_SCAN_EVENT | |
734 | TGEC_IMASK_REM_FAULT | |
735 | TGEC_IMASK_LOC_FAULT | |
736 | TGEC_IMASK_TX_ECC_ER | |
737 | TGEC_IMASK_TX_FIFO_UNFL | |
738 | TGEC_IMASK_TX_FIFO_OVFL | |
739 | TGEC_IMASK_TX_ER | |
740 | TGEC_IMASK_RX_FIFO_OVFL | |
741 | TGEC_IMASK_RX_ECC_ER | |
742 | TGEC_IMASK_RX_JAB_FRM | |
743 | TGEC_IMASK_RX_OVRSZ_FRM | |
744 | TGEC_IMASK_RX_RUNT_FRM | |
745 | TGEC_IMASK_RX_FRAG_FRM | |
746 | TGEC_IMASK_RX_CRC_ER | |
747 | TGEC_IMASK_RX_ALIGN_ER); |
748 | tgec->exception_cb = params->exception_cb; |
749 | tgec->event_cb = params->event_cb; |
750 | tgec->dev_id = mac_dev; |
751 | tgec->fm = params->fm; |
752 | |
753 | /* Save FMan revision */ |
754 | fman_get_revision(fman: tgec->fm, rev_info: &tgec->fm_rev_info); |
755 | |
756 | return tgec; |
757 | } |
758 | |
759 | int tgec_initialization(struct mac_device *mac_dev, |
760 | struct device_node *mac_node, |
761 | struct fman_mac_params *params) |
762 | { |
763 | int err; |
764 | struct fman_mac *tgec; |
765 | |
766 | mac_dev->phylink_ops = &tgec_mac_ops; |
767 | mac_dev->set_promisc = tgec_set_promiscuous; |
768 | mac_dev->change_addr = tgec_modify_mac_address; |
769 | mac_dev->add_hash_mac_addr = tgec_add_hash_mac_address; |
770 | mac_dev->remove_hash_mac_addr = tgec_del_hash_mac_address; |
771 | mac_dev->set_exception = tgec_set_exception; |
772 | mac_dev->set_allmulti = tgec_set_allmulti; |
773 | mac_dev->set_tstamp = tgec_set_tstamp; |
774 | mac_dev->set_multi = fman_set_multi; |
775 | mac_dev->enable = tgec_enable; |
776 | mac_dev->disable = tgec_disable; |
777 | |
778 | mac_dev->fman_mac = tgec_config(mac_dev, params); |
779 | if (!mac_dev->fman_mac) { |
780 | err = -EINVAL; |
781 | goto _return; |
782 | } |
783 | |
784 | /* The internal connection to the serdes is XGMII, but this isn't |
785 | * really correct for the phy mode (which is the external connection). |
786 | * However, this is how all older device trees say that they want |
787 | * XAUI, so just convert it for them. |
788 | */ |
789 | if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII) |
790 | mac_dev->phy_if = PHY_INTERFACE_MODE_XAUI; |
791 | |
792 | __set_bit(PHY_INTERFACE_MODE_XAUI, |
793 | mac_dev->phylink_config.supported_interfaces); |
794 | mac_dev->phylink_config.mac_capabilities = |
795 | MAC_SYM_PAUSE | MAC_ASYM_PAUSE | MAC_10000FD; |
796 | |
797 | tgec = mac_dev->fman_mac; |
798 | tgec->cfg->max_frame_length = fman_get_max_frm(); |
799 | err = tgec_init(tgec); |
800 | if (err < 0) |
801 | goto _return_fm_mac_free; |
802 | |
803 | /* For 10G MAC, disable Tx ECC exception */ |
804 | err = tgec_set_exception(tgec, exception: FM_MAC_EX_10G_TX_ECC_ER, enable: false); |
805 | if (err < 0) |
806 | goto _return_fm_mac_free; |
807 | |
808 | pr_info("FMan XGEC version: 0x%08x\n" , |
809 | ioread32be(&tgec->regs->tgec_id)); |
810 | goto _return; |
811 | |
812 | _return_fm_mac_free: |
813 | tgec_free(tgec: mac_dev->fman_mac); |
814 | |
815 | _return: |
816 | return err; |
817 | } |
818 | |