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