This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / net / chelsio / mac.c
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 };