aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/chelsio/pm3393.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/chelsio/pm3393.c')
-rw-r--r--drivers/net/chelsio/pm3393.c831
1 files changed, 831 insertions, 0 deletions
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c
new file mode 100644
index 000000000000..17bd20f60d99
--- /dev/null
+++ b/drivers/net/chelsio/pm3393.c
@@ -0,0 +1,831 @@
1/*****************************************************************************
2 * *
3 * File: pm3393.c *
4 * $Revision: 1.9 $ *
5 * $Date: 2005/03/23 07:41:27 $ *
6 * Description: *
7 * PMC/SIERRA (pm3393) MAC-PHY functionality. *
8 * part of the Chelsio 10Gb Ethernet Driver. *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License, version 2, as *
12 * published by the Free Software Foundation. *
13 * *
14 * You should have received a copy of the GNU General Public License along *
15 * with this program; if not, write to the Free Software Foundation, Inc., *
16 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
17 * *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED *
19 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF *
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
21 * *
22 * http://www.chelsio.com *
23 * *
24 * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. *
25 * All rights reserved. *
26 * *
27 * Maintainers: maintainers@chelsio.com *
28 * *
29 * Authors: Dimitrios Michailidis <dm@chelsio.com> *
30 * Tina Yang <tainay@chelsio.com> *
31 * Felix Marti <felix@chelsio.com> *
32 * Scott Bardone <sbardone@chelsio.com> *
33 * Kurt Ottaway <kottaway@chelsio.com> *
34 * Frank DiMambro <frank@chelsio.com> *
35 * *
36 * History: *
37 * *
38 ****************************************************************************/
39
40#include "common.h"
41#include "regs.h"
42#include "gmac.h"
43#include "elmer0.h"
44#include "suni1x10gexp_regs.h"
45
46/* 802.3ae 10Gb/s MDIO Manageable Device(MMD)
47 */
48#define MMD_RESERVED 0
49#define MMD_PMAPMD 1
50#define MMD_WIS 2
51#define MMD_PCS 3
52#define MMD_PHY_XGXS 4 /* XGMII Extender Sublayer */
53#define MMD_DTE_XGXS 5
54
55#define PHY_XGXS_CTRL_1 0
56#define PHY_XGXS_STATUS_1 1
57
58#define OFFSET(REG_ADDR) (REG_ADDR << 2)
59
60/* Max frame size PM3393 can handle. Includes Ethernet header and CRC. */
61#define MAX_FRAME_SIZE 9600
62
63#define IPG 12
64#define TXXG_CONF1_VAL ((IPG << SUNI1x10GEXP_BITOFF_TXXG_IPGT) | \
65 SUNI1x10GEXP_BITMSK_TXXG_32BIT_ALIGN | SUNI1x10GEXP_BITMSK_TXXG_CRCEN | \
66 SUNI1x10GEXP_BITMSK_TXXG_PADEN)
67#define RXXG_CONF1_VAL (SUNI1x10GEXP_BITMSK_RXXG_PUREP | 0x14 | \
68 SUNI1x10GEXP_BITMSK_RXXG_FLCHK | SUNI1x10GEXP_BITMSK_RXXG_CRC_STRIP)
69
70/* Update statistics every 15 minutes */
71#define STATS_TICK_SECS (15 * 60)
72
73enum { /* RMON registers */
74 RxOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW,
75 RxUnicastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_4_LOW,
76 RxMulticastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_5_LOW,
77 RxBroadcastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_6_LOW,
78 RxPAUSEMACCtrlFramesReceived = SUNI1x10GEXP_REG_MSTAT_COUNTER_8_LOW,
79 RxFrameCheckSequenceErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_10_LOW,
80 RxFramesLostDueToInternalMACErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_11_LOW,
81 RxSymbolErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_12_LOW,
82 RxInRangeLengthErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_13_LOW,
83 RxFramesTooLongErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_15_LOW,
84 RxJabbers = SUNI1x10GEXP_REG_MSTAT_COUNTER_16_LOW,
85 RxFragments = SUNI1x10GEXP_REG_MSTAT_COUNTER_17_LOW,
86 RxUndersizedFrames = SUNI1x10GEXP_REG_MSTAT_COUNTER_18_LOW,
87
88 TxOctetsTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW,
89 TxFramesLostDueToInternalMACTransmissionError = SUNI1x10GEXP_REG_MSTAT_COUNTER_35_LOW,
90 TxTransmitSystemError = SUNI1x10GEXP_REG_MSTAT_COUNTER_36_LOW,
91 TxUnicastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_38_LOW,
92 TxMulticastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_40_LOW,
93 TxBroadcastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_42_LOW,
94 TxPAUSEMACCtrlFramesTransmitted = SUNI1x10GEXP_REG_MSTAT_COUNTER_43_LOW
95};
96
97struct _cmac_instance {
98 u8 enabled;
99 u8 fc;
100 u8 mac_addr[6];
101};
102
103static int pmread(struct cmac *cmac, u32 reg, u32 * data32)
104{
105 t1_tpi_read(cmac->adapter, OFFSET(reg), data32);
106 return 0;
107}
108
109static int pmwrite(struct cmac *cmac, u32 reg, u32 data32)
110{
111 t1_tpi_write(cmac->adapter, OFFSET(reg), data32);
112 return 0;
113}
114
115/* Port reset. */
116static int pm3393_reset(struct cmac *cmac)
117{
118 return 0;
119}
120
121/*
122 * Enable interrupts for the PM3393
123
124 1. Enable PM3393 BLOCK interrupts.
125 2. Enable PM3393 Master Interrupt bit(INTE)
126 3. Enable ELMER's PM3393 bit.
127 4. Enable Terminator external interrupt.
128*/
129static int pm3393_interrupt_enable(struct cmac *cmac)
130{
131 u32 pl_intr;
132
133 /* PM3393 - Enabling all hardware block interrupts.
134 */
135 pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0xffff);
136 pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0xffff);
137 pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0xffff);
138 pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0xffff);
139
140 /* Don't interrupt on statistics overflow, we are polling */
141 pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0);
142 pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0);
143 pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0);
144 pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0);
145
146 pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0xffff);
147 pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0xffff);
148 pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0xffff);
149 pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0xffff);
150 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0xffff);
151 pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0xffff);
152 pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0xffff);
153 pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0xffff);
154 pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0xffff);
155
156 /* PM3393 - Global interrupt enable
157 */
158 /* TBD XXX Disable for now until we figure out why error interrupts keep asserting. */
159 pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE,
160 0 /*SUNI1x10GEXP_BITMSK_TOP_INTE */ );
161
162 /* TERMINATOR - PL_INTERUPTS_EXT */
163 pl_intr = t1_read_reg_4(cmac->adapter, A_PL_ENABLE);
164 pl_intr |= F_PL_INTR_EXT;
165 t1_write_reg_4(cmac->adapter, A_PL_ENABLE, pl_intr);
166 return 0;
167}
168
169static int pm3393_interrupt_disable(struct cmac *cmac)
170{
171 u32 elmer;
172
173 /* PM3393 - Enabling HW interrupt blocks. */
174 pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0);
175 pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0);
176 pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0);
177 pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0);
178 pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0);
179 pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0);
180 pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0);
181 pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0);
182 pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0);
183 pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0);
184 pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0);
185 pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0);
186 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0);
187 pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0);
188 pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0);
189 pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0);
190 pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0);
191
192 /* PM3393 - Global interrupt enable */
193 pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0);
194
195 /* ELMER - External chip interrupts. */
196 t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer);
197 elmer &= ~ELMER0_GP_BIT1;
198 t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer);
199
200 /* TERMINATOR - PL_INTERUPTS_EXT */
201 /* DO NOT DISABLE TERMINATOR's EXTERNAL INTERRUPTS. ANOTHER CHIP
202 * COULD WANT THEM ENABLED. We disable PM3393 at the ELMER level.
203 */
204
205 return 0;
206}
207
208static int pm3393_interrupt_clear(struct cmac *cmac)
209{
210 u32 elmer;
211 u32 pl_intr;
212 u32 val32;
213
214 /* PM3393 - Clearing HW interrupt blocks. Note, this assumes
215 * bit WCIMODE=0 for a clear-on-read.
216 */
217 pmread(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_STATUS, &val32);
218 pmread(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_STATUS, &val32);
219 pmread(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_STATUS, &val32);
220 pmread(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_STATUS, &val32);
221 pmread(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT, &val32);
222 pmread(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_STATUS, &val32);
223 pmread(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_INTERRUPT, &val32);
224 pmread(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_STATUS, &val32);
225 pmread(cmac, SUNI1x10GEXP_REG_RXXG_INTERRUPT, &val32);
226 pmread(cmac, SUNI1x10GEXP_REG_TXXG_INTERRUPT, &val32);
227 pmread(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT, &val32);
228 pmread(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_INDICATION,
229 &val32);
230 pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_STATUS, &val32);
231 pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_CHANGE, &val32);
232
233 /* PM3393 - Global interrupt status
234 */
235 pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS, &val32);
236
237 /* ELMER - External chip interrupts.
238 */
239 t1_tpi_read(cmac->adapter, A_ELMER0_INT_CAUSE, &elmer);
240 elmer |= ELMER0_GP_BIT1;
241 t1_tpi_write(cmac->adapter, A_ELMER0_INT_CAUSE, elmer);
242
243 /* TERMINATOR - PL_INTERUPTS_EXT
244 */
245 pl_intr = t1_read_reg_4(cmac->adapter, A_PL_CAUSE);
246 pl_intr |= F_PL_INTR_EXT;
247 t1_write_reg_4(cmac->adapter, A_PL_CAUSE, pl_intr);
248
249 return 0;
250}
251
252/* Interrupt handler */
253static int pm3393_interrupt_handler(struct cmac *cmac)
254{
255 u32 master_intr_status;
256/*
257 1. Read master interrupt register.
258 2. Read BLOCK's interrupt status registers.
259 3. Handle BLOCK interrupts.
260*/
261 /* Read the master interrupt status register. */
262 pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS,
263 &master_intr_status);
264 CH_DBG(cmac->adapter, INTR, "PM3393 intr cause 0x%x\n",
265 master_intr_status);
266
267 /* TBD XXX Lets just clear everything for now */
268 pm3393_interrupt_clear(cmac);
269
270 return 0;
271}
272
273static int pm3393_enable(struct cmac *cmac, int which)
274{
275 if (which & MAC_DIRECTION_RX)
276 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1,
277 (RXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_RXXG_RXEN));
278
279 if (which & MAC_DIRECTION_TX) {
280 u32 val = TXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_TXXG_TXEN0;
281
282 if (cmac->instance->fc & PAUSE_RX)
283 val |= SUNI1x10GEXP_BITMSK_TXXG_FCRX;
284 if (cmac->instance->fc & PAUSE_TX)
285 val |= SUNI1x10GEXP_BITMSK_TXXG_FCTX;
286 pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, val);
287 }
288
289 cmac->instance->enabled |= which;
290 return 0;
291}
292
293static int pm3393_enable_port(struct cmac *cmac, int which)
294{
295 /* Clear port statistics */
296 pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
297 SUNI1x10GEXP_BITMSK_MSTAT_CLEAR);
298 udelay(2);
299 memset(&cmac->stats, 0, sizeof(struct cmac_statistics));
300
301 pm3393_enable(cmac, which);
302
303 /*
304 * XXX This should be done by the PHY and preferrably not at all.
305 * The PHY doesn't give us link status indication on its own so have
306 * the link management code query it instead.
307 */
308 {
309 extern void link_changed(adapter_t *adapter, int port_id);
310
311 link_changed(cmac->adapter, 0);
312 }
313 return 0;
314}
315
316static int pm3393_disable(struct cmac *cmac, int which)
317{
318 if (which & MAC_DIRECTION_RX)
319 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, RXXG_CONF1_VAL);
320 if (which & MAC_DIRECTION_TX)
321 pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, TXXG_CONF1_VAL);
322
323 /*
324 * The disable is graceful. Give the PM3393 time. Can't wait very
325 * long here, we may be holding locks.
326 */
327 udelay(20);
328
329 cmac->instance->enabled &= ~which;
330 return 0;
331}
332
333static int pm3393_loopback_enable(struct cmac *cmac)
334{
335 return 0;
336}
337
338static int pm3393_loopback_disable(struct cmac *cmac)
339{
340 return 0;
341}
342
343static int pm3393_set_mtu(struct cmac *cmac, int mtu)
344{
345 int enabled = cmac->instance->enabled;
346
347 /* MAX_FRAME_SIZE includes header + FCS, mtu doesn't */
348 mtu += 14 + 4;
349 if (mtu > MAX_FRAME_SIZE)
350 return -EINVAL;
351
352 /* Disable Rx/Tx MAC before configuring it. */
353 if (enabled)
354 pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
355
356 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH, mtu);
357 pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE, mtu);
358
359 if (enabled)
360 pm3393_enable(cmac, enabled);
361 return 0;
362}
363
364static u32 calc_crc(u8 *b, int len)
365{
366 int i;
367 u32 crc = (u32)~0;
368
369 /* calculate crc one bit at a time */
370 while (len--) {
371 crc ^= *b++;
372 for (i = 0; i < 8; i++) {
373 if (crc & 0x1)
374 crc = (crc >> 1) ^ 0xedb88320;
375 else
376 crc = (crc >> 1);
377 }
378 }
379
380 /* reverse bits */
381 crc = ((crc >> 4) & 0x0f0f0f0f) | ((crc << 4) & 0xf0f0f0f0);
382 crc = ((crc >> 2) & 0x33333333) | ((crc << 2) & 0xcccccccc);
383 crc = ((crc >> 1) & 0x55555555) | ((crc << 1) & 0xaaaaaaaa);
384 /* swap bytes */
385 crc = (crc >> 16) | (crc << 16);
386 crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
387
388 return crc;
389}
390
391static int pm3393_set_rx_mode(struct cmac *cmac, struct t1_rx_mode *rm)
392{
393 int enabled = cmac->instance->enabled & MAC_DIRECTION_RX;
394 u32 rx_mode;
395
396 /* Disable MAC RX before reconfiguring it */
397 if (enabled)
398 pm3393_disable(cmac, MAC_DIRECTION_RX);
399
400 pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, &rx_mode);
401 rx_mode &= ~(SUNI1x10GEXP_BITMSK_RXXG_PMODE |
402 SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN);
403 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2,
404 (u16)rx_mode);
405
406 if (t1_rx_mode_promisc(rm)) {
407 /* Promiscuous mode. */
408 rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_PMODE;
409 }
410 if (t1_rx_mode_allmulti(rm)) {
411 /* Accept all multicast. */
412 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, 0xffff);
413 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, 0xffff);
414 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, 0xffff);
415 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, 0xffff);
416 rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN;
417 } else if (t1_rx_mode_mc_cnt(rm)) {
418 /* Accept one or more multicast(s). */
419 u8 *addr;
420 int bit;
421 u16 mc_filter[4] = { 0, };
422
423 while ((addr = t1_get_next_mcaddr(rm))) {
424 bit = (calc_crc(addr, ETH_ALEN) >> 23) & 0x3f; /* bit[23:28] */
425 mc_filter[bit >> 4] |= 1 << (bit & 0xf);
426 }
427 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, mc_filter[0]);
428 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, mc_filter[1]);
429 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, mc_filter[2]);
430 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, mc_filter[3]);
431 rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN;
432 }
433
434 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, (u16)rx_mode);
435
436 if (enabled)
437 pm3393_enable(cmac, MAC_DIRECTION_RX);
438
439 return 0;
440}
441
442static int pm3393_get_speed_duplex_fc(struct cmac *cmac, int *speed,
443 int *duplex, int *fc)
444{
445 if (speed)
446 *speed = SPEED_10000;
447 if (duplex)
448 *duplex = DUPLEX_FULL;
449 if (fc)
450 *fc = cmac->instance->fc;
451 return 0;
452}
453
454static int pm3393_set_speed_duplex_fc(struct cmac *cmac, int speed, int duplex,
455 int fc)
456{
457 if (speed >= 0 && speed != SPEED_10000)
458 return -1;
459 if (duplex >= 0 && duplex != DUPLEX_FULL)
460 return -1;
461 if (fc & ~(PAUSE_TX | PAUSE_RX))
462 return -1;
463
464 if (fc != cmac->instance->fc) {
465 cmac->instance->fc = (u8) fc;
466 if (cmac->instance->enabled & MAC_DIRECTION_TX)
467 pm3393_enable(cmac, MAC_DIRECTION_TX);
468 }
469 return 0;
470}
471
472#define RMON_UPDATE(mac, name, stat_name) \
473 { \
474 t1_tpi_read((mac)->adapter, OFFSET(name), &val0); \
475 t1_tpi_read((mac)->adapter, OFFSET(((name)+1)), &val1); \
476 t1_tpi_read((mac)->adapter, OFFSET(((name)+2)), &val2); \
477 (mac)->stats.stat_name = ((u64)val0 & 0xffff) | \
478 (((u64)val1 & 0xffff) << 16) | \
479 (((u64)val2 & 0xff) << 32) | \
480 ((mac)->stats.stat_name & \
481 (~(u64)0 << 40)); \
482 if (ro & \
483 ((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2)) \
484 (mac)->stats.stat_name += ((u64)1 << 40); \
485 }
486
487static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
488 int flag)
489{
490 u64 ro;
491 u32 val0, val1, val2, val3;
492
493 /* Snap the counters */
494 pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
495 SUNI1x10GEXP_BITMSK_MSTAT_SNAP);
496
497 /* Counter rollover, clear on read */
498 pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_0, &val0);
499 pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_1, &val1);
500 pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_2, &val2);
501 pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_3, &val3);
502 ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) |
503 (((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48);
504
505 /* Rx stats */
506 RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK);
507 RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK);
508 RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK);
509 RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK);
510 RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames);
511 RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors);
512 RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors,
513 RxInternalMACRcvError);
514 RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
515 RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors);
516 RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors);
517 RMON_UPDATE(mac, RxJabbers, RxJabberErrors);
518 RMON_UPDATE(mac, RxFragments, RxRuntErrors);
519 RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors);
520
521 /* Tx stats */
522 RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK);
523 RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError,
524 TxInternalMACXmitError);
525 RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors);
526 RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK);
527 RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK);
528 RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK);
529 RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames);
530
531 return &mac->stats;
532}
533
534static int pm3393_macaddress_get(struct cmac *cmac, u8 mac_addr[6])
535{
536 memcpy(mac_addr, cmac->instance->mac_addr, 6);
537 return 0;
538}
539
540static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6])
541{
542 u32 val, lo, mid, hi, enabled = cmac->instance->enabled;
543
544 /*
545 * MAC addr: 00:07:43:00:13:09
546 *
547 * ma[5] = 0x09
548 * ma[4] = 0x13
549 * ma[3] = 0x00
550 * ma[2] = 0x43
551 * ma[1] = 0x07
552 * ma[0] = 0x00
553 *
554 * The PM3393 requires byte swapping and reverse order entry
555 * when programming MAC addresses:
556 *
557 * low_bits[15:0] = ma[1]:ma[0]
558 * mid_bits[31:16] = ma[3]:ma[2]
559 * high_bits[47:32] = ma[5]:ma[4]
560 */
561
562 /* Store local copy */
563 memcpy(cmac->instance->mac_addr, ma, 6);
564
565 lo = ((u32) ma[1] << 8) | (u32) ma[0];
566 mid = ((u32) ma[3] << 8) | (u32) ma[2];
567 hi = ((u32) ma[5] << 8) | (u32) ma[4];
568
569 /* Disable Rx/Tx MAC before configuring it. */
570 if (enabled)
571 pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
572
573 /* Set RXXG Station Address */
574 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_15_0, lo);
575 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_31_16, mid);
576 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_47_32, hi);
577
578 /* Set TXXG Station Address */
579 pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_15_0, lo);
580 pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_31_16, mid);
581 pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_47_32, hi);
582
583 /* Setup Exact Match Filter 1 with our MAC address
584 *
585 * Must disable exact match filter before configuring it.
586 */
587 pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, &val);
588 val &= 0xff0f;
589 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val);
590
591 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_LOW, lo);
592 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_MID, mid);
593 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_HIGH, hi);
594
595 val |= 0x0090;
596 pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val);
597
598 if (enabled)
599 pm3393_enable(cmac, enabled);
600 return 0;
601}
602
603static void pm3393_destroy(struct cmac *cmac)
604{
605 kfree(cmac);
606}
607
608static struct cmac_ops pm3393_ops = {
609 .destroy = pm3393_destroy,
610 .reset = pm3393_reset,
611 .interrupt_enable = pm3393_interrupt_enable,
612 .interrupt_disable = pm3393_interrupt_disable,
613 .interrupt_clear = pm3393_interrupt_clear,
614 .interrupt_handler = pm3393_interrupt_handler,
615 .enable = pm3393_enable_port,
616 .disable = pm3393_disable,
617 .loopback_enable = pm3393_loopback_enable,
618 .loopback_disable = pm3393_loopback_disable,
619 .set_mtu = pm3393_set_mtu,
620 .set_rx_mode = pm3393_set_rx_mode,
621 .get_speed_duplex_fc = pm3393_get_speed_duplex_fc,
622 .set_speed_duplex_fc = pm3393_set_speed_duplex_fc,
623 .statistics_update = pm3393_update_statistics,
624 .macaddress_get = pm3393_macaddress_get,
625 .macaddress_set = pm3393_macaddress_set
626};
627
628static struct cmac *pm3393_mac_create(adapter_t *adapter, int index)
629{
630 struct cmac *cmac;
631
632 cmac = kmalloc(sizeof(*cmac) + sizeof(cmac_instance), GFP_KERNEL);
633 if (!cmac)
634 return NULL;
635 memset(cmac, 0, sizeof(*cmac));
636
637 cmac->ops = &pm3393_ops;
638 cmac->instance = (cmac_instance *) (cmac + 1);
639 cmac->adapter = adapter;
640 cmac->instance->fc = PAUSE_TX | PAUSE_RX;
641
642 t1_tpi_write(adapter, OFFSET(0x0001), 0x00008000);
643 t1_tpi_write(adapter, OFFSET(0x0001), 0x00000000);
644 t1_tpi_write(adapter, OFFSET(0x2308), 0x00009800);
645 t1_tpi_write(adapter, OFFSET(0x2305), 0x00001001); /* PL4IO Enable */
646 t1_tpi_write(adapter, OFFSET(0x2320), 0x00008800);
647 t1_tpi_write(adapter, OFFSET(0x2321), 0x00008800);
648 t1_tpi_write(adapter, OFFSET(0x2322), 0x00008800);
649 t1_tpi_write(adapter, OFFSET(0x2323), 0x00008800);
650 t1_tpi_write(adapter, OFFSET(0x2324), 0x00008800);
651 t1_tpi_write(adapter, OFFSET(0x2325), 0x00008800);
652 t1_tpi_write(adapter, OFFSET(0x2326), 0x00008800);
653 t1_tpi_write(adapter, OFFSET(0x2327), 0x00008800);
654 t1_tpi_write(adapter, OFFSET(0x2328), 0x00008800);
655 t1_tpi_write(adapter, OFFSET(0x2329), 0x00008800);
656 t1_tpi_write(adapter, OFFSET(0x232a), 0x00008800);
657 t1_tpi_write(adapter, OFFSET(0x232b), 0x00008800);
658 t1_tpi_write(adapter, OFFSET(0x232c), 0x00008800);
659 t1_tpi_write(adapter, OFFSET(0x232d), 0x00008800);
660 t1_tpi_write(adapter, OFFSET(0x232e), 0x00008800);
661 t1_tpi_write(adapter, OFFSET(0x232f), 0x00008800);
662 t1_tpi_write(adapter, OFFSET(0x230d), 0x00009c00);
663 t1_tpi_write(adapter, OFFSET(0x2304), 0x00000202); /* PL4IO Calendar Repetitions */
664
665 t1_tpi_write(adapter, OFFSET(0x3200), 0x00008080); /* EFLX Enable */
666 t1_tpi_write(adapter, OFFSET(0x3210), 0x00000000); /* EFLX Channel Deprovision */
667 t1_tpi_write(adapter, OFFSET(0x3203), 0x00000000); /* EFLX Low Limit */
668 t1_tpi_write(adapter, OFFSET(0x3204), 0x00000040); /* EFLX High Limit */
669 t1_tpi_write(adapter, OFFSET(0x3205), 0x000002cc); /* EFLX Almost Full */
670 t1_tpi_write(adapter, OFFSET(0x3206), 0x00000199); /* EFLX Almost Empty */
671 t1_tpi_write(adapter, OFFSET(0x3207), 0x00000240); /* EFLX Cut Through Threshold */
672 t1_tpi_write(adapter, OFFSET(0x3202), 0x00000000); /* EFLX Indirect Register Update */
673 t1_tpi_write(adapter, OFFSET(0x3210), 0x00000001); /* EFLX Channel Provision */
674 t1_tpi_write(adapter, OFFSET(0x3208), 0x0000ffff); /* EFLX Undocumented */
675 t1_tpi_write(adapter, OFFSET(0x320a), 0x0000ffff); /* EFLX Undocumented */
676 t1_tpi_write(adapter, OFFSET(0x320c), 0x0000ffff); /* EFLX enable overflow interrupt The other bit are undocumented */
677 t1_tpi_write(adapter, OFFSET(0x320e), 0x0000ffff); /* EFLX Undocumented */
678
679 t1_tpi_write(adapter, OFFSET(0x2200), 0x0000c000); /* IFLX Configuration - enable */
680 t1_tpi_write(adapter, OFFSET(0x2201), 0x00000000); /* IFLX Channel Deprovision */
681 t1_tpi_write(adapter, OFFSET(0x220e), 0x00000000); /* IFLX Low Limit */
682 t1_tpi_write(adapter, OFFSET(0x220f), 0x00000100); /* IFLX High Limit */
683 t1_tpi_write(adapter, OFFSET(0x2210), 0x00000c00); /* IFLX Almost Full Limit */
684 t1_tpi_write(adapter, OFFSET(0x2211), 0x00000599); /* IFLX Almost Empty Limit */
685 t1_tpi_write(adapter, OFFSET(0x220d), 0x00000000); /* IFLX Indirect Register Update */
686 t1_tpi_write(adapter, OFFSET(0x2201), 0x00000001); /* IFLX Channel Provision */
687 t1_tpi_write(adapter, OFFSET(0x2203), 0x0000ffff); /* IFLX Undocumented */
688 t1_tpi_write(adapter, OFFSET(0x2205), 0x0000ffff); /* IFLX Undocumented */
689 t1_tpi_write(adapter, OFFSET(0x2209), 0x0000ffff); /* IFLX Enable overflow interrupt. The other bit are undocumented */
690
691 t1_tpi_write(adapter, OFFSET(0x2241), 0xfffffffe); /* PL4MOS Undocumented */
692 t1_tpi_write(adapter, OFFSET(0x2242), 0x0000ffff); /* PL4MOS Undocumented */
693 t1_tpi_write(adapter, OFFSET(0x2243), 0x00000008); /* PL4MOS Starving Burst Size */
694 t1_tpi_write(adapter, OFFSET(0x2244), 0x00000008); /* PL4MOS Hungry Burst Size */
695 t1_tpi_write(adapter, OFFSET(0x2245), 0x00000008); /* PL4MOS Transfer Size */
696 t1_tpi_write(adapter, OFFSET(0x2240), 0x00000005); /* PL4MOS Disable */
697
698 t1_tpi_write(adapter, OFFSET(0x2280), 0x00002103); /* PL4ODP Training Repeat and SOP rule */
699 t1_tpi_write(adapter, OFFSET(0x2284), 0x00000000); /* PL4ODP MAX_T setting */
700
701 t1_tpi_write(adapter, OFFSET(0x3280), 0x00000087); /* PL4IDU Enable data forward, port state machine. Set ALLOW_NON_ZERO_OLB */
702 t1_tpi_write(adapter, OFFSET(0x3282), 0x0000001f); /* PL4IDU Enable Dip4 check error interrupts */
703
704 t1_tpi_write(adapter, OFFSET(0x3040), 0x0c32); /* # TXXG Config */
705 /* For T1 use timer based Mac flow control. */
706 if (t1_is_T1B(adapter))
707 t1_tpi_write(adapter, OFFSET(0x304d), 0x8000);
708 t1_tpi_write(adapter, OFFSET(0x2040), 0x059c); /* # RXXG Config */
709 t1_tpi_write(adapter, OFFSET(0x2049), 0x0000); /* # RXXG Cut Through */
710 t1_tpi_write(adapter, OFFSET(0x2070), 0x0000); /* # Disable promiscuous mode */
711
712 /* Setup Exact Match Filter 0 to allow broadcast packets.
713 */
714 t1_tpi_write(adapter, OFFSET(0x206e), 0x0000); /* # Disable Match Enable bit */
715 t1_tpi_write(adapter, OFFSET(0x204a), 0xffff); /* # low addr */
716 t1_tpi_write(adapter, OFFSET(0x204b), 0xffff); /* # mid addr */
717 t1_tpi_write(adapter, OFFSET(0x204c), 0xffff); /* # high addr */
718 t1_tpi_write(adapter, OFFSET(0x206e), 0x0009); /* # Enable Match Enable bit */
719
720 t1_tpi_write(adapter, OFFSET(0x0003), 0x0000); /* # NO SOP/ PAD_EN setup */
721 t1_tpi_write(adapter, OFFSET(0x0100), 0x0ff0); /* # RXEQB disabled */
722 t1_tpi_write(adapter, OFFSET(0x0101), 0x0f0f); /* # No Preemphasis */
723
724 return cmac;
725}
726
727static int pm3393_mac_reset(adapter_t * adapter)
728{
729 u32 val;
730 u32 x;
731 u32 is_pl4_reset_finished;
732 u32 is_pl4_outof_lock;
733 u32 is_xaui_mabc_pll_locked;
734 u32 successful_reset;
735 int i;
736
737 /* The following steps are required to properly reset
738 * the PM3393. This information is provided in the
739 * PM3393 datasheet (Issue 2: November 2002)
740 * section 13.1 -- Device Reset.
741 *
742 * The PM3393 has three types of components that are
743 * individually reset:
744 *
745 * DRESETB - Digital circuitry
746 * PL4_ARESETB - PL4 analog circuitry
747 * XAUI_ARESETB - XAUI bus analog circuitry
748 *
749 * Steps to reset PM3393 using RSTB pin:
750 *
751 * 1. Assert RSTB pin low ( write 0 )
752 * 2. Wait at least 1ms to initiate a complete initialization of device.
753 * 3. Wait until all external clocks and REFSEL are stable.
754 * 4. Wait minimum of 1ms. (after external clocks and REFEL are stable)
755 * 5. De-assert RSTB ( write 1 )
756 * 6. Wait until internal timers to expires after ~14ms.
757 * - Allows analog clock synthesizer(PL4CSU) to stabilize to
758 * selected reference frequency before allowing the digital
759 * portion of the device to operate.
760 * 7. Wait at least 200us for XAUI interface to stabilize.
761 * 8. Verify the PM3393 came out of reset successfully.
762 * Set successful reset flag if everything worked else try again
763 * a few more times.
764 */
765
766 successful_reset = 0;
767 for (i = 0; i < 3 && !successful_reset; i++) {
768 /* 1 */
769 t1_tpi_read(adapter, A_ELMER0_GPO, &val);
770 val &= ~1;
771 t1_tpi_write(adapter, A_ELMER0_GPO, val);
772
773 /* 2 */
774 msleep(1);
775
776 /* 3 */
777 msleep(1);
778
779 /* 4 */
780 msleep(2 /*1 extra ms for safety */ );
781
782 /* 5 */
783 val |= 1;
784 t1_tpi_write(adapter, A_ELMER0_GPO, val);
785
786 /* 6 */
787 msleep(15 /*1 extra ms for safety */ );
788
789 /* 7 */
790 msleep(1);
791
792 /* 8 */
793
794 /* Has PL4 analog block come out of reset correctly? */
795 t1_tpi_read(adapter, OFFSET(SUNI1x10GEXP_REG_DEVICE_STATUS), &val);
796 is_pl4_reset_finished = (val & SUNI1x10GEXP_BITMSK_TOP_EXPIRED);
797
798 /* TBD XXX SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL gets locked later in the init sequence
799 * figure out why? */
800
801 /* Have all PL4 block clocks locked? */
802 x = (SUNI1x10GEXP_BITMSK_TOP_PL4_ID_DOOL
803 /*| SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL */ |
804 SUNI1x10GEXP_BITMSK_TOP_PL4_ID_ROOL |
805 SUNI1x10GEXP_BITMSK_TOP_PL4_IS_ROOL |
806 SUNI1x10GEXP_BITMSK_TOP_PL4_OUT_ROOL);
807 is_pl4_outof_lock = (val & x);
808
809 /* ??? If this fails, might be able to software reset the XAUI part
810 * and try to recover... thus saving us from doing another HW reset */
811 /* Has the XAUI MABC PLL circuitry stablized? */
812 is_xaui_mabc_pll_locked =
813 (val & SUNI1x10GEXP_BITMSK_TOP_SXRA_EXPIRED);
814
815 successful_reset = (is_pl4_reset_finished && !is_pl4_outof_lock
816 && is_xaui_mabc_pll_locked);
817
818 CH_DBG(adapter, HW,
819 "PM3393 HW reset %d: pl4_reset 0x%x, val 0x%x, "
820 "is_pl4_outof_lock 0x%x, xaui_locked 0x%x\n",
821 i, is_pl4_reset_finished, val, is_pl4_outof_lock,
822 is_xaui_mabc_pll_locked);
823 }
824 return successful_reset ? 0 : 1;
825}
826
827struct gmac t1_pm3393_ops = {
828 STATS_TICK_SECS,
829 pm3393_mac_create,
830 pm3393_mac_reset
831};