diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-12-01 19:36:17 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-12-02 00:24:49 -0500 |
commit | 352c417ddb593de757f0ee1fa490cb5444778c41 (patch) | |
tree | dd1047e7611f09511c3ad1432a3f49b553b0e91e | |
parent | f1d3d38af75789f1b82969b83b69cab540609789 (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>
-rw-r--r-- | drivers/net/Kconfig | 7 | ||||
-rw-r--r-- | drivers/net/chelsio/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/chelsio/common.h | 2 | ||||
-rw-r--r-- | drivers/net/chelsio/cxgb2.c | 1 | ||||
-rw-r--r-- | drivers/net/chelsio/ixf1010.c | 485 | ||||
-rw-r--r-- | drivers/net/chelsio/mac.c | 368 | ||||
-rw-r--r-- | drivers/net/chelsio/mv88e1xxx.c | 397 | ||||
-rw-r--r-- | drivers/net/chelsio/subr.c | 221 | ||||
-rw-r--r-- | drivers/net/chelsio/tp.c | 33 | ||||
-rw-r--r-- | drivers/net/chelsio/vsc7326.c | 725 | ||||
-rw-r--r-- | drivers/net/chelsio/vsc8244.c | 368 | ||||
-rw-r--r-- | drivers/net/chelsio/vsc8244_reg.h | 172 |
12 files changed, 2780 insertions, 0 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 2f10dd554e3..ee391f29dae 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 | ||
2379 | config 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 | |||
2379 | config EHEA | 2386 | config 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 6d87316e58c..382d23f810a 100644 --- a/drivers/net/chelsio/Makefile +++ b/drivers/net/chelsio/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_CHELSIO_T1) += cxgb.o | 5 | obj-$(CONFIG_CHELSIO_T1) += cxgb.o |
6 | 6 | ||
7 | cxgb-$(CONFIG_CHELSIO_T1_1G) += ixf1010.o mac.o mv88e1xxx.o vsc7326.o vsc8244.o | ||
7 | cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \ | 8 | cxgb-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 e4e59d2d410..55f1eaad115 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 a8c873b0af5..571aa06ddfd 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 00000000000..5b8f144e83d --- /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 */ | ||
18 | enum { | ||
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 | |||
92 | enum { /* 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 | |||
124 | enum { | ||
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 | |||
132 | struct _cmac_instance { | ||
133 | u32 mac_base; | ||
134 | u32 index; | ||
135 | u32 version; | ||
136 | u32 ticks; | ||
137 | }; | ||
138 | |||
139 | static 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 | */ | ||
156 | static 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 */ | ||
193 | static int mac_intr_op(struct cmac *mac) | ||
194 | { | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* Expect MAC address to be in network byte order. */ | ||
199 | static 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 | |||
216 | static 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 */ | ||
233 | static int mac_reset(struct cmac *mac) | ||
234 | { | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static 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 | |||
273 | static 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 | |||
282 | static 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 | |||
307 | static 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 | |||
330 | static 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 */ | ||
378 | static 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 | |||
385 | static 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 | */ | ||
401 | static 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 | |||
418 | static void mac_destroy(struct cmac *mac) | ||
419 | { | ||
420 | kfree(mac); | ||
421 | } | ||
422 | |||
423 | static 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 | |||
440 | static 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 | |||
458 | static 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 | |||
481 | struct 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 00000000000..6af39dc7045 --- /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. */ | ||
12 | struct 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 | |||
43 | static 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 | |||
50 | struct _cmac_instance { | ||
51 | u32 index; | ||
52 | }; | ||
53 | |||
54 | static 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 | |||
79 | static 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 | |||
104 | static 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 | |||
127 | static 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 | |||
145 | static 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 | |||
172 | static 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 | |||
187 | static 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 | |||
223 | static 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 | |||
238 | static 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 | ||
254 | static 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 | |||
262 | static 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 | |||
274 | static 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 | |||
284 | static 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 | |||
301 | static void mac_destroy(struct cmac *mac) | ||
302 | { | ||
303 | kfree(mac); | ||
304 | } | ||
305 | |||
306 | static 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 | |||
321 | static 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 | |||
366 | struct 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 00000000000..28ac93ff7c4 --- /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 | */ | ||
17 | static 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 | */ | ||
28 | static 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 | */ | ||
47 | static 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 | |||
64 | static 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 | |||
84 | static 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 | |||
103 | static 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 | */ | ||
127 | static 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 | |||
150 | static 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 | |||
163 | static 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 | |||
176 | static 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 | |||
196 | static int mv88e1xxx_autoneg_restart(struct cphy *cphy) | ||
197 | { | ||
198 | mdio_set_bit(cphy, MII_BMCR, BMCR_ANRESTART); | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static 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 | |||
234 | static 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 | |||
243 | static 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 | |||
276 | static 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 | |||
296 | static 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 | |||
337 | static void mv88e1xxx_destroy(struct cphy *cphy) | ||
338 | { | ||
339 | kfree(cphy); | ||
340 | } | ||
341 | |||
342 | static 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 | |||
358 | static 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 | |||
389 | static int mv88e1xxx_phy_reset(adapter_t* adapter) | ||
390 | { | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | struct 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 d41d15a71e4..22ed9a383c0 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 | */ | ||
197 | static 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 | */ | ||
217 | static 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 | */ | ||
288 | static 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 | |||
306 | static 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) | ||
325 | static 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 | |||
224 | static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr, | 334 | static 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 | ||
634 | int t1_slow_intr_handler(adapter_t *adapter) | 821 | int 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 | ||
777 | static void __devinit init_link_config(struct link_config *lc, | 991 | static 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 04a7073e9d1..0ca0b6e19e4 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 | ||
6 | struct petp { | 9 | struct 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 | ||
92 | void t1_tp_intr_clear(struct petp *tp) | 112 | void 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 00000000000..85dc3b1dc30 --- /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 | |||
24 | struct init_table { | ||
25 | u32 addr; | ||
26 | u32 data; | ||
27 | }; | ||
28 | |||
29 | struct _cmac_instance { | ||
30 | u32 index; | ||
31 | u32 ticks; | ||
32 | }; | ||
33 | |||
34 | #define INITBLOCK_SLEEP 0xffffffff | ||
35 | |||
36 | static 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 | |||
64 | static 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. */ | ||
76 | static 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 | |||
96 | static 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 | |||
114 | static 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 | |||
221 | static 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 | |||
235 | static 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 | |||
262 | static 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 | |||
292 | static 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 | |||
301 | static 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 | |||
315 | static 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 | |||
322 | static 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 | |||
364 | static int mac_intr_handler(struct cmac *mac) | ||
365 | { | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static int mac_intr_enable(struct cmac *mac) | ||
370 | { | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int mac_intr_disable(struct cmac *mac) | ||
375 | { | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static int mac_intr_clear(struct cmac *mac) | ||
380 | { | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /* Expect MAC address to be in network byte order. */ | ||
385 | static 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 | |||
408 | static 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 */ | ||
426 | static 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 | |||
436 | static 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 | |||
453 | static 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 | |||
465 | static 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 | |||
534 | static 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 | |||
551 | static 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 | |||
577 | static 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 | |||
592 | static 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 | */ | ||
639 | static 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 | |||
660 | static void mac_destroy(struct cmac *mac) | ||
661 | { | ||
662 | kfree(mac); | ||
663 | } | ||
664 | |||
665 | static 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 | |||
682 | static 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 | |||
713 | static 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 | |||
721 | struct 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 00000000000..c493e783d45 --- /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. */ | ||
34 | enum { | ||
35 | VSC8244_INTR_ENABLE = 25, | ||
36 | VSC8244_INTR_STATUS = 26, | ||
37 | VSC8244_AUX_CTRL_STAT = 28, | ||
38 | }; | ||
39 | |||
40 | enum { | ||
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 | */ | ||
79 | static 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 | |||
93 | static 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 | |||
112 | static 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 | |||
130 | static 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 | */ | ||
154 | static 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 | |||
180 | int 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 | |||
191 | static 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 | |||
197 | static int vsc8244_autoneg_restart(struct cphy *cphy) | ||
198 | { | ||
199 | return t1_mdio_set_bits(cphy, 0, MII_BMCR, BMCR_ANRESTART); | ||
200 | } | ||
201 | |||
202 | static 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 | |||
237 | static 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 | |||
310 | static 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 | |||
327 | static void vsc8244_destroy(struct cphy *cphy) | ||
328 | { | ||
329 | kfree(cphy); | ||
330 | } | ||
331 | |||
332 | static 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 | |||
346 | static 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 | |||
358 | static int vsc8244_phy_reset(adapter_t* adapter) | ||
359 | { | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | struct 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 00000000000..d3c1829055c --- /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 | ||