1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (C) 2003-2005 Chelsio Communications. All rights reserved.
24 */
25
26 #include "gmac.h"
27 #include "regs.h"
28 #include "fpga_defs.h"
29
30 #define MAC_CSR_INTERFACE_GMII 0x0
31 #define MAC_CSR_INTERFACE_TBI 0x1
32 #define MAC_CSR_INTERFACE_MII 0x2
33 #define MAC_CSR_INTERFACE_RMII 0x3
34
35 /* Chelsio's MAC statistics. */
36 struct mac_statistics {
37
38 /* Transmit */
39 u32 TxFramesTransmittedOK;
40 u32 TxReserved1;
41 u32 TxReserved2;
42 u32 TxOctetsTransmittedOK;
43 u32 TxFramesWithDeferredXmissions;
44 u32 TxLateCollisions;
45 u32 TxFramesAbortedDueToXSCollisions;
46 u32 TxFramesLostDueToIntMACXmitError;
47 u32 TxReserved3;
48 u32 TxMulticastFrameXmittedOK;
49 u32 TxBroadcastFramesXmittedOK;
50 u32 TxFramesWithExcessiveDeferral;
51 u32 TxPAUSEMACCtrlFramesTransmitted;
52
53 /* Receive */
54 u32 RxFramesReceivedOK;
55 u32 RxFrameCheckSequenceErrors;
56 u32 RxAlignmentErrors;
57 u32 RxOctetsReceivedOK;
58 u32 RxFramesLostDueToIntMACRcvError;
59 u32 RxMulticastFramesReceivedOK;
60 u32 RxBroadcastFramesReceivedOK;
61 u32 RxInRangeLengthErrors;
62 u32 RxTxOutOfRangeLengthField;
63 u32 RxFrameTooLongErrors;
64 u32 RxPAUSEMACCtrlFramesReceived;
65 };
66
67 static int static_aPorts[] = {
68 FPGA_GMAC_INTERRUPT_PORT0,
69 FPGA_GMAC_INTERRUPT_PORT1,
70 FPGA_GMAC_INTERRUPT_PORT2,
71 FPGA_GMAC_INTERRUPT_PORT3
72 };
73
74 struct _cmac_instance {
75 u32 index;
76 };
77
mac_intr_enable(struct cmac * mac)78 static int mac_intr_enable(struct cmac *mac)
79 {
80 u32 mac_intr;
81
82 if (t1_is_asic(mac->adapter)) {
83 /* ASIC */
84 /*EMPTY*/
85 /* We don't use the on chip MAC for ASIC products. */
86 } else {
87 /* FPGA */
88
89 /* Set parent gmac interrupt. */
90 mac_intr = t1_read_reg_4(mac->adapter, A_PL_ENABLE);
91 mac_intr |= FPGA_PCIX_INTERRUPT_GMAC;
92 t1_write_reg_4(mac->adapter, A_PL_ENABLE, mac_intr);
93
94 mac_intr = t1_read_reg_4(mac->adapter,
95 FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
96 mac_intr |= static_aPorts[mac->instance->index];
97 t1_write_reg_4(mac->adapter,
98 FPGA_GMAC_ADDR_INTERRUPT_ENABLE, mac_intr);
99 }
100
101 return (0);
102 }
103
mac_intr_disable(struct cmac * mac)104 static int mac_intr_disable(struct cmac *mac)
105 {
106 u32 mac_intr;
107
108 if (t1_is_asic(mac->adapter)) {
109 /* ASIC */
110 /*EMPTY*/
111 /* We don't use the on chip MAC for ASIC products. */
112 } else {
113 /* FPGA */
114
115 /* Set parent gmac interrupt. */
116 mac_intr = t1_read_reg_4(mac->adapter, A_PL_ENABLE);
117 mac_intr &= ~FPGA_PCIX_INTERRUPT_GMAC;
118 t1_write_reg_4(mac->adapter, A_PL_ENABLE, mac_intr);
119
120 mac_intr = t1_read_reg_4(mac->adapter,
121 FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
122 mac_intr &= ~(static_aPorts[mac->instance->index]);
123 t1_write_reg_4(mac->adapter,
124 FPGA_GMAC_ADDR_INTERRUPT_ENABLE, mac_intr);
125 }
126
127 return (0);
128 }
129
mac_intr_clear(struct cmac * mac)130 static int mac_intr_clear(struct cmac *mac)
131 {
132 u32 mac_intr;
133
134 if (t1_is_asic(mac->adapter)) {
135 /* ASIC */
136 /*EMPTY*/
137 /* We don't use the on chip MAC for ASIC products. */
138 } else {
139 /* FPGA */
140
141 /* Set parent gmac interrupt. */
142 t1_write_reg_4(mac->adapter, A_PL_CAUSE,
143 FPGA_PCIX_INTERRUPT_GMAC);
144
145 mac_intr = t1_read_reg_4(mac->adapter,
146 FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
147 mac_intr |= (static_aPorts[mac->instance->index]);
148 t1_write_reg_4(mac->adapter,
149 FPGA_GMAC_ADDR_INTERRUPT_CAUSE, mac_intr);
150 }
151
152 return (0);
153 }
154
mac_get_address(struct cmac * mac,u8 addr[6])155 static int mac_get_address(struct cmac *mac, u8 addr[6])
156 {
157 u32 data32_lo, data32_hi;
158
159 data32_lo = t1_read_reg_4(mac->adapter,
160 MAC_REG_IDLO(mac->instance->index));
161 data32_hi = t1_read_reg_4(mac->adapter,
162 MAC_REG_IDHI(mac->instance->index));
163
164 addr[0] = (u8) ((data32_hi >> 8) & 0xFF);
165 addr[1] = (u8) ((data32_hi) & 0xFF);
166 addr[2] = (u8) ((data32_lo >> 24) & 0xFF);
167 addr[3] = (u8) ((data32_lo >> 16) & 0xFF);
168 addr[4] = (u8) ((data32_lo >> 8) & 0xFF);
169 addr[5] = (u8) ((data32_lo) & 0xFF);
170 return (0);
171 }
172
mac_reset(struct cmac * mac)173 static int mac_reset(struct cmac *mac)
174 {
175 u32 data32;
176 int mac_in_reset, time_out = 100;
177 int idx = mac->instance->index;
178
179 data32 = t1_read_reg_4(mac->adapter, MAC_REG_CSR(idx));
180 t1_write_reg_4(mac->adapter, MAC_REG_CSR(idx),
181 data32 | F_MAC_RESET);
182
183 do {
184 data32 = t1_read_reg_4(mac->adapter,
185 MAC_REG_CSR(idx));
186 mac_in_reset = data32 & F_MAC_RESET;
187 if (mac_in_reset)
188 DELAY_US(1);
189 } while (mac_in_reset && --time_out);
190
191 if (mac_in_reset) {
192 CH_ERR("%s: MAC %d reset timed out\n",
193 adapter_name(mac->adapter), idx);
194 return (2);
195 }
196
197 return (0);
198 }
199
mac_set_rx_mode(struct cmac * mac,struct t1_rx_mode * rm)200 static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
201 {
202 u32 val;
203
204 val = t1_read_reg_4(mac->adapter,
205 MAC_REG_CSR(mac->instance->index));
206 val &= ~(F_MAC_PROMISC | F_MAC_MC_ENABLE);
207 val |= V_MAC_PROMISC(t1_rx_mode_promisc(rm) != 0);
208 val |= V_MAC_MC_ENABLE(t1_rx_mode_allmulti(rm) != 0);
209 t1_write_reg_4(mac->adapter,
210 MAC_REG_CSR(mac->instance->index), val);
211
212 return (0);
213 }
214
mac_set_speed_duplex_fc(struct cmac * mac,int speed,int duplex,int fc)215 static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
216 int fc)
217 {
218 u32 data32;
219
220 data32 = t1_read_reg_4(mac->adapter,
221 MAC_REG_CSR(mac->instance->index));
222 data32 &= ~(F_MAC_HALF_DUPLEX | V_MAC_SPEED(M_MAC_SPEED) |
223 V_INTERFACE(M_INTERFACE) | F_MAC_TX_PAUSE_ENABLE |
224 F_MAC_RX_PAUSE_ENABLE);
225
226 switch (speed) {
227 case SPEED_10:
228 case SPEED_100:
229 data32 |= V_INTERFACE(MAC_CSR_INTERFACE_MII);
230 data32 |= V_MAC_SPEED(speed == SPEED_10 ? 0 : 1);
231 break;
232 case SPEED_1000:
233 data32 |= V_INTERFACE(MAC_CSR_INTERFACE_GMII);
234 data32 |= V_MAC_SPEED(2);
235 break;
236 }
237
238 if (duplex >= 0)
239 data32 |= V_MAC_HALF_DUPLEX(duplex == DUPLEX_HALF);
240
241 if (fc >= 0) {
242 data32 |= V_MAC_RX_PAUSE_ENABLE((fc & PAUSE_RX) != 0);
243 data32 |= V_MAC_TX_PAUSE_ENABLE((fc & PAUSE_TX) != 0);
244 }
245
246 t1_write_reg_4(mac->adapter,
247 MAC_REG_CSR(mac->instance->index), data32);
248 return (0);
249 }
250
mac_enable(struct cmac * mac,int which)251 static int mac_enable(struct cmac *mac, int which)
252 {
253 u32 val;
254
255 val = t1_read_reg_4(mac->adapter,
256 MAC_REG_CSR(mac->instance->index));
257 if (which & MAC_DIRECTION_RX)
258 val |= F_MAC_RX_ENABLE;
259 if (which & MAC_DIRECTION_TX)
260 val |= F_MAC_TX_ENABLE;
261 t1_write_reg_4(mac->adapter,
262 MAC_REG_CSR(mac->instance->index), val);
263 return (0);
264 }
265
mac_disable(struct cmac * mac,int which)266 static int mac_disable(struct cmac *mac, int which)
267 {
268 u32 val;
269
270 val = t1_read_reg_4(mac->adapter,
271 MAC_REG_CSR(mac->instance->index));
272 if (which & MAC_DIRECTION_RX)
273 val &= ~F_MAC_RX_ENABLE;
274 if (which & MAC_DIRECTION_TX)
275 val &= ~F_MAC_TX_ENABLE;
276 t1_write_reg_4(mac->adapter,
277 MAC_REG_CSR(mac->instance->index), val);
278 return (0);
279 }
280
281 int
mac_set_ifs(struct cmac * mac,u32 mode)282 mac_set_ifs(struct cmac *mac, u32 mode)
283 {
284 t1_write_reg_4(mac->adapter,
285 MAC_REG_IFS(mac->instance->index), mode);
286
287 return (0);
288 }
289
290 int
mac_enable_isl(struct cmac * mac)291 mac_enable_isl(struct cmac *mac)
292 {
293 u32 data32 = t1_read_reg_4(mac->adapter,
294 MAC_REG_CSR(mac->instance->index));
295 data32 |= F_MAC_RX_ENABLE | F_MAC_TX_ENABLE;
296 t1_write_reg_4(mac->adapter,
297 MAC_REG_CSR(mac->instance->index), data32);
298
299 return (0);
300 }
301
mac_set_mtu(struct cmac * mac,int mtu)302 static int mac_set_mtu(struct cmac *mac, int mtu)
303 {
304 if (mtu > 9600)
305 return (-EINVAL);
306 t1_write_reg_4(mac->adapter,
307 MAC_REG_LARGEFRAMELENGTH(mac->instance->index),
308 mtu + 14 + 4);
309 return (0);
310 }
311
312 /* ARGSUSED */
mac_update_statistics(struct cmac * mac,int flag)313 static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
314 int flag)
315 {
316 struct mac_statistics st;
317 u32 *p = (u32 *) & st, i;
318
319 t1_write_reg_4(mac->adapter,
320 MAC_REG_RMCNT(mac->instance->index), 0);
321 for (i = 0; i < sizeof (st) / sizeof (u32); i++)
322 *p++ = t1_read_reg_4(mac->adapter,
323 MAC_REG_RMDATA(mac->instance->index));
324
325 /* XXX convert stats */
326 return (&mac->stats);
327 }
328
mac_destroy(struct cmac * mac)329 static void mac_destroy(struct cmac *mac)
330 {
331 t1_os_free((void *)mac, sizeof (*mac) + sizeof (cmac_instance));
332 }
333
334 #ifdef C99_NOT_SUPPORTED
335 static struct cmac_ops chelsio_mac_ops = {
336 mac_destroy,
337 mac_reset,
338 mac_intr_enable,
339 mac_intr_disable,
340 mac_intr_clear,
341 NULL,
342 mac_enable,
343 mac_disable,
344 NULL,
345 NULL,
346 mac_set_mtu,
347 mac_set_rx_mode,
348 mac_set_speed_duplex_fc,
349 NULL,
350 mac_update_statistics,
351 mac_get_address,
352 NULL
353 };
354 #else
355 static struct cmac_ops chelsio_mac_ops = {
356 .destroy = mac_destroy,
357 .reset = mac_reset,
358 .interrupt_enable = mac_intr_enable,
359 .interrupt_disable = mac_intr_disable,
360 .interrupt_clear = mac_intr_clear,
361 .enable = mac_enable,
362 .disable = mac_disable,
363 .set_mtu = mac_set_mtu,
364 .set_rx_mode = mac_set_rx_mode,
365 .set_speed_duplex_fc = mac_set_speed_duplex_fc,
366 .macaddress_get = mac_get_address,
367 .statistics_update = mac_update_statistics,
368 };
369 #endif
370
mac_create(adapter_t * adapter,int index)371 static struct cmac *mac_create(adapter_t *adapter, int index)
372 {
373 struct cmac *mac;
374 u32 data32;
375
376 if (index >= 4)
377 return (NULL);
378
379 mac = t1_os_malloc_wait_zero(sizeof (*mac) + sizeof (cmac_instance));
380 if (!mac)
381 return (NULL);
382
383 mac->ops = &chelsio_mac_ops;
384 mac->instance = (cmac_instance *) (mac + 1);
385
386 mac->instance->index = index;
387 mac->adapter = adapter;
388
389 data32 = t1_read_reg_4(adapter, MAC_REG_CSR(mac->instance->index));
390 data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC |
391 F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE);
392 data32 |= F_MAC_JUMBO_ENABLE;
393 t1_write_reg_4(adapter, MAC_REG_CSR(mac->instance->index), data32);
394
395 /* Initialize the random backoff seed. */
396 data32 = 0x55aa + (3 * index);
397 t1_write_reg_4(adapter,
398 MAC_REG_GMRANDBACKOFFSEED(mac->instance->index), data32);
399
400 /* Check to see if the mac address needs to be set manually. */
401 data32 = t1_read_reg_4(adapter, MAC_REG_IDLO(mac->instance->index));
402 if (data32 == 0 || data32 == 0xffffffff) {
403 /*
404 * Add a default MAC address if we can't read one.
405 */
406 t1_write_reg_4(adapter, MAC_REG_IDLO(mac->instance->index),
407 0x43FFFFFF - index);
408 t1_write_reg_4(adapter, MAC_REG_IDHI(mac->instance->index),
409 0x0007);
410 }
411
412 (void) mac_set_mtu(mac, 1500);
413 return (mac);
414 }
415
416 struct gmac t1_chelsio_mac_ops = {
417 0,
418 mac_create
419 };
420