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