aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-12-01 19:36:17 -0500
committerJeff Garzik <jeff@garzik.org>2006-12-02 00:24:49 -0500
commit352c417ddb593de757f0ee1fa490cb5444778c41 (patch)
treedd1047e7611f09511c3ad1432a3f49b553b0e91e /drivers
parentf1d3d38af75789f1b82969b83b69cab540609789 (diff)
[PATCH] chelsio: add 1G swcixw aupport
Add support for 1G versions of Chelsio devices. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/Kconfig7
-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
12 files changed, 2780 insertions, 0 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 2f10dd554e33..ee391f29dae7 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2376,6 +2376,13 @@ config CHELSIO_T1
2376 To compile this driver as a module, choose M here: the module 2376 To compile this driver as a module, choose M here: the module
2377 will be called cxgb. 2377 will be called cxgb.
2378 2378
2379config CHELSIO_T1_1G
2380 bool "Chelsio gigabit Ethernet support"
2381 depends on CHELSIO_T1
2382 help
2383 Enables support for Chelsio's gigabit Ethernet PCI cards. If you
2384 are using only 10G cards say 'N' here.
2385
2379config EHEA 2386config EHEA
2380 tristate "eHEA Ethernet support" 2387 tristate "eHEA Ethernet support"
2381 depends on IBMEBUS 2388 depends on IBMEBUS
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