aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/chelsio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/chelsio')
-rw-r--r--drivers/net/chelsio/Makefile1
-rw-r--r--drivers/net/chelsio/common.h2
-rw-r--r--drivers/net/chelsio/cxgb2.c1
-rw-r--r--drivers/net/chelsio/ixf1010.c485
-rw-r--r--drivers/net/chelsio/mac.c368
-rw-r--r--drivers/net/chelsio/mv88e1xxx.c397
-rw-r--r--drivers/net/chelsio/subr.c221
-rw-r--r--drivers/net/chelsio/tp.c33
-rw-r--r--drivers/net/chelsio/vsc7326.c725
-rw-r--r--drivers/net/chelsio/vsc8244.c368
-rw-r--r--drivers/net/chelsio/vsc8244_reg.h172
11 files changed, 2773 insertions, 0 deletions
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile
index 6d87316e58cb..382d23f810ab 100644
--- a/drivers/net/chelsio/Makefile
+++ b/drivers/net/chelsio/Makefile
@@ -4,6 +4,7 @@
4 4
5obj-$(CONFIG_CHELSIO_T1) += cxgb.o 5obj-$(CONFIG_CHELSIO_T1) += cxgb.o
6 6
7cxgb-$(CONFIG_CHELSIO_T1_1G) += ixf1010.o mac.o mv88e1xxx.o vsc7326.o vsc8244.o
7cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \ 8cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \
8 mv88x201x.o my3126.o $(cxgb-y) 9 mv88x201x.o my3126.o $(cxgb-y)
9 10
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index e4e59d2d410e..55f1eaad115c 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -283,6 +283,8 @@ struct adapter {
283 283
284 spinlock_t tpi_lock; 284 spinlock_t tpi_lock;
285 spinlock_t work_lock; 285 spinlock_t work_lock;
286 spinlock_t mac_lock;
287
286 /* guards async operations */ 288 /* guards async operations */
287 spinlock_t async_lock ____cacheline_aligned; 289 spinlock_t async_lock ____cacheline_aligned;
288 u32 slow_intr_mask; 290 u32 slow_intr_mask;
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index a8c873b0af54..571aa06ddfd4 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -1094,6 +1094,7 @@ static int __devinit init_one(struct pci_dev *pdev,
1094 spin_lock_init(&adapter->tpi_lock); 1094 spin_lock_init(&adapter->tpi_lock);
1095 spin_lock_init(&adapter->work_lock); 1095 spin_lock_init(&adapter->work_lock);
1096 spin_lock_init(&adapter->async_lock); 1096 spin_lock_init(&adapter->async_lock);
1097 spin_lock_init(&adapter->mac_lock);
1097 1098
1098 INIT_WORK(&adapter->ext_intr_handler_task, 1099 INIT_WORK(&adapter->ext_intr_handler_task,
1099 ext_intr_task, adapter); 1100 ext_intr_task, adapter);
diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c
new file mode 100644
index 000000000000..5b8f144e83d4
--- /dev/null
+++ b/drivers/net/chelsio/ixf1010.c
@@ -0,0 +1,485 @@
1/* $Date: 2005/11/12 02:13:49 $ $RCSfile: ixf1010.c,v $ $Revision: 1.36 $ */
2#include "gmac.h"
3#include "elmer0.h"
4
5/* Update fast changing statistics every 15 seconds */
6#define STATS_TICK_SECS 15
7/* 30 minutes for full statistics update */
8#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS)
9
10/*
11 * The IXF1010 can handle frames up to 16383 bytes but it's optimized for
12 * frames up to 9831 (0x2667) bytes, so we limit jumbo frame size to this.
13 * This length includes ethernet header and FCS.
14 */
15#define MAX_FRAME_SIZE 0x2667
16
17/* MAC registers */
18enum {
19 /* Per-port registers */
20 REG_MACADDR_LOW = 0,
21 REG_MACADDR_HIGH = 0x4,
22 REG_FDFC_TYPE = 0xC,
23 REG_FC_TX_TIMER_VALUE = 0x1c,
24 REG_IPG_RX_TIME1 = 0x28,
25 REG_IPG_RX_TIME2 = 0x2c,
26 REG_IPG_TX_TIME = 0x30,
27 REG_PAUSE_THRES = 0x38,
28 REG_MAX_FRAME_SIZE = 0x3c,
29 REG_RGMII_SPEED = 0x40,
30 REG_FC_ENABLE = 0x48,
31 REG_DISCARD_CTRL_FRAMES = 0x54,
32 REG_DIVERSE_CONFIG = 0x60,
33 REG_RX_FILTER = 0x64,
34 REG_MC_ADDR_LOW = 0x68,
35 REG_MC_ADDR_HIGH = 0x6c,
36
37 REG_RX_OCTETS_OK = 0x80,
38 REG_RX_OCTETS_BAD = 0x84,
39 REG_RX_UC_PKTS = 0x88,
40 REG_RX_MC_PKTS = 0x8c,
41 REG_RX_BC_PKTS = 0x90,
42 REG_RX_FCS_ERR = 0xb0,
43 REG_RX_TAGGED = 0xb4,
44 REG_RX_DATA_ERR = 0xb8,
45 REG_RX_ALIGN_ERR = 0xbc,
46 REG_RX_LONG_ERR = 0xc0,
47 REG_RX_JABBER_ERR = 0xc4,
48 REG_RX_PAUSE_FRAMES = 0xc8,
49 REG_RX_UNKNOWN_CTRL_FRAMES = 0xcc,
50 REG_RX_VERY_LONG_ERR = 0xd0,
51 REG_RX_RUNT_ERR = 0xd4,
52 REG_RX_SHORT_ERR = 0xd8,
53 REG_RX_SYMBOL_ERR = 0xe4,
54
55 REG_TX_OCTETS_OK = 0x100,
56 REG_TX_OCTETS_BAD = 0x104,
57 REG_TX_UC_PKTS = 0x108,
58 REG_TX_MC_PKTS = 0x10c,
59 REG_TX_BC_PKTS = 0x110,
60 REG_TX_EXCESSIVE_LEN_DROP = 0x14c,
61 REG_TX_UNDERRUN = 0x150,
62 REG_TX_TAGGED = 0x154,
63 REG_TX_PAUSE_FRAMES = 0x15C,
64
65 /* Global registers */
66 REG_PORT_ENABLE = 0x1400,
67
68 REG_JTAG_ID = 0x1430,
69
70 RX_FIFO_HIGH_WATERMARK_BASE = 0x1600,
71 RX_FIFO_LOW_WATERMARK_BASE = 0x1628,
72 RX_FIFO_FRAMES_REMOVED_BASE = 0x1650,
73
74 REG_RX_ERR_DROP = 0x167c,
75 REG_RX_FIFO_OVERFLOW_EVENT = 0x1680,
76
77 TX_FIFO_HIGH_WATERMARK_BASE = 0x1800,
78 TX_FIFO_LOW_WATERMARK_BASE = 0x1828,
79 TX_FIFO_XFER_THRES_BASE = 0x1850,
80
81 REG_TX_FIFO_OVERFLOW_EVENT = 0x1878,
82 REG_TX_FIFO_OOS_EVENT = 0x1884,
83
84 TX_FIFO_FRAMES_REMOVED_BASE = 0x1888,
85
86 REG_SPI_RX_BURST = 0x1c00,
87 REG_SPI_RX_TRAINING = 0x1c04,
88 REG_SPI_RX_CALENDAR = 0x1c08,
89 REG_SPI_TX_SYNC = 0x1c0c
90};
91
92enum { /* RMON registers */
93 REG_RxOctetsTotalOK = 0x80,
94 REG_RxOctetsBad = 0x84,
95 REG_RxUCPkts = 0x88,
96 REG_RxMCPkts = 0x8c,
97 REG_RxBCPkts = 0x90,
98 REG_RxJumboPkts = 0xac,
99 REG_RxFCSErrors = 0xb0,
100 REG_RxDataErrors = 0xb8,
101 REG_RxAlignErrors = 0xbc,
102 REG_RxLongErrors = 0xc0,
103 REG_RxJabberErrors = 0xc4,
104 REG_RxPauseMacControlCounter = 0xc8,
105 REG_RxVeryLongErrors = 0xd0,
106 REG_RxRuntErrors = 0xd4,
107 REG_RxShortErrors = 0xd8,
108 REG_RxSequenceErrors = 0xe0,
109 REG_RxSymbolErrors = 0xe4,
110
111 REG_TxOctetsTotalOK = 0x100,
112 REG_TxOctetsBad = 0x104,
113 REG_TxUCPkts = 0x108,
114 REG_TxMCPkts = 0x10c,
115 REG_TxBCPkts = 0x110,
116 REG_TxJumboPkts = 0x12C,
117 REG_TxTotalCollisions = 0x134,
118 REG_TxExcessiveLengthDrop = 0x14c,
119 REG_TxUnderrun = 0x150,
120 REG_TxCRCErrors = 0x158,
121 REG_TxPauseFrames = 0x15c
122};
123
124enum {
125 DIVERSE_CONFIG_PAD_ENABLE = 0x80,
126 DIVERSE_CONFIG_CRC_ADD = 0x40
127};
128
129#define MACREG_BASE 0
130#define MACREG(mac, mac_reg) ((mac)->instance->mac_base + (mac_reg))
131
132struct _cmac_instance {
133 u32 mac_base;
134 u32 index;
135 u32 version;
136 u32 ticks;
137};
138
139static void disable_port(struct cmac *mac)
140{
141 u32 val;
142
143 t1_tpi_read(mac->adapter, REG_PORT_ENABLE, &val);
144 val &= ~(1 << mac->instance->index);
145 t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val);
146}
147
148#define RMON_UPDATE(mac, name, stat_name) \
149 t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
150 (mac)->stats.stat_name += val;
151
152/*
153 * Read the current values of the RMON counters and add them to the cumulative
154 * port statistics. The HW RMON counters are cleared by this operation.
155 */
156static void port_stats_update(struct cmac *mac)
157{
158 u32 val;
159
160 /* Rx stats */
161 RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
162 RMON_UPDATE(mac, RxOctetsBad, RxOctetsBad);
163 RMON_UPDATE(mac, RxUCPkts, RxUnicastFramesOK);
164 RMON_UPDATE(mac, RxMCPkts, RxMulticastFramesOK);
165 RMON_UPDATE(mac, RxBCPkts, RxBroadcastFramesOK);
166 RMON_UPDATE(mac, RxJumboPkts, RxJumboFramesOK);
167 RMON_UPDATE(mac, RxFCSErrors, RxFCSErrors);
168 RMON_UPDATE(mac, RxAlignErrors, RxAlignErrors);
169 RMON_UPDATE(mac, RxLongErrors, RxFrameTooLongErrors);
170 RMON_UPDATE(mac, RxVeryLongErrors, RxFrameTooLongErrors);
171 RMON_UPDATE(mac, RxPauseMacControlCounter, RxPauseFrames);
172 RMON_UPDATE(mac, RxDataErrors, RxDataErrors);
173 RMON_UPDATE(mac, RxJabberErrors, RxJabberErrors);
174 RMON_UPDATE(mac, RxRuntErrors, RxRuntErrors);
175 RMON_UPDATE(mac, RxShortErrors, RxRuntErrors);
176 RMON_UPDATE(mac, RxSequenceErrors, RxSequenceErrors);
177 RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
178
179 /* Tx stats (skip collision stats as we are full-duplex only) */
180 RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
181 RMON_UPDATE(mac, TxOctetsBad, TxOctetsBad);
182 RMON_UPDATE(mac, TxUCPkts, TxUnicastFramesOK);
183 RMON_UPDATE(mac, TxMCPkts, TxMulticastFramesOK);
184 RMON_UPDATE(mac, TxBCPkts, TxBroadcastFramesOK);
185 RMON_UPDATE(mac, TxJumboPkts, TxJumboFramesOK);
186 RMON_UPDATE(mac, TxPauseFrames, TxPauseFrames);
187 RMON_UPDATE(mac, TxExcessiveLengthDrop, TxLengthErrors);
188 RMON_UPDATE(mac, TxUnderrun, TxUnderrun);
189 RMON_UPDATE(mac, TxCRCErrors, TxFCSErrors);
190}
191
192/* No-op interrupt operation as this MAC does not support interrupts */
193static int mac_intr_op(struct cmac *mac)
194{
195 return 0;
196}
197
198/* Expect MAC address to be in network byte order. */
199static int mac_set_address(struct cmac *mac, u8 addr[6])
200{
201 u32 addr_lo, addr_hi;
202
203 addr_lo = addr[2];
204 addr_lo = (addr_lo << 8) | addr[3];
205 addr_lo = (addr_lo << 8) | addr[4];
206 addr_lo = (addr_lo << 8) | addr[5];
207
208 addr_hi = addr[0];
209 addr_hi = (addr_hi << 8) | addr[1];
210
211 t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_LOW), addr_lo);
212 t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), addr_hi);
213 return 0;
214}
215
216static int mac_get_address(struct cmac *mac, u8 addr[6])
217{
218 u32 addr_lo, addr_hi;
219
220 t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_LOW), &addr_lo);
221 t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), &addr_hi);
222
223 addr[0] = (u8) (addr_hi >> 8);
224 addr[1] = (u8) addr_hi;
225 addr[2] = (u8) (addr_lo >> 24);
226 addr[3] = (u8) (addr_lo >> 16);
227 addr[4] = (u8) (addr_lo >> 8);
228 addr[5] = (u8) addr_lo;
229 return 0;
230}
231
232/* This is intended to reset a port, not the whole MAC */
233static int mac_reset(struct cmac *mac)
234{
235 return 0;
236}
237
238static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
239{
240 u32 val, new_mode;
241 adapter_t *adapter = mac->adapter;
242 u32 addr_lo, addr_hi;
243 u8 *addr;
244
245 t1_tpi_read(adapter, MACREG(mac, REG_RX_FILTER), &val);
246 new_mode = val & ~7;
247 if (!t1_rx_mode_promisc(rm) && mac->instance->version > 0)
248 new_mode |= 1; /* only set if version > 0 due to erratum */
249 if (!t1_rx_mode_promisc(rm) && !t1_rx_mode_allmulti(rm)
250 && t1_rx_mode_mc_cnt(rm) <= 1)
251 new_mode |= 2;
252 if (new_mode != val)
253 t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), new_mode);
254 switch (t1_rx_mode_mc_cnt(rm)) {
255 case 0:
256 t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), 0);
257 t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), 0);
258 break;
259 case 1:
260 addr = t1_get_next_mcaddr(rm);
261 addr_lo = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |
262 addr[5];
263 addr_hi = (addr[0] << 8) | addr[1];
264 t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), addr_lo);
265 t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), addr_hi);
266 break;
267 default:
268 break;
269 }
270 return 0;
271}
272
273static int mac_set_mtu(struct cmac *mac, int mtu)
274{
275 /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */
276 if (mtu > (MAX_FRAME_SIZE - 14 - 4)) return -EINVAL;
277 t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE),
278 mtu + 14 + 4);
279 return 0;
280}
281
282static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
283 int fc)
284{
285 u32 val;
286
287 if (speed >= 0 && speed != SPEED_100 && speed != SPEED_1000)
288 return -1;
289 if (duplex >= 0 && duplex != DUPLEX_FULL)
290 return -1;
291
292 if (speed >= 0) {
293 val = speed == SPEED_100 ? 1 : 2;
294 t1_tpi_write(mac->adapter, MACREG(mac, REG_RGMII_SPEED), val);
295 }
296
297 t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val);
298 val &= ~3;
299 if (fc & PAUSE_RX)
300 val |= 1;
301 if (fc & PAUSE_TX)
302 val |= 2;
303 t1_tpi_write(mac->adapter, MACREG(mac, REG_FC_ENABLE), val);
304 return 0;
305}
306
307static int mac_get_speed_duplex_fc(struct cmac *mac, int *speed, int *duplex,
308 int *fc)
309{
310 u32 val;
311
312 if (duplex)
313 *duplex = DUPLEX_FULL;
314 if (speed) {
315 t1_tpi_read(mac->adapter, MACREG(mac, REG_RGMII_SPEED),
316 &val);
317 *speed = (val & 2) ? SPEED_1000 : SPEED_100;
318 }
319 if (fc) {
320 t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val);
321 *fc = 0;
322 if (val & 1)
323 *fc |= PAUSE_RX;
324 if (val & 2)
325 *fc |= PAUSE_TX;
326 }
327 return 0;
328}
329
330static void enable_port(struct cmac *mac)
331{
332 u32 val;
333 u32 index = mac->instance->index;
334 adapter_t *adapter = mac->adapter;
335
336 t1_tpi_read(adapter, MACREG(mac, REG_DIVERSE_CONFIG), &val);
337 val |= DIVERSE_CONFIG_CRC_ADD | DIVERSE_CONFIG_PAD_ENABLE;
338 t1_tpi_write(adapter, MACREG(mac, REG_DIVERSE_CONFIG), val);
339 if (mac->instance->version > 0)
340 t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 3);
341 else /* Don't enable unicast address filtering due to IXF1010 bug */
342 t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 2);
343
344 t1_tpi_read(adapter, REG_RX_ERR_DROP, &val);
345 val |= (1 << index);
346 t1_tpi_write(adapter, REG_RX_ERR_DROP, val);
347
348 /*
349 * Clear the port RMON registers by adding their current values to the
350 * cumulatice port stats and then clearing the stats. Really.
351 */
352 port_stats_update(mac);
353 memset(&mac->stats, 0, sizeof(struct cmac_statistics));
354 mac->instance->ticks = 0;
355
356 t1_tpi_read(adapter, REG_PORT_ENABLE, &val);
357 val |= (1 << index);
358 t1_tpi_write(adapter, REG_PORT_ENABLE, val);
359
360 index <<= 2;
361 if (is_T2(adapter)) {
362 /* T204: set the Fifo water level & threshold */
363 t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740);
364 t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730);
365 t1_tpi_write(adapter, TX_FIFO_HIGH_WATERMARK_BASE + index, 0x600);
366 t1_tpi_write(adapter, TX_FIFO_LOW_WATERMARK_BASE + index, 0x1d0);
367 t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x1100);
368 } else {
369 /*
370 * Set the TX Fifo Threshold to 0x400 instead of 0x100 to work around
371 * Underrun problem. Intel has blessed this solution.
372 */
373 t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x400);
374 }
375}
376
377/* IXF1010 ports do not have separate enables for TX and RX */
378static int mac_enable(struct cmac *mac, int which)
379{
380 if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX))
381 enable_port(mac);
382 return 0;
383}
384
385static int mac_disable(struct cmac *mac, int which)
386{
387 if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX))
388 disable_port(mac);
389 return 0;
390}
391
392/*
393 * This function is called periodically to accumulate the current values of the
394 * RMON counters into the port statistics. Since the counters are only 32 bits
395 * some of them can overflow in less than a minute at GigE speeds, so this
396 * function should be called every 30 seconds or so.
397 *
398 * To cut down on reading costs we update only the octet counters at each tick
399 * and do a full update at major ticks, which can be every 30 minutes or more.
400 */
401static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
402 int flag)
403{
404 if (flag == MAC_STATS_UPDATE_FULL ||
405 MAJOR_UPDATE_TICKS <= mac->instance->ticks) {
406 port_stats_update(mac);
407 mac->instance->ticks = 0;
408 } else {
409 u32 val;
410
411 RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
412 RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
413 mac->instance->ticks++;
414 }
415 return &mac->stats;
416}
417
418static void mac_destroy(struct cmac *mac)
419{
420 kfree(mac);
421}
422
423static struct cmac_ops ixf1010_ops = {
424 .destroy = mac_destroy,
425 .reset = mac_reset,
426 .interrupt_enable = mac_intr_op,
427 .interrupt_disable = mac_intr_op,
428 .interrupt_clear = mac_intr_op,
429 .enable = mac_enable,
430 .disable = mac_disable,
431 .set_mtu = mac_set_mtu,
432 .set_rx_mode = mac_set_rx_mode,
433 .set_speed_duplex_fc = mac_set_speed_duplex_fc,
434 .get_speed_duplex_fc = mac_get_speed_duplex_fc,
435 .statistics_update = mac_update_statistics,
436 .macaddress_get = mac_get_address,
437 .macaddress_set = mac_set_address,
438};
439
440static int ixf1010_mac_reset(adapter_t *adapter)
441{
442 u32 val;
443
444 t1_tpi_read(adapter, A_ELMER0_GPO, &val);
445 if ((val & 1) != 0) {
446 val &= ~1;
447 t1_tpi_write(adapter, A_ELMER0_GPO, val);
448 udelay(2);
449 }
450 val |= 1;
451 t1_tpi_write(adapter, A_ELMER0_GPO, val);
452 udelay(2);
453
454 t1_tpi_write(adapter, REG_PORT_ENABLE, 0);
455 return 0;
456}
457
458static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index)
459{
460 struct cmac *mac;
461 u32 val;
462
463 if (index > 9) return NULL;
464
465 mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
466 if (!mac) return NULL;
467
468 mac->ops = &ixf1010_ops;
469 mac->instance = (cmac_instance *)(mac + 1);
470
471 mac->instance->mac_base = MACREG_BASE + (index * 0x200);
472 mac->instance->index = index;
473 mac->adapter = adapter;
474 mac->instance->ticks = 0;
475
476 t1_tpi_read(adapter, REG_JTAG_ID, &val);
477 mac->instance->version = val >> 28;
478 return mac;
479}
480
481struct gmac t1_ixf1010_ops = {
482 STATS_TICK_SECS,
483 ixf1010_mac_create,
484 ixf1010_mac_reset
485};
diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c
new file mode 100644
index 000000000000..6af39dc70459
--- /dev/null
+++ b/drivers/net/chelsio/mac.c
@@ -0,0 +1,368 @@
1/* $Date: 2005/10/22 00:42:59 $ $RCSfile: mac.c,v $ $Revision: 1.32 $ */
2#include "gmac.h"
3#include "regs.h"
4#include "fpga_defs.h"
5
6#define MAC_CSR_INTERFACE_GMII 0x0
7#define MAC_CSR_INTERFACE_TBI 0x1
8#define MAC_CSR_INTERFACE_MII 0x2
9#define MAC_CSR_INTERFACE_RMII 0x3
10
11/* Chelsio's MAC statistics. */
12struct mac_statistics {
13
14 /* Transmit */
15 u32 TxFramesTransmittedOK;
16 u32 TxReserved1;
17 u32 TxReserved2;
18 u32 TxOctetsTransmittedOK;
19 u32 TxFramesWithDeferredXmissions;
20 u32 TxLateCollisions;
21 u32 TxFramesAbortedDueToXSCollisions;
22 u32 TxFramesLostDueToIntMACXmitError;
23 u32 TxReserved3;
24 u32 TxMulticastFrameXmittedOK;
25 u32 TxBroadcastFramesXmittedOK;
26 u32 TxFramesWithExcessiveDeferral;
27 u32 TxPAUSEMACCtrlFramesTransmitted;
28
29 /* Receive */
30 u32 RxFramesReceivedOK;
31 u32 RxFrameCheckSequenceErrors;
32 u32 RxAlignmentErrors;
33 u32 RxOctetsReceivedOK;
34 u32 RxFramesLostDueToIntMACRcvError;
35 u32 RxMulticastFramesReceivedOK;
36 u32 RxBroadcastFramesReceivedOK;
37 u32 RxInRangeLengthErrors;
38 u32 RxTxOutOfRangeLengthField;
39 u32 RxFrameTooLongErrors;
40 u32 RxPAUSEMACCtrlFramesReceived;
41};
42
43static int static_aPorts[] = {
44 FPGA_GMAC_INTERRUPT_PORT0,
45 FPGA_GMAC_INTERRUPT_PORT1,
46 FPGA_GMAC_INTERRUPT_PORT2,
47 FPGA_GMAC_INTERRUPT_PORT3
48};
49
50struct _cmac_instance {
51 u32 index;
52};
53
54static int mac_intr_enable(struct cmac *mac)
55{
56 u32 mac_intr;
57
58 if (t1_is_asic(mac->adapter)) {
59 /* ASIC */
60
61 /* We don't use the on chip MAC for ASIC products. */
62 } else {
63 /* FPGA */
64
65 /* Set parent gmac interrupt. */
66 mac_intr = readl(mac->adapter->regs + A_PL_ENABLE);
67 mac_intr |= FPGA_PCIX_INTERRUPT_GMAC;
68 writel(mac_intr, mac->adapter->regs + A_PL_ENABLE);
69
70 mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
71 mac_intr |= static_aPorts[mac->instance->index];
72 writel(mac_intr,
73 mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
74 }
75
76 return 0;
77}
78
79static int mac_intr_disable(struct cmac *mac)
80{
81 u32 mac_intr;
82
83 if (t1_is_asic(mac->adapter)) {
84 /* ASIC */
85
86 /* We don't use the on chip MAC for ASIC products. */
87 } else {
88 /* FPGA */
89
90 /* Set parent gmac interrupt. */
91 mac_intr = readl(mac->adapter->regs + A_PL_ENABLE);
92 mac_intr &= ~FPGA_PCIX_INTERRUPT_GMAC;
93 writel(mac_intr, mac->adapter->regs + A_PL_ENABLE);
94
95 mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
96 mac_intr &= ~(static_aPorts[mac->instance->index]);
97 writel(mac_intr,
98 mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
99 }
100
101 return 0;
102}
103
104static int mac_intr_clear(struct cmac *mac)
105{
106 u32 mac_intr;
107
108 if (t1_is_asic(mac->adapter)) {
109 /* ASIC */
110
111 /* We don't use the on chip MAC for ASIC products. */
112 } else {
113 /* FPGA */
114
115 /* Set parent gmac interrupt. */
116 writel(FPGA_PCIX_INTERRUPT_GMAC,
117 mac->adapter->regs + A_PL_CAUSE);
118 mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
119 mac_intr |= (static_aPorts[mac->instance->index]);
120 writel(mac_intr,
121 mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
122 }
123
124 return 0;
125}
126
127static int mac_get_address(struct cmac *mac, u8 addr[6])
128{
129 u32 data32_lo, data32_hi;
130
131 data32_lo = readl(mac->adapter->regs
132 + MAC_REG_IDLO(mac->instance->index));
133 data32_hi = readl(mac->adapter->regs
134 + MAC_REG_IDHI(mac->instance->index));
135
136 addr[0] = (u8) ((data32_hi >> 8) & 0xFF);
137 addr[1] = (u8) ((data32_hi) & 0xFF);
138 addr[2] = (u8) ((data32_lo >> 24) & 0xFF);
139 addr[3] = (u8) ((data32_lo >> 16) & 0xFF);
140 addr[4] = (u8) ((data32_lo >> 8) & 0xFF);
141 addr[5] = (u8) ((data32_lo) & 0xFF);
142 return 0;
143}
144
145static int mac_reset(struct cmac *mac)
146{
147 u32 data32;
148 int mac_in_reset, time_out = 100;
149 int idx = mac->instance->index;
150
151 data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx));
152 writel(data32 | F_MAC_RESET,
153 mac->adapter->regs + MAC_REG_CSR(idx));
154
155 do {
156 data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx));
157
158 mac_in_reset = data32 & F_MAC_RESET;
159 if (mac_in_reset)
160 udelay(1);
161 } while (mac_in_reset && --time_out);
162
163 if (mac_in_reset) {
164 CH_ERR("%s: MAC %d reset timed out\n",
165 mac->adapter->name, idx);
166 return 2;
167 }
168
169 return 0;
170}
171
172static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
173{
174 u32 val;
175
176 val = readl(mac->adapter->regs
177 + MAC_REG_CSR(mac->instance->index));
178 val &= ~(F_MAC_PROMISC | F_MAC_MC_ENABLE);
179 val |= V_MAC_PROMISC(t1_rx_mode_promisc(rm) != 0);
180 val |= V_MAC_MC_ENABLE(t1_rx_mode_allmulti(rm) != 0);
181 writel(val,
182 mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
183
184 return 0;
185}
186
187static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
188 int fc)
189{
190 u32 data32;
191
192 data32 = readl(mac->adapter->regs
193 + MAC_REG_CSR(mac->instance->index));
194 data32 &= ~(F_MAC_HALF_DUPLEX | V_MAC_SPEED(M_MAC_SPEED) |
195 V_INTERFACE(M_INTERFACE) | F_MAC_TX_PAUSE_ENABLE |
196 F_MAC_RX_PAUSE_ENABLE);
197
198 switch (speed) {
199 case SPEED_10:
200 case SPEED_100:
201 data32 |= V_INTERFACE(MAC_CSR_INTERFACE_MII);
202 data32 |= V_MAC_SPEED(speed == SPEED_10 ? 0 : 1);
203 break;
204 case SPEED_1000:
205 data32 |= V_INTERFACE(MAC_CSR_INTERFACE_GMII);
206 data32 |= V_MAC_SPEED(2);
207 break;
208 }
209
210 if (duplex >= 0)
211 data32 |= V_MAC_HALF_DUPLEX(duplex == DUPLEX_HALF);
212
213 if (fc >= 0) {
214 data32 |= V_MAC_RX_PAUSE_ENABLE((fc & PAUSE_RX) != 0);
215 data32 |= V_MAC_TX_PAUSE_ENABLE((fc & PAUSE_TX) != 0);
216 }
217
218 writel(data32,
219 mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
220 return 0;
221}
222
223static int mac_enable(struct cmac *mac, int which)
224{
225 u32 val;
226
227 val = readl(mac->adapter->regs
228 + MAC_REG_CSR(mac->instance->index));
229 if (which & MAC_DIRECTION_RX)
230 val |= F_MAC_RX_ENABLE;
231 if (which & MAC_DIRECTION_TX)
232 val |= F_MAC_TX_ENABLE;
233 writel(val,
234 mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
235 return 0;
236}
237
238static int mac_disable(struct cmac *mac, int which)
239{
240 u32 val;
241
242 val = readl(mac->adapter->regs
243 + MAC_REG_CSR(mac->instance->index));
244 if (which & MAC_DIRECTION_RX)
245 val &= ~F_MAC_RX_ENABLE;
246 if (which & MAC_DIRECTION_TX)
247 val &= ~F_MAC_TX_ENABLE;
248 writel(val,
249 mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
250 return 0;
251}
252
253#if 0
254static int mac_set_ifs(struct cmac *mac, u32 mode)
255{
256 t1_write_reg_4(mac->adapter,
257 MAC_REG_IFS(mac->instance->index),
258 mode);
259 return 0;
260}
261
262static int mac_enable_isl(struct cmac *mac)
263{
264 u32 data32 = readl(mac->adapter->regs
265 + MAC_REG_CSR(mac->instance->index));
266 data32 |= F_MAC_RX_ENABLE | F_MAC_TX_ENABLE;
267 t1_write_reg_4(mac->adapter,
268 MAC_REG_CSR(mac->instance->index),
269 data32);
270 return 0;
271}
272#endif
273
274static int mac_set_mtu(struct cmac *mac, int mtu)
275{
276 if (mtu > 9600)
277 return -EINVAL;
278 writel(mtu + ETH_HLEN + VLAN_HLEN,
279 mac->adapter->regs + MAC_REG_LARGEFRAMELENGTH(mac->instance->index));
280
281 return 0;
282}
283
284static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
285 int flag)
286{
287 struct mac_statistics st;
288 u32 *p = (u32 *) & st, i;
289
290 writel(0,
291 mac->adapter->regs + MAC_REG_RMCNT(mac->instance->index));
292
293 for (i = 0; i < sizeof(st) / sizeof(u32); i++)
294 *p++ = readl(mac->adapter->regs
295 + MAC_REG_RMDATA(mac->instance->index));
296
297 /* XXX convert stats */
298 return &mac->stats;
299}
300
301static void mac_destroy(struct cmac *mac)
302{
303 kfree(mac);
304}
305
306static struct cmac_ops chelsio_mac_ops = {
307 .destroy = mac_destroy,
308 .reset = mac_reset,
309 .interrupt_enable = mac_intr_enable,
310 .interrupt_disable = mac_intr_disable,
311 .interrupt_clear = mac_intr_clear,
312 .enable = mac_enable,
313 .disable = mac_disable,
314 .set_mtu = mac_set_mtu,
315 .set_rx_mode = mac_set_rx_mode,
316 .set_speed_duplex_fc = mac_set_speed_duplex_fc,
317 .macaddress_get = mac_get_address,
318 .statistics_update = mac_update_statistics,
319};
320
321static struct cmac *mac_create(adapter_t *adapter, int index)
322{
323 struct cmac *mac;
324 u32 data32;
325
326 if (index >= 4)
327 return NULL;
328
329 mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
330 if (!mac)
331 return NULL;
332
333 mac->ops = &chelsio_mac_ops;
334 mac->instance = (cmac_instance *) (mac + 1);
335
336 mac->instance->index = index;
337 mac->adapter = adapter;
338
339 data32 = readl(adapter->regs + MAC_REG_CSR(mac->instance->index));
340 data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC |
341 F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE);
342 data32 |= F_MAC_JUMBO_ENABLE;
343 writel(data32, adapter->regs + MAC_REG_CSR(mac->instance->index));
344
345 /* Initialize the random backoff seed. */
346 data32 = 0x55aa + (3 * index);
347 writel(data32,
348 adapter->regs + MAC_REG_GMRANDBACKOFFSEED(mac->instance->index));
349
350 /* Check to see if the mac address needs to be set manually. */
351 data32 = readl(adapter->regs + MAC_REG_IDLO(mac->instance->index));
352 if (data32 == 0 || data32 == 0xffffffff) {
353 /*
354 * Add a default MAC address if we can't read one.
355 */
356 writel(0x43FFFFFF - index,
357 adapter->regs + MAC_REG_IDLO(mac->instance->index));
358 writel(0x0007,
359 adapter->regs + MAC_REG_IDHI(mac->instance->index));
360 }
361
362 (void) mac_set_mtu(mac, 1500);
363 return mac;
364}
365
366struct gmac t1_chelsio_mac_ops = {
367 .create = mac_create
368};
diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c
new file mode 100644
index 000000000000..28ac93ff7c4f
--- /dev/null
+++ b/drivers/net/chelsio/mv88e1xxx.c
@@ -0,0 +1,397 @@
1/* $Date: 2005/10/24 23:18:13 $ $RCSfile: mv88e1xxx.c,v $ $Revision: 1.49 $ */
2#include "common.h"
3#include "mv88e1xxx.h"
4#include "cphy.h"
5#include "elmer0.h"
6
7/* MV88E1XXX MDI crossover register values */
8#define CROSSOVER_MDI 0
9#define CROSSOVER_MDIX 1
10#define CROSSOVER_AUTO 3
11
12#define INTR_ENABLE_MASK 0x6CA0
13
14/*
15 * Set the bits given by 'bitval' in PHY register 'reg'.
16 */
17static void mdio_set_bit(struct cphy *cphy, int reg, u32 bitval)
18{
19 u32 val;
20
21 (void) simple_mdio_read(cphy, reg, &val);
22 (void) simple_mdio_write(cphy, reg, val | bitval);
23}
24
25/*
26 * Clear the bits given by 'bitval' in PHY register 'reg'.
27 */
28static void mdio_clear_bit(struct cphy *cphy, int reg, u32 bitval)
29{
30 u32 val;
31
32 (void) simple_mdio_read(cphy, reg, &val);
33 (void) simple_mdio_write(cphy, reg, val & ~bitval);
34}
35
36/*
37 * NAME: phy_reset
38 *
39 * DESC: Reset the given PHY's port. NOTE: This is not a global
40 * chip reset.
41 *
42 * PARAMS: cphy - Pointer to PHY instance data.
43 *
44 * RETURN: 0 - Successfull reset.
45 * -1 - Timeout.
46 */
47static int mv88e1xxx_reset(struct cphy *cphy, int wait)
48{
49 u32 ctl;
50 int time_out = 1000;
51
52 mdio_set_bit(cphy, MII_BMCR, BMCR_RESET);
53
54 do {
55 (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
56 ctl &= BMCR_RESET;
57 if (ctl)
58 udelay(1);
59 } while (ctl && --time_out);
60
61 return ctl ? -1 : 0;
62}
63
64static int mv88e1xxx_interrupt_enable(struct cphy *cphy)
65{
66 /* Enable PHY interrupts. */
67 (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER,
68 INTR_ENABLE_MASK);
69
70 /* Enable Marvell interrupts through Elmer0. */
71 if (t1_is_asic(cphy->adapter)) {
72 u32 elmer;
73
74 t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
75 elmer |= ELMER0_GP_BIT1;
76 if (is_T2(cphy->adapter)) {
77 elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
78 }
79 t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
80 }
81 return 0;
82}
83
84static int mv88e1xxx_interrupt_disable(struct cphy *cphy)
85{
86 /* Disable all phy interrupts. */
87 (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 0);
88
89 /* Disable Marvell interrupts through Elmer0. */
90 if (t1_is_asic(cphy->adapter)) {
91 u32 elmer;
92
93 t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
94 elmer &= ~ELMER0_GP_BIT1;
95 if (is_T2(cphy->adapter)) {
96 elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
97 }
98 t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
99 }
100 return 0;
101}
102
103static int mv88e1xxx_interrupt_clear(struct cphy *cphy)
104{
105 u32 elmer;
106
107 /* Clear PHY interrupts by reading the register. */
108 (void) simple_mdio_read(cphy,
109 MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer);
110
111 /* Clear Marvell interrupts through Elmer0. */
112 if (t1_is_asic(cphy->adapter)) {
113 t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
114 elmer |= ELMER0_GP_BIT1;
115 if (is_T2(cphy->adapter)) {
116 elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
117 }
118 t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
119 }
120 return 0;
121}
122
123/*
124 * Set the PHY speed and duplex. This also disables auto-negotiation, except
125 * for 1Gb/s, where auto-negotiation is mandatory.
126 */
127static int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex)
128{
129 u32 ctl;
130
131 (void) simple_mdio_read(phy, MII_BMCR, &ctl);
132 if (speed >= 0) {
133 ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
134 if (speed == SPEED_100)
135 ctl |= BMCR_SPEED100;
136 else if (speed == SPEED_1000)
137 ctl |= BMCR_SPEED1000;
138 }
139 if (duplex >= 0) {
140 ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
141 if (duplex == DUPLEX_FULL)
142 ctl |= BMCR_FULLDPLX;
143 }
144 if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */
145 ctl |= BMCR_ANENABLE;
146 (void) simple_mdio_write(phy, MII_BMCR, ctl);
147 return 0;
148}
149
150static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
151{
152 u32 data32;
153
154 (void) simple_mdio_read(cphy,
155 MV88E1XXX_SPECIFIC_CNTRL_REGISTER, &data32);
156 data32 &= ~V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE);
157 data32 |= V_PSCR_MDI_XOVER_MODE(crossover);
158 (void) simple_mdio_write(cphy,
159 MV88E1XXX_SPECIFIC_CNTRL_REGISTER, data32);
160 return 0;
161}
162
163static int mv88e1xxx_autoneg_enable(struct cphy *cphy)
164{
165 u32 ctl;
166
167 (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO);
168
169 (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
170 /* restart autoneg for change to take effect */
171 ctl |= BMCR_ANENABLE | BMCR_ANRESTART;
172 (void) simple_mdio_write(cphy, MII_BMCR, ctl);
173 return 0;
174}
175
176static int mv88e1xxx_autoneg_disable(struct cphy *cphy)
177{
178 u32 ctl;
179
180 /*
181 * Crossover *must* be set to manual in order to disable auto-neg.
182 * The Alaska FAQs document highlights this point.
183 */
184 (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_MDI);
185
186 /*
187 * Must include autoneg reset when disabling auto-neg. This
188 * is described in the Alaska FAQ document.
189 */
190 (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
191 ctl &= ~BMCR_ANENABLE;
192 (void) simple_mdio_write(cphy, MII_BMCR, ctl | BMCR_ANRESTART);
193 return 0;
194}
195
196static int mv88e1xxx_autoneg_restart(struct cphy *cphy)
197{
198 mdio_set_bit(cphy, MII_BMCR, BMCR_ANRESTART);
199 return 0;
200}
201
202static int mv88e1xxx_advertise(struct cphy *phy, unsigned int advertise_map)
203{
204 u32 val = 0;
205
206 if (advertise_map &
207 (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
208 (void) simple_mdio_read(phy, MII_GBCR, &val);
209 val &= ~(GBCR_ADV_1000HALF | GBCR_ADV_1000FULL);
210 if (advertise_map & ADVERTISED_1000baseT_Half)
211 val |= GBCR_ADV_1000HALF;
212 if (advertise_map & ADVERTISED_1000baseT_Full)
213 val |= GBCR_ADV_1000FULL;
214 }
215 (void) simple_mdio_write(phy, MII_GBCR, val);
216
217 val = 1;
218 if (advertise_map & ADVERTISED_10baseT_Half)
219 val |= ADVERTISE_10HALF;
220 if (advertise_map & ADVERTISED_10baseT_Full)
221 val |= ADVERTISE_10FULL;
222 if (advertise_map & ADVERTISED_100baseT_Half)
223 val |= ADVERTISE_100HALF;
224 if (advertise_map & ADVERTISED_100baseT_Full)
225 val |= ADVERTISE_100FULL;
226 if (advertise_map & ADVERTISED_PAUSE)
227 val |= ADVERTISE_PAUSE;
228 if (advertise_map & ADVERTISED_ASYM_PAUSE)
229 val |= ADVERTISE_PAUSE_ASYM;
230 (void) simple_mdio_write(phy, MII_ADVERTISE, val);
231 return 0;
232}
233
234static int mv88e1xxx_set_loopback(struct cphy *cphy, int on)
235{
236 if (on)
237 mdio_set_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
238 else
239 mdio_clear_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
240 return 0;
241}
242
243static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok,
244 int *speed, int *duplex, int *fc)
245{
246 u32 status;
247 int sp = -1, dplx = -1, pause = 0;
248
249 (void) simple_mdio_read(cphy,
250 MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
251 if ((status & V_PSSR_STATUS_RESOLVED) != 0) {
252 if (status & V_PSSR_RX_PAUSE)
253 pause |= PAUSE_RX;
254 if (status & V_PSSR_TX_PAUSE)
255 pause |= PAUSE_TX;
256 dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
257 sp = G_PSSR_SPEED(status);
258 if (sp == 0)
259 sp = SPEED_10;
260 else if (sp == 1)
261 sp = SPEED_100;
262 else
263 sp = SPEED_1000;
264 }
265 if (link_ok)
266 *link_ok = (status & V_PSSR_LINK) != 0;
267 if (speed)
268 *speed = sp;
269 if (duplex)
270 *duplex = dplx;
271 if (fc)
272 *fc = pause;
273 return 0;
274}
275
276static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
277{
278 u32 val;
279
280 (void) simple_mdio_read(cphy,
281 MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, &val);
282
283 /*
284 * Set the downshift counter to 2 so we try to establish Gb link
285 * twice before downshifting.
286 */
287 val &= ~(V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT));
288
289 if (downshift_enable)
290 val |= V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2);
291 (void) simple_mdio_write(cphy,
292 MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, val);
293 return 0;
294}
295
296static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
297{
298 int cphy_cause = 0;
299 u32 status;
300
301 /*
302 * Loop until cause reads zero. Need to handle bouncing interrupts.
303 */
304 while (1) {
305 u32 cause;
306
307 (void) simple_mdio_read(cphy,
308 MV88E1XXX_INTERRUPT_STATUS_REGISTER,
309 &cause);
310 cause &= INTR_ENABLE_MASK;
311 if (!cause) break;
312
313 if (cause & MV88E1XXX_INTR_LINK_CHNG) {
314 (void) simple_mdio_read(cphy,
315 MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
316
317 if (status & MV88E1XXX_INTR_LINK_CHNG) {
318 cphy->state |= PHY_LINK_UP;
319 } else {
320 cphy->state &= ~PHY_LINK_UP;
321 if (cphy->state & PHY_AUTONEG_EN)
322 cphy->state &= ~PHY_AUTONEG_RDY;
323 cphy_cause |= cphy_cause_link_change;
324 }
325 }
326
327 if (cause & MV88E1XXX_INTR_AUTONEG_DONE)
328 cphy->state |= PHY_AUTONEG_RDY;
329
330 if ((cphy->state & (PHY_LINK_UP | PHY_AUTONEG_RDY)) ==
331 (PHY_LINK_UP | PHY_AUTONEG_RDY))
332 cphy_cause |= cphy_cause_link_change;
333 }
334 return cphy_cause;
335}
336
337static void mv88e1xxx_destroy(struct cphy *cphy)
338{
339 kfree(cphy);
340}
341
342static struct cphy_ops mv88e1xxx_ops = {
343 .destroy = mv88e1xxx_destroy,
344 .reset = mv88e1xxx_reset,
345 .interrupt_enable = mv88e1xxx_interrupt_enable,
346 .interrupt_disable = mv88e1xxx_interrupt_disable,
347 .interrupt_clear = mv88e1xxx_interrupt_clear,
348 .interrupt_handler = mv88e1xxx_interrupt_handler,
349 .autoneg_enable = mv88e1xxx_autoneg_enable,
350 .autoneg_disable = mv88e1xxx_autoneg_disable,
351 .autoneg_restart = mv88e1xxx_autoneg_restart,
352 .advertise = mv88e1xxx_advertise,
353 .set_loopback = mv88e1xxx_set_loopback,
354 .set_speed_duplex = mv88e1xxx_set_speed_duplex,
355 .get_link_status = mv88e1xxx_get_link_status,
356};
357
358static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
359 struct mdio_ops *mdio_ops)
360{
361 struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
362
363 if (!cphy) return NULL;
364
365 cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops);
366
367 /* Configure particular PHY's to run in a different mode. */
368 if ((board_info(adapter)->caps & SUPPORTED_TP) &&
369 board_info(adapter)->chip_phy == CHBT_PHY_88E1111) {
370 /*
371 * Configure the PHY transmitter as class A to reduce EMI.
372 */
373 (void) simple_mdio_write(cphy,
374 MV88E1XXX_EXTENDED_ADDR_REGISTER, 0xB);
375 (void) simple_mdio_write(cphy,
376 MV88E1XXX_EXTENDED_REGISTER, 0x8004);
377 }
378 (void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */
379
380 /* LED */
381 if (is_T2(adapter)) {
382 (void) simple_mdio_write(cphy,
383 MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
384 }
385
386 return cphy;
387}
388
389static int mv88e1xxx_phy_reset(adapter_t* adapter)
390{
391 return 0;
392}
393
394struct gphy t1_mv88e1xxx_ops = {
395 mv88e1xxx_phy_create,
396 mv88e1xxx_phy_reset
397};
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index d41d15a71e4d..22ed9a383c08 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -185,6 +185,66 @@ static int t1_pci_intr_handler(adapter_t *adapter)
185 return 0; 185 return 0;
186} 186}
187 187
188#ifdef CONFIG_CHELSIO_T1_COUGAR
189#include "cspi.h"
190#endif
191#ifdef CONFIG_CHELSIO_T1_1G
192#include "fpga_defs.h"
193
194/*
195 * PHY interrupt handler for FPGA boards.
196 */
197static int fpga_phy_intr_handler(adapter_t *adapter)
198{
199 int p;
200 u32 cause = readl(adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
201
202 for_each_port(adapter, p)
203 if (cause & (1 << p)) {
204 struct cphy *phy = adapter->port[p].phy;
205 int phy_cause = phy->ops->interrupt_handler(phy);
206
207 if (phy_cause & cphy_cause_link_change)
208 t1_link_changed(adapter, p);
209 }
210 writel(cause, adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
211 return 0;
212}
213
214/*
215 * Slow path interrupt handler for FPGAs.
216 */
217static int fpga_slow_intr(adapter_t *adapter)
218{
219 u32 cause = readl(adapter->regs + A_PL_CAUSE);
220
221 cause &= ~F_PL_INTR_SGE_DATA;
222 if (cause & F_PL_INTR_SGE_ERR)
223 t1_sge_intr_error_handler(adapter->sge);
224
225 if (cause & FPGA_PCIX_INTERRUPT_GMAC)
226 fpga_phy_intr_handler(adapter);
227
228 if (cause & FPGA_PCIX_INTERRUPT_TP) {
229 /*
230 * FPGA doesn't support MC4 interrupts and it requires
231 * this odd layer of indirection for MC5.
232 */
233 u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
234
235 /* Clear TP interrupt */
236 writel(tp_cause, adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
237 }
238 if (cause & FPGA_PCIX_INTERRUPT_PCIX)
239 t1_pci_intr_handler(adapter);
240
241 /* Clear the interrupts just processed. */
242 if (cause)
243 writel(cause, adapter->regs + A_PL_CAUSE);
244
245 return cause != 0;
246}
247#endif
188 248
189/* 249/*
190 * Wait until Elmer's MI1 interface is ready for new operations. 250 * Wait until Elmer's MI1 interface is ready for new operations.
@@ -221,6 +281,56 @@ static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi)
221 t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val); 281 t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val);
222} 282}
223 283
284#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
285/*
286 * Elmer MI1 MDIO read/write operations.
287 */
288static int mi1_mdio_read(adapter_t *adapter, int phy_addr, int mmd_addr,
289 int reg_addr, unsigned int *valp)
290{
291 u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr);
292
293 if (mmd_addr)
294 return -EINVAL;
295
296 spin_lock(&adapter->tpi_lock);
297 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
298 __t1_tpi_write(adapter,
299 A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_READ);
300 mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
301 __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp);
302 spin_unlock(&adapter->tpi_lock);
303 return 0;
304}
305
306static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr,
307 int reg_addr, unsigned int val)
308{
309 u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr);
310
311 if (mmd_addr)
312 return -EINVAL;
313
314 spin_lock(&adapter->tpi_lock);
315 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
316 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val);
317 __t1_tpi_write(adapter,
318 A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_WRITE);
319 mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
320 spin_unlock(&adapter->tpi_lock);
321 return 0;
322}
323
324#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
325static struct mdio_ops mi1_mdio_ops = {
326 mi1_mdio_init,
327 mi1_mdio_read,
328 mi1_mdio_write
329};
330#endif
331
332#endif
333
224static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr, 334static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr,
225 int reg_addr, unsigned int *valp) 335 int reg_addr, unsigned int *valp)
226{ 336{
@@ -330,6 +440,17 @@ static struct board_info t1_board[] = {
330 &t1_my3126_ops, &mi1_mdio_ext_ops, 440 &t1_my3126_ops, &mi1_mdio_ext_ops,
331 "Chelsio T210 1x10GBase-CX4 TOE" }, 441 "Chelsio T210 1x10GBase-CX4 TOE" },
332 442
443#ifdef CONFIG_CHELSIO_T1_1G
444{ CHBT_BOARD_CHN204, 4/*ports#*/,
445 SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half |
446 SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
447 SUPPORTED_PAUSE | SUPPORTED_TP /*caps*/, CHBT_TERM_T2, CHBT_MAC_VSC7321, CHBT_PHY_88E1111,
448 100000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
449 4/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
450 0/*mdiinv*/, 1/*mdc*/, 4/*phybaseaddr*/, &t1_vsc7326_ops,
451 &t1_mv88e1xxx_ops, &mi1_mdio_ops,
452 "Chelsio N204 4x100/1000BaseT NIC" },
453#endif
333 454
334}; 455};
335 456
@@ -483,6 +604,48 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
483 t1_tpi_read(adapter, A_ELMER0_INT_CAUSE, &cause); 604 t1_tpi_read(adapter, A_ELMER0_INT_CAUSE, &cause);
484 605
485 switch (board_info(adapter)->board) { 606 switch (board_info(adapter)->board) {
607#ifdef CONFIG_CHELSIO_T1_1G
608 case CHBT_BOARD_CHT204:
609 case CHBT_BOARD_CHT204E:
610 case CHBT_BOARD_CHN204:
611 case CHBT_BOARD_CHT204V: {
612 int i, port_bit;
613 for_each_port(adapter, i) {
614 port_bit = i + 1;
615 if (!(cause & (1 << port_bit))) continue;
616
617 phy = adapter->port[i].phy;
618 phy_cause = phy->ops->interrupt_handler(phy);
619 if (phy_cause & cphy_cause_link_change)
620 t1_link_changed(adapter, i);
621 }
622 break;
623 }
624 case CHBT_BOARD_CHT101:
625 if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */
626 phy = adapter->port[0].phy;
627 phy_cause = phy->ops->interrupt_handler(phy);
628 if (phy_cause & cphy_cause_link_change)
629 t1_link_changed(adapter, 0);
630 }
631 break;
632 case CHBT_BOARD_7500: {
633 int p;
634 /*
635 * Elmer0's interrupt cause isn't useful here because there is
636 * only one bit that can be set for all 4 ports. This means
637 * we are forced to check every PHY's interrupt status
638 * register to see who initiated the interrupt.
639 */
640 for_each_port(adapter, p) {
641 phy = adapter->port[p].phy;
642 phy_cause = phy->ops->interrupt_handler(phy);
643 if (phy_cause & cphy_cause_link_change)
644 t1_link_changed(adapter, p);
645 }
646 break;
647 }
648#endif
486 case CHBT_BOARD_CHT210: 649 case CHBT_BOARD_CHT210:
487 case CHBT_BOARD_N210: 650 case CHBT_BOARD_N210:
488 case CHBT_BOARD_N110: 651 case CHBT_BOARD_N110:
@@ -511,6 +674,30 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
511 mod_detect ? "removed" : "inserted"); 674 mod_detect ? "removed" : "inserted");
512 } 675 }
513 break; 676 break;
677#ifdef CONFIG_CHELSIO_T1_COUGAR
678 case CHBT_BOARD_COUGAR:
679 if (adapter->params.nports == 1) {
680 if (cause & ELMER0_GP_BIT1) { /* Vitesse MAC */
681 struct cmac *mac = adapter->port[0].mac;
682 mac->ops->interrupt_handler(mac);
683 }
684 if (cause & ELMER0_GP_BIT5) { /* XPAK MOD_DETECT */
685 }
686 } else {
687 int i, port_bit;
688
689 for_each_port(adapter, i) {
690 port_bit = i ? i + 1 : 0;
691 if (!(cause & (1 << port_bit))) continue;
692
693 phy = adapter->port[i].phy;
694 phy_cause = phy->ops->interrupt_handler(phy);
695 if (phy_cause & cphy_cause_link_change)
696 t1_link_changed(adapter, i);
697 }
698 }
699 break;
700#endif
514 } 701 }
515 t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause); 702 t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause);
516 return 0; 703 return 0;
@@ -633,6 +820,10 @@ static int asic_slow_intr(adapter_t *adapter)
633 820
634int t1_slow_intr_handler(adapter_t *adapter) 821int t1_slow_intr_handler(adapter_t *adapter)
635{ 822{
823#ifdef CONFIG_CHELSIO_T1_1G
824 if (!t1_is_asic(adapter))
825 return fpga_slow_intr(adapter);
826#endif
636 return asic_slow_intr(adapter); 827 return asic_slow_intr(adapter);
637} 828}
638 829
@@ -698,6 +889,21 @@ static int board_init(adapter_t *adapter, const struct board_info *bi)
698 */ 889 */
699 power_sequence_xpak(adapter); 890 power_sequence_xpak(adapter);
700 break; 891 break;
892#ifdef CONFIG_CHELSIO_T1_1G
893 case CHBT_BOARD_CHT204E:
894 /* add config space write here */
895 case CHBT_BOARD_CHT204:
896 case CHBT_BOARD_CHT204V:
897 case CHBT_BOARD_CHN204:
898 t1_tpi_par(adapter, 0xf);
899 t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
900 break;
901 case CHBT_BOARD_CHT101:
902 case CHBT_BOARD_7500:
903 t1_tpi_par(adapter, 0xf);
904 t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
905 break;
906#endif
701 } 907 }
702 return 0; 908 return 0;
703} 909}
@@ -719,6 +925,10 @@ int t1_init_hw_modules(adapter_t *adapter)
719 adapter->regs + A_MC5_CONFIG); 925 adapter->regs + A_MC5_CONFIG);
720 } 926 }
721 927
928#ifdef CONFIG_CHELSIO_T1_COUGAR
929 if (adapter->cspi && t1_cspi_init(adapter->cspi))
930 goto out_err;
931#endif
722 if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac, 932 if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac,
723 bi->espi_nports)) 933 bi->espi_nports))
724 goto out_err; 934 goto out_err;
@@ -772,6 +982,10 @@ void t1_free_sw_modules(adapter_t *adapter)
772 t1_tp_destroy(adapter->tp); 982 t1_tp_destroy(adapter->tp);
773 if (adapter->espi) 983 if (adapter->espi)
774 t1_espi_destroy(adapter->espi); 984 t1_espi_destroy(adapter->espi);
985#ifdef CONFIG_CHELSIO_T1_COUGAR
986 if (adapter->cspi)
987 t1_cspi_destroy(adapter->cspi);
988#endif
775} 989}
776 990
777static void __devinit init_link_config(struct link_config *lc, 991static void __devinit init_link_config(struct link_config *lc,
@@ -791,6 +1005,13 @@ static void __devinit init_link_config(struct link_config *lc,
791 } 1005 }
792} 1006}
793 1007
1008#ifdef CONFIG_CHELSIO_T1_COUGAR
1009 if (bi->clock_cspi && !(adapter->cspi = t1_cspi_create(adapter))) {
1010 CH_ERR("%s: CSPI initialization failed\n",
1011 adapter->name);
1012 goto error;
1013 }
1014#endif
794 1015
795/* 1016/*
796 * Allocate and initialize the data structures that hold the SW state of 1017 * Allocate and initialize the data structures that hold the SW state of
diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c
index 04a7073e9d15..0ca0b6e19e43 100644
--- a/drivers/net/chelsio/tp.c
+++ b/drivers/net/chelsio/tp.c
@@ -2,6 +2,9 @@
2#include "common.h" 2#include "common.h"
3#include "regs.h" 3#include "regs.h"
4#include "tp.h" 4#include "tp.h"
5#ifdef CONFIG_CHELSIO_T1_1G
6#include "fpga_defs.h"
7#endif
5 8
6struct petp { 9struct petp {
7 adapter_t *adapter; 10 adapter_t *adapter;
@@ -70,6 +73,15 @@ void t1_tp_intr_enable(struct petp *tp)
70{ 73{
71 u32 tp_intr = readl(tp->adapter->regs + A_PL_ENABLE); 74 u32 tp_intr = readl(tp->adapter->regs + A_PL_ENABLE);
72 75
76#ifdef CONFIG_CHELSIO_T1_1G
77 if (!t1_is_asic(tp->adapter)) {
78 /* FPGA */
79 writel(0xffffffff,
80 tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_ENABLE);
81 writel(tp_intr | FPGA_PCIX_INTERRUPT_TP,
82 tp->adapter->regs + A_PL_ENABLE);
83 } else
84#endif
73 { 85 {
74 /* We don't use any TP interrupts */ 86 /* We don't use any TP interrupts */
75 writel(0, tp->adapter->regs + A_TP_INT_ENABLE); 87 writel(0, tp->adapter->regs + A_TP_INT_ENABLE);
@@ -82,6 +94,14 @@ void t1_tp_intr_disable(struct petp *tp)
82{ 94{
83 u32 tp_intr = readl(tp->adapter->regs + A_PL_ENABLE); 95 u32 tp_intr = readl(tp->adapter->regs + A_PL_ENABLE);
84 96
97#ifdef CONFIG_CHELSIO_T1_1G
98 if (!t1_is_asic(tp->adapter)) {
99 /* FPGA */
100 writel(0, tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_ENABLE);
101 writel(tp_intr & ~FPGA_PCIX_INTERRUPT_TP,
102 tp->adapter->regs + A_PL_ENABLE);
103 } else
104#endif
85 { 105 {
86 writel(0, tp->adapter->regs + A_TP_INT_ENABLE); 106 writel(0, tp->adapter->regs + A_TP_INT_ENABLE);
87 writel(tp_intr & ~F_PL_INTR_TP, 107 writel(tp_intr & ~F_PL_INTR_TP,
@@ -91,6 +111,14 @@ void t1_tp_intr_disable(struct petp *tp)
91 111
92void t1_tp_intr_clear(struct petp *tp) 112void t1_tp_intr_clear(struct petp *tp)
93{ 113{
114#ifdef CONFIG_CHELSIO_T1_1G
115 if (!t1_is_asic(tp->adapter)) {
116 writel(0xffffffff,
117 tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
118 writel(FPGA_PCIX_INTERRUPT_TP, tp->adapter->regs + A_PL_CAUSE);
119 return;
120 }
121#endif
94 writel(0xffffffff, tp->adapter->regs + A_TP_INT_CAUSE); 122 writel(0xffffffff, tp->adapter->regs + A_TP_INT_CAUSE);
95 writel(F_PL_INTR_TP, tp->adapter->regs + A_PL_CAUSE); 123 writel(F_PL_INTR_TP, tp->adapter->regs + A_PL_CAUSE);
96} 124}
@@ -99,6 +127,11 @@ int t1_tp_intr_handler(struct petp *tp)
99{ 127{
100 u32 cause; 128 u32 cause;
101 129
130#ifdef CONFIG_CHELSIO_T1_1G
131 /* FPGA doesn't support TP interrupts. */
132 if (!t1_is_asic(tp->adapter))
133 return 1;
134#endif
102 135
103 cause = readl(tp->adapter->regs + A_TP_INT_CAUSE); 136 cause = readl(tp->adapter->regs + A_TP_INT_CAUSE);
104 writel(cause, tp->adapter->regs + A_TP_INT_CAUSE); 137 writel(cause, tp->adapter->regs + A_TP_INT_CAUSE);
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c
new file mode 100644
index 000000000000..85dc3b1dc309
--- /dev/null
+++ b/drivers/net/chelsio/vsc7326.c
@@ -0,0 +1,725 @@
1/* $Date: 2006/04/28 19:20:06 $ $RCSfile: vsc7326.c,v $ $Revision: 1.19 $ */
2
3/* Driver for Vitesse VSC7326 (Schaumburg) MAC */
4
5#include "gmac.h"
6#include "elmer0.h"
7#include "vsc7326_reg.h"
8
9/* Update fast changing statistics every 15 seconds */
10#define STATS_TICK_SECS 15
11/* 30 minutes for full statistics update */
12#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS)
13
14#define MAX_MTU 9600
15
16/* The egress WM value 0x01a01fff should be used only when the
17 * interface is down (MAC port disabled). This is a workaround
18 * for disabling the T2/MAC flow-control. When the interface is
19 * enabled, the WM value should be set to 0x014a03F0.
20 */
21#define WM_DISABLE 0x01a01fff
22#define WM_ENABLE 0x014a03F0
23
24struct init_table {
25 u32 addr;
26 u32 data;
27};
28
29struct _cmac_instance {
30 u32 index;
31 u32 ticks;
32};
33
34#define INITBLOCK_SLEEP 0xffffffff
35
36static void vsc_read(adapter_t *adapter, u32 addr, u32 *val)
37{
38 u32 status, vlo, vhi;
39 int i;
40
41 spin_lock_bh(&adapter->mac_lock);
42 t1_tpi_read(adapter, (addr << 2) + 4, &vlo);
43 i = 0;
44 do {
45 t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo);
46 t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi);
47 status = (vhi << 16) | vlo;
48 i++;
49 } while (((status & 1) == 0) && (i < 50));
50 if (i == 50)
51 CH_ERR("Invalid tpi read from MAC, breaking loop.\n");
52
53 t1_tpi_read(adapter, (REG_LOCAL_DATA << 2) + 4, &vlo);
54 t1_tpi_read(adapter, REG_LOCAL_DATA << 2, &vhi);
55
56 *val = (vhi << 16) | vlo;
57
58 /* CH_ERR("rd: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n",
59 ((addr&0xe000)>>13), ((addr&0x1e00)>>9),
60 ((addr&0x01fe)>>1), *val); */
61 spin_unlock_bh(&adapter->mac_lock);
62}
63
64static void vsc_write(adapter_t *adapter, u32 addr, u32 data)
65{
66 spin_lock_bh(&adapter->mac_lock);
67 t1_tpi_write(adapter, (addr << 2) + 4, data & 0xFFFF);
68 t1_tpi_write(adapter, addr << 2, (data >> 16) & 0xFFFF);
69 /* CH_ERR("wr: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n",
70 ((addr&0xe000)>>13), ((addr&0x1e00)>>9),
71 ((addr&0x01fe)>>1), data); */
72 spin_unlock_bh(&adapter->mac_lock);
73}
74
75/* Hard reset the MAC. This wipes out *all* configuration. */
76static void vsc7326_full_reset(adapter_t* adapter)
77{
78 u32 val;
79 u32 result = 0xffff;
80
81 t1_tpi_read(adapter, A_ELMER0_GPO, &val);
82 val &= ~1;
83 t1_tpi_write(adapter, A_ELMER0_GPO, val);
84 udelay(2);
85 val |= 0x1; /* Enable mac MAC itself */
86 val |= 0x800; /* Turn off the red LED */
87 t1_tpi_write(adapter, A_ELMER0_GPO, val);
88 mdelay(1);
89 vsc_write(adapter, REG_SW_RESET, 0x80000001);
90 do {
91 mdelay(1);
92 vsc_read(adapter, REG_SW_RESET, &result);
93 } while (result != 0x0);
94}
95
96static struct init_table vsc7326_reset[] = {
97 { REG_IFACE_MODE, 0x00000000 },
98 { REG_CRC_CFG, 0x00000020 },
99 { REG_PLL_CLK_SPEED, 0x00050c00 },
100 { REG_PLL_CLK_SPEED, 0x00050c00 },
101 { REG_MSCH, 0x00002f14 },
102 { REG_SPI4_MISC, 0x00040409 },
103 { REG_SPI4_DESKEW, 0x00080000 },
104 { REG_SPI4_ING_SETUP2, 0x08080004 },
105 { REG_SPI4_ING_SETUP0, 0x04111004 },
106 { REG_SPI4_EGR_SETUP0, 0x80001a04 },
107 { REG_SPI4_ING_SETUP1, 0x02010000 },
108 { REG_AGE_INC(0), 0x00000000 },
109 { REG_AGE_INC(1), 0x00000000 },
110 { REG_ING_CONTROL, 0x0a200011 },
111 { REG_EGR_CONTROL, 0xa0010091 },
112};
113
114static struct init_table vsc7326_portinit[4][22] = {
115 { /* Port 0 */
116 /* FIFO setup */
117 { REG_DBG(0), 0x000004f0 },
118 { REG_HDX(0), 0x00073101 },
119 { REG_TEST(0,0), 0x00000022 },
120 { REG_TEST(1,0), 0x00000022 },
121 { REG_TOP_BOTTOM(0,0), 0x003f0000 },
122 { REG_TOP_BOTTOM(1,0), 0x00120000 },
123 { REG_HIGH_LOW_WM(0,0), 0x07460757 },
124 { REG_HIGH_LOW_WM(1,0), WM_DISABLE },
125 { REG_CT_THRHLD(0,0), 0x00000000 },
126 { REG_CT_THRHLD(1,0), 0x00000000 },
127 { REG_BUCKE(0), 0x0002ffff },
128 { REG_BUCKI(0), 0x0002ffff },
129 { REG_TEST(0,0), 0x00000020 },
130 { REG_TEST(1,0), 0x00000020 },
131 /* Port config */
132 { REG_MAX_LEN(0), 0x00002710 },
133 { REG_PORT_FAIL(0), 0x00000002 },
134 { REG_NORMALIZER(0), 0x00000a64 },
135 { REG_DENORM(0), 0x00000010 },
136 { REG_STICK_BIT(0), 0x03baa370 },
137 { REG_DEV_SETUP(0), 0x00000083 },
138 { REG_DEV_SETUP(0), 0x00000082 },
139 { REG_MODE_CFG(0), 0x0200259f },
140 },
141 { /* Port 1 */
142 /* FIFO setup */
143 { REG_DBG(1), 0x000004f0 },
144 { REG_HDX(1), 0x00073101 },
145 { REG_TEST(0,1), 0x00000022 },
146 { REG_TEST(1,1), 0x00000022 },
147 { REG_TOP_BOTTOM(0,1), 0x007e003f },
148 { REG_TOP_BOTTOM(1,1), 0x00240012 },
149 { REG_HIGH_LOW_WM(0,1), 0x07460757 },
150 { REG_HIGH_LOW_WM(1,1), WM_DISABLE },
151 { REG_CT_THRHLD(0,1), 0x00000000 },
152 { REG_CT_THRHLD(1,1), 0x00000000 },
153 { REG_BUCKE(1), 0x0002ffff },
154 { REG_BUCKI(1), 0x0002ffff },
155 { REG_TEST(0,1), 0x00000020 },
156 { REG_TEST(1,1), 0x00000020 },
157 /* Port config */
158 { REG_MAX_LEN(1), 0x00002710 },
159 { REG_PORT_FAIL(1), 0x00000002 },
160 { REG_NORMALIZER(1), 0x00000a64 },
161 { REG_DENORM(1), 0x00000010 },
162 { REG_STICK_BIT(1), 0x03baa370 },
163 { REG_DEV_SETUP(1), 0x00000083 },
164 { REG_DEV_SETUP(1), 0x00000082 },
165 { REG_MODE_CFG(1), 0x0200259f },
166 },
167 { /* Port 2 */
168 /* FIFO setup */
169 { REG_DBG(2), 0x000004f0 },
170 { REG_HDX(2), 0x00073101 },
171 { REG_TEST(0,2), 0x00000022 },
172 { REG_TEST(1,2), 0x00000022 },
173 { REG_TOP_BOTTOM(0,2), 0x00bd007e },
174 { REG_TOP_BOTTOM(1,2), 0x00360024 },
175 { REG_HIGH_LOW_WM(0,2), 0x07460757 },
176 { REG_HIGH_LOW_WM(1,2), WM_DISABLE },
177 { REG_CT_THRHLD(0,2), 0x00000000 },
178 { REG_CT_THRHLD(1,2), 0x00000000 },
179 { REG_BUCKE(2), 0x0002ffff },
180 { REG_BUCKI(2), 0x0002ffff },
181 { REG_TEST(0,2), 0x00000020 },
182 { REG_TEST(1,2), 0x00000020 },
183 /* Port config */
184 { REG_MAX_LEN(2), 0x00002710 },
185 { REG_PORT_FAIL(2), 0x00000002 },
186 { REG_NORMALIZER(2), 0x00000a64 },
187 { REG_DENORM(2), 0x00000010 },
188 { REG_STICK_BIT(2), 0x03baa370 },
189 { REG_DEV_SETUP(2), 0x00000083 },
190 { REG_DEV_SETUP(2), 0x00000082 },
191 { REG_MODE_CFG(2), 0x0200259f },
192 },
193 { /* Port 3 */
194 /* FIFO setup */
195 { REG_DBG(3), 0x000004f0 },
196 { REG_HDX(3), 0x00073101 },
197 { REG_TEST(0,3), 0x00000022 },
198 { REG_TEST(1,3), 0x00000022 },
199 { REG_TOP_BOTTOM(0,3), 0x00fc00bd },
200 { REG_TOP_BOTTOM(1,3), 0x00480036 },
201 { REG_HIGH_LOW_WM(0,3), 0x07460757 },
202 { REG_HIGH_LOW_WM(1,3), WM_DISABLE },
203 { REG_CT_THRHLD(0,3), 0x00000000 },
204 { REG_CT_THRHLD(1,3), 0x00000000 },
205 { REG_BUCKE(3), 0x0002ffff },
206 { REG_BUCKI(3), 0x0002ffff },
207 { REG_TEST(0,3), 0x00000020 },
208 { REG_TEST(1,3), 0x00000020 },
209 /* Port config */
210 { REG_MAX_LEN(3), 0x00002710 },
211 { REG_PORT_FAIL(3), 0x00000002 },
212 { REG_NORMALIZER(3), 0x00000a64 },
213 { REG_DENORM(3), 0x00000010 },
214 { REG_STICK_BIT(3), 0x03baa370 },
215 { REG_DEV_SETUP(3), 0x00000083 },
216 { REG_DEV_SETUP(3), 0x00000082 },
217 { REG_MODE_CFG(3), 0x0200259f },
218 },
219};
220
221static void run_table(adapter_t *adapter, struct init_table *ib, int len)
222{
223 int i;
224
225 for (i = 0; i < len; i++) {
226 if (ib[i].addr == INITBLOCK_SLEEP) {
227 udelay( ib[i].data );
228 CH_ERR("sleep %d us\n",ib[i].data);
229 } else {
230 vsc_write( adapter, ib[i].addr, ib[i].data );
231 }
232 }
233}
234
235static int bist_rd(adapter_t *adapter, int moduleid, int address)
236{
237 int data=0;
238 u32 result=0;
239
240 if( (address != 0x0) &&
241 (address != 0x1) &&
242 (address != 0x2) &&
243 (address != 0xd) &&
244 (address != 0xe))
245 CH_ERR("No bist address: 0x%x\n", address);
246
247 data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) |
248 ((moduleid & 0xff) << 0));
249 vsc_write(adapter, REG_RAM_BIST_CMD, data);
250
251 udelay(10);
252
253 vsc_read(adapter, REG_RAM_BIST_RESULT, &result);
254 if((result & (1<<9)) != 0x0)
255 CH_ERR("Still in bist read: 0x%x\n", result);
256 else if((result & (1<<8)) != 0x0)
257 CH_ERR("bist read error: 0x%x\n", result);
258
259 return(result & 0xff);
260}
261
262static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
263{
264 int data=0;
265 u32 result=0;
266
267 if( (address != 0x0) &&
268 (address != 0x1) &&
269 (address != 0x2) &&
270 (address != 0xd) &&
271 (address != 0xe))
272 CH_ERR("No bist address: 0x%x\n", address);
273
274 if( value>255 )
275 CH_ERR("Suspicious write out of range value: 0x%x\n", value);
276
277 data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) |
278 ((moduleid & 0xff) << 0));
279 vsc_write(adapter, REG_RAM_BIST_CMD, data);
280
281 udelay(5);
282
283 vsc_read(adapter, REG_RAM_BIST_CMD, &result);
284 if((result & (1<<27)) != 0x0)
285 CH_ERR("Still in bist write: 0x%x\n", result);
286 else if((result & (1<<26)) != 0x0)
287 CH_ERR("bist write error: 0x%x\n", result);
288
289 return(0);
290}
291
292static int run_bist(adapter_t *adapter, int moduleid)
293{
294 /*run bist*/
295 (void) bist_wr(adapter,moduleid, 0x00, 0x02);
296 (void) bist_wr(adapter,moduleid, 0x01, 0x01);
297
298 return(0);
299}
300
301static int check_bist(adapter_t *adapter, int moduleid)
302{
303 int result=0;
304 int column=0;
305 /*check bist*/
306 result = bist_rd(adapter,moduleid, 0x02);
307 column = ((bist_rd(adapter,moduleid, 0x0e)<<8) +
308 (bist_rd(adapter,moduleid, 0x0d)));
309 if ((result & 3) != 0x3)
310 CH_ERR("Result: 0x%x BIST error in ram %d, column: 0x%04x\n",
311 result, moduleid, column);
312 return(0);
313}
314
315static int enable_mem(adapter_t *adapter, int moduleid)
316{
317 /*enable mem*/
318 (void) bist_wr(adapter,moduleid, 0x00, 0x00);
319 return(0);
320}
321
322static int run_bist_all(adapter_t *adapter)
323{
324 int port=0;
325 u32 val=0;
326
327 vsc_write(adapter, REG_MEM_BIST, 0x5);
328 vsc_read(adapter, REG_MEM_BIST, &val);
329
330 for(port=0; port<12; port++){
331 vsc_write(adapter, REG_DEV_SETUP(port), 0x0);
332 }
333
334 udelay(300);
335 vsc_write(adapter, REG_SPI4_MISC, 0x00040409);
336 udelay(300);
337
338 (void) run_bist(adapter,13);
339 (void) run_bist(adapter,14);
340 (void) run_bist(adapter,20);
341 (void) run_bist(adapter,21);
342 mdelay(200);
343 (void) check_bist(adapter,13);
344 (void) check_bist(adapter,14);
345 (void) check_bist(adapter,20);
346 (void) check_bist(adapter,21);
347 udelay(100);
348 (void) enable_mem(adapter,13);
349 (void) enable_mem(adapter,14);
350 (void) enable_mem(adapter,20);
351 (void) enable_mem(adapter,21);
352 udelay(300);
353 vsc_write(adapter, REG_SPI4_MISC, 0x60040400);
354 udelay(300);
355 for(port=0; port<12; port++){
356 vsc_write(adapter, REG_DEV_SETUP(port), 0x1);
357 }
358 udelay(300);
359 vsc_write(adapter, REG_MEM_BIST, 0x0);
360 mdelay(10);
361 return(0);
362}
363
364static int mac_intr_handler(struct cmac *mac)
365{
366 return 0;
367}
368
369static int mac_intr_enable(struct cmac *mac)
370{
371 return 0;
372}
373
374static int mac_intr_disable(struct cmac *mac)
375{
376 return 0;
377}
378
379static int mac_intr_clear(struct cmac *mac)
380{
381 return 0;
382}
383
384/* Expect MAC address to be in network byte order. */
385static int mac_set_address(struct cmac* mac, u8 addr[6])
386{
387 u32 val;
388 int port = mac->instance->index;
389
390 vsc_write(mac->adapter, REG_MAC_LOW_ADDR(port),
391 (addr[3] << 16) | (addr[4] << 8) | addr[5]);
392 vsc_write(mac->adapter, REG_MAC_HIGH_ADDR(port),
393 (addr[0] << 16) | (addr[1] << 8) | addr[2]);
394
395 vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &val);
396 val &= ~0xf0000000;
397 vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, val | (port << 28));
398
399 vsc_write(mac->adapter, REG_ING_FFILT_MASK0,
400 0xffff0000 | (addr[4] << 8) | addr[5]);
401 vsc_write(mac->adapter, REG_ING_FFILT_MASK1,
402 0xffff0000 | (addr[2] << 8) | addr[3]);
403 vsc_write(mac->adapter, REG_ING_FFILT_MASK2,
404 0xffff0000 | (addr[0] << 8) | addr[1]);
405 return 0;
406}
407
408static int mac_get_address(struct cmac *mac, u8 addr[6])
409{
410 u32 addr_lo, addr_hi;
411 int port = mac->instance->index;
412
413 vsc_read(mac->adapter, REG_MAC_LOW_ADDR(port), &addr_lo);
414 vsc_read(mac->adapter, REG_MAC_HIGH_ADDR(port), &addr_hi);
415
416 addr[0] = (u8) (addr_hi >> 16);
417 addr[1] = (u8) (addr_hi >> 8);
418 addr[2] = (u8) addr_hi;
419 addr[3] = (u8) (addr_lo >> 16);
420 addr[4] = (u8) (addr_lo >> 8);
421 addr[5] = (u8) addr_lo;
422 return 0;
423}
424
425/* This is intended to reset a port, not the whole MAC */
426static int mac_reset(struct cmac *mac)
427{
428 int index = mac->instance->index;
429
430 run_table(mac->adapter, vsc7326_portinit[index],
431 ARRAY_SIZE(vsc7326_portinit[index]));
432
433 return 0;
434}
435
436static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
437{
438 u32 v;
439 int port = mac->instance->index;
440
441 vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &v);
442 v |= 1 << 12;
443
444 if (t1_rx_mode_promisc(rm))
445 v &= ~(1 << (port + 16));
446 else
447 v |= 1 << (port + 16);
448
449 vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, v);
450 return 0;
451}
452
453static int mac_set_mtu(struct cmac *mac, int mtu)
454{
455 int port = mac->instance->index;
456
457 if (mtu > MAX_MTU)
458 return -EINVAL;
459
460 /* max_len includes header and FCS */
461 vsc_write(mac->adapter, REG_MAX_LEN(port), mtu + 14 + 4);
462 return 0;
463}
464
465static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
466 int fc)
467{
468 u32 v;
469 int enable, port = mac->instance->index;
470
471 if (speed >= 0 && speed != SPEED_10 && speed != SPEED_100 &&
472 speed != SPEED_1000)
473 return -1;
474 if (duplex > 0 && duplex != DUPLEX_FULL)
475 return -1;
476
477 if (speed >= 0) {
478 vsc_read(mac->adapter, REG_MODE_CFG(port), &v);
479 enable = v & 3; /* save tx/rx enables */
480 v &= ~0xf;
481 v |= 4; /* full duplex */
482 if (speed == SPEED_1000)
483 v |= 8; /* GigE */
484 enable |= v;
485 vsc_write(mac->adapter, REG_MODE_CFG(port), v);
486
487 if (speed == SPEED_1000)
488 v = 0x82;
489 else if (speed == SPEED_100)
490 v = 0x84;
491 else /* SPEED_10 */
492 v = 0x86;
493 vsc_write(mac->adapter, REG_DEV_SETUP(port), v | 1); /* reset */
494 vsc_write(mac->adapter, REG_DEV_SETUP(port), v);
495 vsc_read(mac->adapter, REG_DBG(port), &v);
496 v &= ~0xff00;
497 if (speed == SPEED_1000)
498 v |= 0x400;
499 else if (speed == SPEED_100)
500 v |= 0x2000;
501 else /* SPEED_10 */
502 v |= 0xff00;
503 vsc_write(mac->adapter, REG_DBG(port), v);
504
505 vsc_write(mac->adapter, REG_TX_IFG(port),
506 speed == SPEED_1000 ? 5 : 0x11);
507 if (duplex == DUPLEX_HALF)
508 enable = 0x0; /* 100 or 10 */
509 else if (speed == SPEED_1000)
510 enable = 0xc;
511 else /* SPEED_100 or 10 */
512 enable = 0x4;
513 enable |= 0x9 << 10; /* IFG1 */
514 enable |= 0x6 << 6; /* IFG2 */
515 enable |= 0x1 << 4; /* VLAN */
516 enable |= 0x3; /* RX/TX EN */
517 vsc_write(mac->adapter, REG_MODE_CFG(port), enable);
518
519 }
520
521 vsc_read(mac->adapter, REG_PAUSE_CFG(port), &v);
522 v &= 0xfff0ffff;
523 v |= 0x20000; /* xon/xoff */
524 if (fc & PAUSE_RX)
525 v |= 0x40000;
526 if (fc & PAUSE_TX)
527 v |= 0x80000;
528 if (fc == (PAUSE_RX | PAUSE_TX))
529 v |= 0x10000;
530 vsc_write(mac->adapter, REG_PAUSE_CFG(port), v);
531 return 0;
532}
533
534static int mac_enable(struct cmac *mac, int which)
535{
536 u32 val;
537 int port = mac->instance->index;
538
539 /* Write the correct WM value when the port is enabled. */
540 vsc_write(mac->adapter, REG_HIGH_LOW_WM(1,port), WM_ENABLE);
541
542 vsc_read(mac->adapter, REG_MODE_CFG(port), &val);
543 if (which & MAC_DIRECTION_RX)
544 val |= 0x2;
545 if (which & MAC_DIRECTION_TX)
546 val |= 1;
547 vsc_write(mac->adapter, REG_MODE_CFG(port), val);
548 return 0;
549}
550
551static int mac_disable(struct cmac *mac, int which)
552{
553 u32 val;
554 int i, port = mac->instance->index;
555
556 /* Reset the port, this also writes the correct WM value */
557 mac_reset(mac);
558
559 vsc_read(mac->adapter, REG_MODE_CFG(port), &val);
560 if (which & MAC_DIRECTION_RX)
561 val &= ~0x2;
562 if (which & MAC_DIRECTION_TX)
563 val &= ~0x1;
564 vsc_write(mac->adapter, REG_MODE_CFG(port), val);
565 vsc_read(mac->adapter, REG_MODE_CFG(port), &val);
566
567 /* Clear stats */
568 for (i = 0; i <= 0x3a; ++i)
569 vsc_write(mac->adapter, CRA(4, port, i), 0);
570
571 /* Clear sofware counters */
572 memset(&mac->stats, 0, sizeof(struct cmac_statistics));
573
574 return 0;
575}
576
577static void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat)
578{
579 u32 v, lo;
580
581 vsc_read(mac->adapter, addr, &v);
582 lo = *stat;
583 *stat = *stat - lo + v;
584
585 if (v == 0)
586 return;
587
588 if (v < lo)
589 *stat += (1ULL << 32);
590}
591
592static void port_stats_update(struct cmac *mac)
593{
594 int port = mac->instance->index;
595
596 /* Rx stats */
597 rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK);
598 rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad);
599 rmon_update(mac, REG_RX_UNICAST(port), &mac->stats.RxUnicastFramesOK);
600 rmon_update(mac, REG_RX_MULTICAST(port),
601 &mac->stats.RxMulticastFramesOK);
602 rmon_update(mac, REG_RX_BROADCAST(port),
603 &mac->stats.RxBroadcastFramesOK);
604 rmon_update(mac, REG_CRC(port), &mac->stats.RxFCSErrors);
605 rmon_update(mac, REG_RX_ALIGNMENT(port), &mac->stats.RxAlignErrors);
606 rmon_update(mac, REG_RX_OVERSIZE(port),
607 &mac->stats.RxFrameTooLongErrors);
608 rmon_update(mac, REG_RX_PAUSE(port), &mac->stats.RxPauseFrames);
609 rmon_update(mac, REG_RX_JABBERS(port), &mac->stats.RxJabberErrors);
610 rmon_update(mac, REG_RX_FRAGMENTS(port), &mac->stats.RxRuntErrors);
611 rmon_update(mac, REG_RX_UNDERSIZE(port), &mac->stats.RxRuntErrors);
612 rmon_update(mac, REG_RX_SYMBOL_CARRIER(port),
613 &mac->stats.RxSymbolErrors);
614 rmon_update(mac, REG_RX_SIZE_1519_TO_MAX(port),
615 &mac->stats.RxJumboFramesOK);
616
617 /* Tx stats (skip collision stats as we are full-duplex only) */
618 rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
619 rmon_update(mac, REG_TX_UNICAST(port), &mac->stats.TxUnicastFramesOK);
620 rmon_update(mac, REG_TX_MULTICAST(port),
621 &mac->stats.TxMulticastFramesOK);
622 rmon_update(mac, REG_TX_BROADCAST(port),
623 &mac->stats.TxBroadcastFramesOK);
624 rmon_update(mac, REG_TX_PAUSE(port), &mac->stats.TxPauseFrames);
625 rmon_update(mac, REG_TX_UNDERRUN(port), &mac->stats.TxUnderrun);
626 rmon_update(mac, REG_TX_SIZE_1519_TO_MAX(port),
627 &mac->stats.TxJumboFramesOK);
628}
629
630/*
631 * This function is called periodically to accumulate the current values of the
632 * RMON counters into the port statistics. Since the counters are only 32 bits
633 * some of them can overflow in less than a minute at GigE speeds, so this
634 * function should be called every 30 seconds or so.
635 *
636 * To cut down on reading costs we update only the octet counters at each tick
637 * and do a full update at major ticks, which can be every 30 minutes or more.
638 */
639static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
640 int flag)
641{
642 if (flag == MAC_STATS_UPDATE_FULL ||
643 mac->instance->ticks >= MAJOR_UPDATE_TICKS) {
644 port_stats_update(mac);
645 mac->instance->ticks = 0;
646 } else {
647 int port = mac->instance->index;
648
649 rmon_update(mac, REG_RX_OK_BYTES(port),
650 &mac->stats.RxOctetsOK);
651 rmon_update(mac, REG_RX_BAD_BYTES(port),
652 &mac->stats.RxOctetsBad);
653 rmon_update(mac, REG_TX_OK_BYTES(port),
654 &mac->stats.TxOctetsOK);
655 mac->instance->ticks++;
656 }
657 return &mac->stats;
658}
659
660static void mac_destroy(struct cmac *mac)
661{
662 kfree(mac);
663}
664
665static struct cmac_ops vsc7326_ops = {
666 .destroy = mac_destroy,
667 .reset = mac_reset,
668 .interrupt_handler = mac_intr_handler,
669 .interrupt_enable = mac_intr_enable,
670 .interrupt_disable = mac_intr_disable,
671 .interrupt_clear = mac_intr_clear,
672 .enable = mac_enable,
673 .disable = mac_disable,
674 .set_mtu = mac_set_mtu,
675 .set_rx_mode = mac_set_rx_mode,
676 .set_speed_duplex_fc = mac_set_speed_duplex_fc,
677 .statistics_update = mac_update_statistics,
678 .macaddress_get = mac_get_address,
679 .macaddress_set = mac_set_address,
680};
681
682static struct cmac *vsc7326_mac_create(adapter_t *adapter, int index)
683{
684 struct cmac *mac;
685 u32 val;
686 int i;
687
688 mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
689 if (!mac) return NULL;
690
691 mac->ops = &vsc7326_ops;
692 mac->instance = (cmac_instance *)(mac + 1);
693 mac->adapter = adapter;
694
695 mac->instance->index = index;
696 mac->instance->ticks = 0;
697
698 i = 0;
699 do {
700 u32 vhi, vlo;
701
702 vhi = vlo = 0;
703 t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo);
704 udelay(1);
705 t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi);
706 udelay(5);
707 val = (vhi << 16) | vlo;
708 } while ((++i < 10000) && (val == 0xffffffff));
709
710 return mac;
711}
712
713static int vsc7326_mac_reset(adapter_t *adapter)
714{
715 vsc7326_full_reset(adapter);
716 (void) run_bist_all(adapter);
717 run_table(adapter, vsc7326_reset, ARRAY_SIZE(vsc7326_reset));
718 return 0;
719}
720
721struct gmac t1_vsc7326_ops = {
722 .stats_update_period = STATS_TICK_SECS,
723 .create = vsc7326_mac_create,
724 .reset = vsc7326_mac_reset,
725};
diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c
new file mode 100644
index 000000000000..c493e783d459
--- /dev/null
+++ b/drivers/net/chelsio/vsc8244.c
@@ -0,0 +1,368 @@
1/*
2 * This file is part of the Chelsio T2 Ethernet driver.
3 *
4 * Copyright (C) 2005 Chelsio Communications. All rights reserved.
5 *
6 * This program is distributed in the hope that it will be useful, but WITHOUT
7 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8 * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this
9 * release for licensing terms and conditions.
10 */
11
12#include "common.h"
13#include "cphy.h"
14#include "elmer0.h"
15
16#ifndef ADVERTISE_PAUSE_CAP
17# define ADVERTISE_PAUSE_CAP 0x400
18#endif
19#ifndef ADVERTISE_PAUSE_ASYM
20# define ADVERTISE_PAUSE_ASYM 0x800
21#endif
22
23/* Gigabit MII registers */
24#ifndef MII_CTRL1000
25# define MII_CTRL1000 9
26#endif
27
28#ifndef ADVERTISE_1000FULL
29# define ADVERTISE_1000FULL 0x200
30# define ADVERTISE_1000HALF 0x100
31#endif
32
33/* VSC8244 PHY specific registers. */
34enum {
35 VSC8244_INTR_ENABLE = 25,
36 VSC8244_INTR_STATUS = 26,
37 VSC8244_AUX_CTRL_STAT = 28,
38};
39
40enum {
41 VSC_INTR_RX_ERR = 1 << 0,
42 VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
43 VSC_INTR_CABLE = 1 << 2, /* cable impairment */
44 VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
45 VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
46 VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
47 VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
48 VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
49 VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
50 VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
51 VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
52 VSC_INTR_LINK_CHG = 1 << 13, /* link change */
53 VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
54};
55
56#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
57 VSC_INTR_NEG_DONE)
58#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
59 VSC_INTR_ENABLE)
60
61/* PHY specific auxiliary control & status register fields */
62#define S_ACSR_ACTIPHY_TMR 0
63#define M_ACSR_ACTIPHY_TMR 0x3
64#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
65
66#define S_ACSR_SPEED 3
67#define M_ACSR_SPEED 0x3
68#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
69
70#define S_ACSR_DUPLEX 5
71#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
72
73#define S_ACSR_ACTIPHY 6
74#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
75
76/*
77 * Reset the PHY. This PHY completes reset immediately so we never wait.
78 */
79static int vsc8244_reset(struct cphy *cphy, int wait)
80{
81 int err;
82 unsigned int ctl;
83
84 err = simple_mdio_read(cphy, MII_BMCR, &ctl);
85 if (err)
86 return err;
87
88 ctl &= ~BMCR_PDOWN;
89 ctl |= BMCR_RESET;
90 return simple_mdio_write(cphy, MII_BMCR, ctl);
91}
92
93static int vsc8244_intr_enable(struct cphy *cphy)
94{
95 simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK);
96
97 /* Enable interrupts through Elmer */
98 if (t1_is_asic(cphy->adapter)) {
99 u32 elmer;
100
101 t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
102 elmer |= ELMER0_GP_BIT1;
103 if (is_T2(cphy->adapter)) {
104 elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
105 }
106 t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
107 }
108
109 return 0;
110}
111
112static int vsc8244_intr_disable(struct cphy *cphy)
113{
114 simple_mdio_write(cphy, VSC8244_INTR_ENABLE, 0);
115
116 if (t1_is_asic(cphy->adapter)) {
117 u32 elmer;
118
119 t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
120 elmer &= ~ELMER0_GP_BIT1;
121 if (is_T2(cphy->adapter)) {
122 elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
123 }
124 t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
125 }
126
127 return 0;
128}
129
130static int vsc8244_intr_clear(struct cphy *cphy)
131{
132 u32 val;
133 u32 elmer;
134
135 /* Clear PHY interrupts by reading the register. */
136 simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val);
137
138 if (t1_is_asic(cphy->adapter)) {
139 t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
140 elmer |= ELMER0_GP_BIT1;
141 if (is_T2(cphy->adapter)) {
142 elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
143 }
144 t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
145 }
146
147 return 0;
148}
149
150/*
151 * Force the PHY speed and duplex. This also disables auto-negotiation, except
152 * for 1Gb/s, where auto-negotiation is mandatory.
153 */
154static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex)
155{
156 int err;
157 unsigned int ctl;
158
159 err = simple_mdio_read(phy, MII_BMCR, &ctl);
160 if (err)
161 return err;
162
163 if (speed >= 0) {
164 ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
165 if (speed == SPEED_100)
166 ctl |= BMCR_SPEED100;
167 else if (speed == SPEED_1000)
168 ctl |= BMCR_SPEED1000;
169 }
170 if (duplex >= 0) {
171 ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
172 if (duplex == DUPLEX_FULL)
173 ctl |= BMCR_FULLDPLX;
174 }
175 if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */
176 ctl |= BMCR_ANENABLE;
177 return simple_mdio_write(phy, MII_BMCR, ctl);
178}
179
180int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits)
181{
182 int ret;
183 unsigned int val;
184
185 ret = mdio_read(phy, mmd, reg, &val);
186 if (!ret)
187 ret = mdio_write(phy, mmd, reg, val | bits);
188 return ret;
189}
190
191static int vsc8244_autoneg_enable(struct cphy *cphy)
192{
193 return t1_mdio_set_bits(cphy, 0, MII_BMCR,
194 BMCR_ANENABLE | BMCR_ANRESTART);
195}
196
197static int vsc8244_autoneg_restart(struct cphy *cphy)
198{
199 return t1_mdio_set_bits(cphy, 0, MII_BMCR, BMCR_ANRESTART);
200}
201
202static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map)
203{
204 int err;
205 unsigned int val = 0;
206
207 err = simple_mdio_read(phy, MII_CTRL1000, &val);
208 if (err)
209 return err;
210
211 val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
212 if (advertise_map & ADVERTISED_1000baseT_Half)
213 val |= ADVERTISE_1000HALF;
214 if (advertise_map & ADVERTISED_1000baseT_Full)
215 val |= ADVERTISE_1000FULL;
216
217 err = simple_mdio_write(phy, MII_CTRL1000, val);
218 if (err)
219 return err;
220
221 val = 1;
222 if (advertise_map & ADVERTISED_10baseT_Half)
223 val |= ADVERTISE_10HALF;
224 if (advertise_map & ADVERTISED_10baseT_Full)
225 val |= ADVERTISE_10FULL;
226 if (advertise_map & ADVERTISED_100baseT_Half)
227 val |= ADVERTISE_100HALF;
228 if (advertise_map & ADVERTISED_100baseT_Full)
229 val |= ADVERTISE_100FULL;
230 if (advertise_map & ADVERTISED_PAUSE)
231 val |= ADVERTISE_PAUSE_CAP;
232 if (advertise_map & ADVERTISED_ASYM_PAUSE)
233 val |= ADVERTISE_PAUSE_ASYM;
234 return simple_mdio_write(phy, MII_ADVERTISE, val);
235}
236
237static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok,
238 int *speed, int *duplex, int *fc)
239{
240 unsigned int bmcr, status, lpa, adv;
241 int err, sp = -1, dplx = -1, pause = 0;
242
243 err = simple_mdio_read(cphy, MII_BMCR, &bmcr);
244 if (!err)
245 err = simple_mdio_read(cphy, MII_BMSR, &status);
246 if (err)
247 return err;
248
249 if (link_ok) {
250 /*
251 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
252 * once more to get the current link state.
253 */
254 if (!(status & BMSR_LSTATUS))
255 err = simple_mdio_read(cphy, MII_BMSR, &status);
256 if (err)
257 return err;
258 *link_ok = (status & BMSR_LSTATUS) != 0;
259 }
260 if (!(bmcr & BMCR_ANENABLE)) {
261 dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
262 if (bmcr & BMCR_SPEED1000)
263 sp = SPEED_1000;
264 else if (bmcr & BMCR_SPEED100)
265 sp = SPEED_100;
266 else
267 sp = SPEED_10;
268 } else if (status & BMSR_ANEGCOMPLETE) {
269 err = simple_mdio_read(cphy, VSC8244_AUX_CTRL_STAT, &status);
270 if (err)
271 return err;
272
273 dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
274 sp = G_ACSR_SPEED(status);
275 if (sp == 0)
276 sp = SPEED_10;
277 else if (sp == 1)
278 sp = SPEED_100;
279 else
280 sp = SPEED_1000;
281
282 if (fc && dplx == DUPLEX_FULL) {
283 err = simple_mdio_read(cphy, MII_LPA, &lpa);
284 if (!err)
285 err = simple_mdio_read(cphy, MII_ADVERTISE,
286 &adv);
287 if (err)
288 return err;
289
290 if (lpa & adv & ADVERTISE_PAUSE_CAP)
291 pause = PAUSE_RX | PAUSE_TX;
292 else if ((lpa & ADVERTISE_PAUSE_CAP) &&
293 (lpa & ADVERTISE_PAUSE_ASYM) &&
294 (adv & ADVERTISE_PAUSE_ASYM))
295 pause = PAUSE_TX;
296 else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
297 (adv & ADVERTISE_PAUSE_CAP))
298 pause = PAUSE_RX;
299 }
300 }
301 if (speed)
302 *speed = sp;
303 if (duplex)
304 *duplex = dplx;
305 if (fc)
306 *fc = pause;
307 return 0;
308}
309
310static int vsc8244_intr_handler(struct cphy *cphy)
311{
312 unsigned int cause;
313 int err, cphy_cause = 0;
314
315 err = simple_mdio_read(cphy, VSC8244_INTR_STATUS, &cause);
316 if (err)
317 return err;
318
319 cause &= INTR_MASK;
320 if (cause & CFG_CHG_INTR_MASK)
321 cphy_cause |= cphy_cause_link_change;
322 if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
323 cphy_cause |= cphy_cause_fifo_error;
324 return cphy_cause;
325}
326
327static void vsc8244_destroy(struct cphy *cphy)
328{
329 kfree(cphy);
330}
331
332static struct cphy_ops vsc8244_ops = {
333 .destroy = vsc8244_destroy,
334 .reset = vsc8244_reset,
335 .interrupt_enable = vsc8244_intr_enable,
336 .interrupt_disable = vsc8244_intr_disable,
337 .interrupt_clear = vsc8244_intr_clear,
338 .interrupt_handler = vsc8244_intr_handler,
339 .autoneg_enable = vsc8244_autoneg_enable,
340 .autoneg_restart = vsc8244_autoneg_restart,
341 .advertise = vsc8244_advertise,
342 .set_speed_duplex = vsc8244_set_speed_duplex,
343 .get_link_status = vsc8244_get_link_status
344};
345
346static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, struct mdio_ops *mdio_ops)
347{
348 struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
349
350 if (!cphy) return NULL;
351
352 cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops);
353
354 return cphy;
355}
356
357
358static int vsc8244_phy_reset(adapter_t* adapter)
359{
360 return 0;
361}
362
363struct gphy t1_vsc8244_ops = {
364 vsc8244_phy_create,
365 vsc8244_phy_reset
366};
367
368
diff --git a/drivers/net/chelsio/vsc8244_reg.h b/drivers/net/chelsio/vsc8244_reg.h
new file mode 100644
index 000000000000..d3c1829055cb
--- /dev/null
+++ b/drivers/net/chelsio/vsc8244_reg.h
@@ -0,0 +1,172 @@
1/* $Date: 2005/11/23 16:28:53 $ $RCSfile: vsc8244_reg.h,v $ $Revision: 1.1 $ */
2#ifndef CHELSIO_MV8E1XXX_H
3#define CHELSIO_MV8E1XXX_H
4
5#ifndef BMCR_SPEED1000
6# define BMCR_SPEED1000 0x40
7#endif
8
9#ifndef ADVERTISE_PAUSE
10# define ADVERTISE_PAUSE 0x400
11#endif
12#ifndef ADVERTISE_PAUSE_ASYM
13# define ADVERTISE_PAUSE_ASYM 0x800
14#endif
15
16/* Gigabit MII registers */
17#define MII_GBMR 1 /* 1000Base-T mode register */
18#define MII_GBCR 9 /* 1000Base-T control register */
19#define MII_GBSR 10 /* 1000Base-T status register */
20
21/* 1000Base-T control register fields */
22#define GBCR_ADV_1000HALF 0x100
23#define GBCR_ADV_1000FULL 0x200
24#define GBCR_PREFER_MASTER 0x400
25#define GBCR_MANUAL_AS_MASTER 0x800
26#define GBCR_MANUAL_CONFIG_ENABLE 0x1000
27
28/* 1000Base-T status register fields */
29#define GBSR_LP_1000HALF 0x400
30#define GBSR_LP_1000FULL 0x800
31#define GBSR_REMOTE_OK 0x1000
32#define GBSR_LOCAL_OK 0x2000
33#define GBSR_LOCAL_MASTER 0x4000
34#define GBSR_MASTER_FAULT 0x8000
35
36/* Vitesse PHY interrupt status bits. */
37#if 0
38#define VSC8244_INTR_JABBER 0x0001
39#define VSC8244_INTR_POLARITY_CHNG 0x0002
40#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010
41#define VSC8244_INTR_DOWNSHIFT 0x0020
42#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040
43#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080
44#define VSC8244_INTR_FALSE_CARRIER 0x0100
45#define VSC8244_INTR_SYMBOL_ERROR 0x0200
46#define VSC8244_INTR_LINK_CHNG 0x0400
47#define VSC8244_INTR_AUTONEG_DONE 0x0800
48#define VSC8244_INTR_PAGE_RECV 0x1000
49#define VSC8244_INTR_DUPLEX_CHNG 0x2000
50#define VSC8244_INTR_SPEED_CHNG 0x4000
51#define VSC8244_INTR_AUTONEG_ERR 0x8000
52#else
53//#define VSC8244_INTR_JABBER 0x0001
54//#define VSC8244_INTR_POLARITY_CHNG 0x0002
55//#define VSC8244_INTR_BIT2 0x0004
56//#define VSC8244_INTR_BIT3 0x0008
57#define VSC8244_INTR_RX_ERR 0x0001
58#define VSC8244_INTR_MASTER_SLAVE 0x0002
59#define VSC8244_INTR_CABLE_IMPAIRED 0x0004
60#define VSC8244_INTR_FALSE_CARRIER 0x0008
61//#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010
62//#define VSC8244_INTR_DOWNSHIFT 0x0020
63//#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040
64//#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080
65#define VSC8244_INTR_BIT4 0x0010
66#define VSC8244_INTR_FIFO_RX 0x0020
67#define VSC8244_INTR_FIFO_OVER_UNDER 0x0040
68#define VSC8244_INTR_LOCK_LOST 0x0080
69//#define VSC8244_INTR_FALSE_CARRIER 0x0100
70//#define VSC8244_INTR_SYMBOL_ERROR 0x0200
71//#define VSC8244_INTR_LINK_CHNG 0x0400
72//#define VSC8244_INTR_AUTONEG_DONE 0x0800
73#define VSC8244_INTR_SYMBOL_ERROR 0x0100
74#define VSC8244_INTR_ENG_DETECT_CHNG 0x0200
75#define VSC8244_INTR_AUTONEG_DONE 0x0400
76#define VSC8244_INTR_AUTONEG_ERR 0x0800
77//#define VSC8244_INTR_PAGE_RECV 0x1000
78//#define VSC8244_INTR_DUPLEX_CHNG 0x2000
79//#define VSC8244_INTR_SPEED_CHNG 0x4000
80//#define VSC8244_INTR_AUTONEG_ERR 0x8000
81#define VSC8244_INTR_DUPLEX_CHNG 0x1000
82#define VSC8244_INTR_LINK_CHNG 0x2000
83#define VSC8244_INTR_SPEED_CHNG 0x4000
84#define VSC8244_INTR_STATUS 0x8000
85#endif
86
87
88/* Vitesse PHY specific registers. */
89#define VSC8244_SPECIFIC_CNTRL_REGISTER 16
90#define VSC8244_SPECIFIC_STATUS_REGISTER 0x1c
91#define VSC8244_INTERRUPT_ENABLE_REGISTER 0x19
92#define VSC8244_INTERRUPT_STATUS_REGISTER 0x1a
93#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_REGISTER 20
94#define VSC8244_RECV_ERR_CNTR_REGISTER 21
95#define VSC8244_RES_REGISTER 22
96#define VSC8244_GLOBAL_STATUS_REGISTER 23
97#define VSC8244_LED_CONTROL_REGISTER 24
98#define VSC8244_MANUAL_LED_OVERRIDE_REGISTER 25
99#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_2_REGISTER 26
100#define VSC8244_EXT_PHY_SPECIFIC_STATUS_REGISTER 27
101#define VSC8244_VIRTUAL_CABLE_TESTER_REGISTER 28
102#define VSC8244_EXTENDED_ADDR_REGISTER 29
103#define VSC8244_EXTENDED_REGISTER 30
104
105/* PHY specific control register fields */
106#define S_PSCR_MDI_XOVER_MODE 5
107#define M_PSCR_MDI_XOVER_MODE 0x3
108#define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE)
109#define G_PSCR_MDI_XOVER_MODE(x) (((x) >> S_PSCR_MDI_XOVER_MODE) & M_PSCR_MDI_XOVER_MODE)
110
111/* Extended PHY specific control register fields */
112#define S_DOWNSHIFT_ENABLE 8
113#define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE)
114
115#define S_DOWNSHIFT_CNT 9
116#define M_DOWNSHIFT_CNT 0x7
117#define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT)
118#define G_DOWNSHIFT_CNT(x) (((x) >> S_DOWNSHIFT_CNT) & M_DOWNSHIFT_CNT)
119
120/* PHY specific status register fields */
121#define S_PSSR_JABBER 0
122#define V_PSSR_JABBER (1 << S_PSSR_JABBER)
123
124#define S_PSSR_POLARITY 1
125#define V_PSSR_POLARITY (1 << S_PSSR_POLARITY)
126
127#define S_PSSR_RX_PAUSE 2
128#define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE)
129
130#define S_PSSR_TX_PAUSE 3
131#define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE)
132
133#define S_PSSR_ENERGY_DETECT 4
134#define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT)
135
136#define S_PSSR_DOWNSHIFT_STATUS 5
137#define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS)
138
139#define S_PSSR_MDI 6
140#define V_PSSR_MDI (1 << S_PSSR_MDI)
141
142#define S_PSSR_CABLE_LEN 7
143#define M_PSSR_CABLE_LEN 0x7
144#define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN)
145#define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN)
146
147//#define S_PSSR_LINK 10
148//#define S_PSSR_LINK 13
149#define S_PSSR_LINK 2
150#define V_PSSR_LINK (1 << S_PSSR_LINK)
151
152//#define S_PSSR_STATUS_RESOLVED 11
153//#define S_PSSR_STATUS_RESOLVED 10
154#define S_PSSR_STATUS_RESOLVED 15
155#define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED)
156
157#define S_PSSR_PAGE_RECEIVED 12
158#define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED)
159
160//#define S_PSSR_DUPLEX 13
161//#define S_PSSR_DUPLEX 12
162#define S_PSSR_DUPLEX 5
163#define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX)
164
165//#define S_PSSR_SPEED 14
166//#define S_PSSR_SPEED 14
167#define S_PSSR_SPEED 3
168#define M_PSSR_SPEED 0x3
169#define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED)
170#define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED)
171
172#endif