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