]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/cxgb/common/cxgb_xgmac.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / cxgb / common / cxgb_xgmac.c
1 /**************************************************************************
2
3 Copyright (c) 2007, Chelsio Inc.
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9  1. Redistributions of source code must retain the above copyright notice,
10     this list of conditions and the following disclaimer.
11
12  2. Neither the name of the Chelsio Corporation nor the names of its
13     contributors may be used to endorse or promote products derived from
14     this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 POSSIBILITY OF SUCH DAMAGE.
27
28 ***************************************************************************/
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #ifdef CONFIG_DEFINED
34 #include <cxgb_include.h>
35 #else
36 #include <dev/cxgb/cxgb_include.h>
37 #endif
38
39 #undef msleep
40 #define msleep t3_os_sleep
41
42
43 static inline int macidx(const struct cmac *mac)
44 {
45         return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
46 }
47
48 static void xaui_serdes_reset(struct cmac *mac)
49 {
50         static const unsigned int clear[] = {
51                 F_PWRDN0 | F_PWRDN1,    F_RESETPLL01,    F_RESET0 | F_RESET1,
52                 F_PWRDN2 | F_PWRDN3,    F_RESETPLL23,    F_RESET2 | F_RESET3
53         };
54
55         int i;
56         adapter_t *adap = mac->adapter;
57         u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
58
59         t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
60                      F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
61                      F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
62                      F_RESETPLL23 | F_RESETPLL01);
63         (void)t3_read_reg(adap, ctrl);
64         udelay(15);
65
66         for (i = 0; i < ARRAY_SIZE(clear); i++) {
67                 t3_set_reg_field(adap, ctrl, clear[i], 0);
68                 udelay(15);
69         }
70 }
71
72 /**
73  *      t3b_pcs_reset - reset the PCS on T3B+ adapters
74  *      @mac: the XGMAC handle
75  *
76  *      Reset the XGMAC PCS block on T3B+ adapters.
77  */
78 void t3b_pcs_reset(struct cmac *mac)
79 {
80         t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
81                          F_PCS_RESET_, 0);
82         udelay(20);
83         t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
84                          F_PCS_RESET_);
85 }
86
87 /**
88  *      t3_mac_reset - reset a MAC
89  *      @mac: the MAC to reset
90  *
91  *      Reset the given MAC.
92  */
93 int t3_mac_reset(struct cmac *mac)
94 {
95         static struct addr_val_pair mac_reset_avp[] = {
96                 { A_XGM_TX_CTRL, 0 },
97                 { A_XGM_RX_CTRL, 0 },
98                 { A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
99                                 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST },
100                 { A_XGM_RX_HASH_LOW, 0 },
101                 { A_XGM_RX_HASH_HIGH, 0 },
102                 { A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
103                 { A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
104                 { A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
105                 { A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
106                 { A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
107                 { A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
108                 { A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
109                 { A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
110                 { A_XGM_STAT_CTRL, F_CLRSTATS }
111         };
112         u32 val;
113         adapter_t *adap = mac->adapter;
114         unsigned int oft = mac->offset;
115
116         t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
117         (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
118
119         t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
120         t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
121                          F_RXSTRFRWRD | F_DISERRFRAMES,
122                          uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
123         t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);
124
125         if (uses_xaui(adap)) {
126                 if (adap->params.rev == 0) {
127                         t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
128                                          F_RXENABLE | F_TXENABLE);
129                         if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
130                                             F_CMULOCK, 1, 5, 2)) {
131                                 CH_ERR(adap,
132                                        "MAC %d XAUI SERDES CMU lock failed\n",
133                                        macidx(mac));
134                                 return -1;
135                         }
136                         t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
137                                          F_SERDESRESET_);
138                 } else
139                         xaui_serdes_reset(mac);
140         }
141
142
143         if (mac->multiport) {
144                 t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
145                              MAX_FRAME_SIZE - 4);
146                 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
147                                  F_DISPREAMBLE);
148                 t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
149                                  F_ENNON802_3PREAMBLE);
150                 t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
151                                  V_TXFIFOTHRESH(M_TXFIFOTHRESH),
152                                  V_TXFIFOTHRESH(64));
153                 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
154                 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
155         }
156
157         t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
158                          V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
159                          V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
160
161         val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
162         if (!mac->multiport)
163                 val |= F_XG2G_RESET_;
164         if (uses_xaui(adap))
165                 val |= F_PCS_RESET_;
166         else
167                 val |= F_RGMII_RESET_;
168         t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
169         (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
170         if ((val & F_PCS_RESET_) && adap->params.rev) {
171                 msleep(1);
172                 t3b_pcs_reset(mac);
173         }
174
175         memset(&mac->stats, 0, sizeof(mac->stats));
176         return 0;
177 }
178
179 static int t3b2_mac_reset(struct cmac *mac)
180 {
181         u32 val;
182         adapter_t *adap = mac->adapter;
183         unsigned int oft = mac->offset;
184         int idx = macidx(mac);
185         unsigned int store;
186
187         /* Stop egress traffic to xgm*/
188         if (!macidx(mac))
189                 t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
190         else
191                 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
192
193         /* PCS in reset */
194         t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
195         (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
196
197         /* Store A_TP_TX_DROP_CFG_CH0 */
198         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
199         store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx);
200
201         msleep(10);
202
203         /* Change DROP_CFG to 0xc0000011 */
204         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
205         t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011);
206
207         /* Check for xgm Rx fifo empty */
208         /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
209         if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
210                             0x80000000, 1, 1000, 2)) {
211                 CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
212                        macidx(mac));
213                 return -1;
214         }
215
216         t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
217         (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
218
219         val = F_MAC_RESET_;
220         if (is_10G(adap))
221                 val |= F_PCS_RESET_;
222         else if (uses_xaui(adap))
223                 val |= F_PCS_RESET_ | F_XG2G_RESET_;
224         else
225                 val |= F_RGMII_RESET_ | F_XG2G_RESET_;
226         t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
227         (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
228         if ((val & F_PCS_RESET_) && adap->params.rev) {
229                 msleep(1);
230                 t3b_pcs_reset(mac);
231         }
232         t3_write_reg(adap, A_XGM_RX_CFG + oft,
233                  F_DISPAUSEFRAMES | F_EN1536BFRAMES |
234                                 F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
235
236         /* Restore the DROP_CFG */
237         t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
238         t3_write_reg(adap, A_TP_PIO_DATA, store);
239
240         /* Resume egress traffic to xgm */
241         if (!macidx(mac))
242                 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
243         else
244                 t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
245
246         return 0;
247 }
248
249 /*
250  * Set the exact match register 'idx' to recognize the given Ethernet address.
251  */
252 static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
253 {
254         u32 addr_lo, addr_hi;
255         unsigned int oft = mac->offset + idx * 8;
256
257         addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
258         addr_hi = (addr[5] << 8) | addr[4];
259
260         t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
261         t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
262 }
263
264 /**
265  *      t3_mac_set_address - set one of the station's unicast MAC addresses
266  *      @mac: the MAC handle
267  *      @idx: index of the exact address match filter to use
268  *      @addr: the Ethernet address
269  *
270  *      Set one of the station's unicast MAC addresses.
271  */
272 int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
273 {
274         if (mac->multiport)
275                 idx = mac->ext_port + idx * mac->adapter->params.nports;
276         if (idx >= mac->nucast)
277                 return -EINVAL;
278         set_addr_filter(mac, idx, addr);
279         if (mac->multiport && idx < mac->adapter->params.nports)
280                 t3_vsc7323_set_addr(mac->adapter, addr, idx);
281         return 0;
282 }
283
284 /**
285  *      t3_mac_set_num_ucast - set the number of unicast addresses needed
286  *      @mac: the MAC handle
287  *      @n: number of unicast addresses needed
288  *
289  *      Specify the number of exact address filters that should be reserved for
290  *      unicast addresses.  Caller should reload the unicast and multicast
291  *      addresses after calling this.
292  *
293  *      Generally, this is 1 with the first one used for the station address,
294  *      and the rest are available for multicast addresses.
295  */
296 int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
297 {
298         if (n > EXACT_ADDR_FILTERS)
299                 return -EINVAL;
300         mac->nucast = n;
301         return 0;
302 }
303
304 static void disable_exact_filters(struct cmac *mac)
305 {
306         unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
307
308         for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
309                 u32 v = t3_read_reg(mac->adapter, reg);
310                 t3_write_reg(mac->adapter, reg, v);
311         }
312         t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
313 }
314
315 static void enable_exact_filters(struct cmac *mac)
316 {
317         unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
318
319         for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
320                 u32 v = t3_read_reg(mac->adapter, reg);
321                 t3_write_reg(mac->adapter, reg, v);
322         }
323         t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
324 }
325
326 /* Calculate the RX hash filter index of an Ethernet address */
327 static int hash_hw_addr(const u8 *addr)
328 {
329         int hash = 0, octet, bit, i = 0, c;
330
331         for (octet = 0; octet < 6; ++octet)
332                 for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
333                         hash ^= (c & 1) << i;
334                         if (++i == 6)
335                                 i = 0;
336                 }
337         return hash;
338 }
339
340 /**
341  *      t3_mac_set_rx_mode - set the Rx mode and address filters
342  *      @mac: the MAC to configure
343  *      @rm: structure containing the Rx mode and MAC addresses needed
344  *
345  *      Configures the MAC Rx mode (promiscuity, etc) and exact and hash
346  *      address filters.
347  */
348 int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
349 {
350         u32 hash_lo, hash_hi;
351         adapter_t *adap = mac->adapter;
352         unsigned int oft = mac->offset;
353
354         if (promisc_rx_mode(rm))
355                 mac->promisc_map |= 1 << mac->ext_port;
356         else
357                 mac->promisc_map &= ~(1 << mac->ext_port);
358         t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
359                          mac->promisc_map ? F_COPYALLFRAMES : 0);
360
361         if (allmulti_rx_mode(rm) || mac->multiport)
362                 hash_lo = hash_hi = 0xffffffff;
363         else {
364                 u8 *addr;
365                 int exact_addr_idx = mac->nucast;
366
367                 hash_lo = hash_hi = 0;
368                 while ((addr = t3_get_next_mcaddr(rm)))
369                         if (exact_addr_idx < EXACT_ADDR_FILTERS)
370                                 set_addr_filter(mac, exact_addr_idx++, addr);
371                         else {
372                                 int hash = hash_hw_addr(addr);
373
374                                 if (hash < 32)
375                                         hash_lo |= (1 << hash);
376                                 else
377                                         hash_hi |= (1 << (hash - 32));
378                         }
379         }
380
381         t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
382         t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
383         return 0;
384 }
385
386 static int rx_fifo_hwm(int mtu)
387 {
388         int hwm;
389
390         hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
391         return min(hwm, MAC_RXFIFO_SIZE - 8192);
392 }
393
394 /**
395  *      t3_mac_set_mtu - set the MAC MTU
396  *      @mac: the MAC to configure
397  *      @mtu: the MTU
398  *
399  *      Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
400  */
401 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
402 {
403         int hwm, lwm, divisor;
404         int ipg;
405         unsigned int thres, v, reg;
406         adapter_t *adap = mac->adapter;
407
408         /*
409          * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
410          * packet size register includes header, but not FCS.
411          */
412         mtu += 14;
413         if (mac->multiport)
414                 mtu += 8;                             /* for preamble */
415         if (mtu > MAX_FRAME_SIZE - 4)
416                 return -EINVAL;
417         if (mac->multiport)
418                 return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
419
420         if (adap->params.rev >= T3_REV_B2 &&
421             (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
422                 disable_exact_filters(mac);
423                 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
424                 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
425                                  F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
426
427                 reg = adap->params.rev == T3_REV_B2 ?
428                         A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
429
430                 /* drain RX FIFO */
431                 if (t3_wait_op_done(adap, reg + mac->offset,
432                                     F_RXFIFO_EMPTY, 1, 20, 5)) {
433                         t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
434                         enable_exact_filters(mac);
435                         return -EIO;
436                 }
437                 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
438                                  V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
439                                  V_RXMAXPKTSIZE(mtu));
440                 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
441                 enable_exact_filters(mac);
442         } else
443                 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
444                                  V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
445                                  V_RXMAXPKTSIZE(mtu));
446         /*
447          * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
448          * HWM only if flow-control is enabled.
449          */
450         hwm = rx_fifo_hwm(mtu);
451         lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
452         v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
453         v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
454         v |= V_RXFIFOPAUSELWM(lwm / 8);
455         if (G_RXFIFOPAUSEHWM(v))
456                 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
457                     V_RXFIFOPAUSEHWM(hwm / 8);
458
459         t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
460
461         /* Adjust the TX FIFO threshold based on the MTU */
462         thres = (adap->params.vpd.cclk * 1000) / 15625;
463         thres = (thres * mtu) / 1000;
464         if (is_10G(adap))
465                 thres /= 10;
466         thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
467         thres = max(thres, 8U);                          /* need at least 8 */
468         ipg = (adap->params.rev == T3_REV_C) ? 0 : 1;
469         t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
470                          V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
471                          V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
472
473         /* Assuming a minimum drain rate of 2.5Gbps...
474          */
475         if (adap->params.rev > 0) {
476                 divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;
477                 t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
478                              (hwm - lwm) * 4 / divisor);
479         }
480         t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
481                      MAC_RXFIFO_SIZE * 4 * 8 / 512);
482         return 0;
483 }
484
485 /**
486  *      t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control
487  *      @mac: the MAC to configure
488  *      @speed: the desired speed (10/100/1000/10000)
489  *      @duplex: the desired duplex
490  *      @fc: desired Tx/Rx PAUSE configuration
491  *
492  *      Set the MAC speed, duplex (actually only full-duplex is supported), and
493  *      flow control.  If a parameter value is negative the corresponding
494  *      MAC setting is left at its current value.
495  */
496 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
497 {
498         u32 val;
499         adapter_t *adap = mac->adapter;
500         unsigned int oft = mac->offset;
501
502         if (duplex >= 0 && duplex != DUPLEX_FULL)
503                 return -EINVAL;
504         if (mac->multiport) {
505                 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
506                 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
507                 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
508                                         A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
509                 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
510
511                 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
512                                         F_TXPAUSEEN);
513                 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
514         }
515         if (speed >= 0) {
516                 if (speed == SPEED_10)
517                         val = V_PORTSPEED(0);
518                 else if (speed == SPEED_100)
519                         val = V_PORTSPEED(1);
520                 else if (speed == SPEED_1000)
521                         val = V_PORTSPEED(2);
522                 else if (speed == SPEED_10000)
523                         val = V_PORTSPEED(3);
524                 else
525                         return -EINVAL;
526
527                 t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
528                                  V_PORTSPEED(M_PORTSPEED), val);
529         }
530
531         val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
532         val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
533         if (fc & PAUSE_TX)
534                 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
535                                         A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
536         t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
537
538         t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
539                         (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
540         return 0;
541 }
542
543 /**
544  *      t3_mac_enable - enable the MAC in the given directions
545  *      @mac: the MAC to configure
546  *      @which: bitmap indicating which directions to enable
547  *
548  *      Enables the MAC for operation in the given directions.
549  *      %MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX
550  *      enables the Rx one.
551  */
552 int t3_mac_enable(struct cmac *mac, int which)
553 {
554         int idx = macidx(mac);
555         adapter_t *adap = mac->adapter;
556         unsigned int oft = mac->offset;
557         struct mac_stats *s = &mac->stats;
558
559         if (mac->multiport)
560                 return t3_vsc7323_enable(adap, mac->ext_port, which);
561
562         if (which & MAC_DIRECTION_TX) {
563                 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
564                 t3_write_reg(adap, A_TP_PIO_DATA,
565                              adap->params.rev == T3_REV_C ?
566                              0xc4ffff01 : 0xc0ede401);
567                 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
568                 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
569                                  adap->params.rev == T3_REV_C ?
570                                  0 : 1 << idx);
571
572                 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
573
574                 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
575                 mac->tx_mcnt = s->tx_frames;
576                 mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
577                                                                A_TP_PIO_DATA)));
578                 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
579                                                 A_XGM_TX_SPI4_SOP_EOP_CNT +
580                                                 oft)));
581                 mac->rx_mcnt = s->rx_frames;
582                 mac->rx_pause = s->rx_pause;
583                 mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
584                                                 A_XGM_RX_SPI4_SOP_EOP_CNT +
585                                                 oft)));
586                 mac->rx_ocnt = s->rx_fifo_ovfl;
587                 mac->txen = F_TXEN;
588                 mac->toggle_cnt = 0;
589         }
590         if (which & MAC_DIRECTION_RX)
591                 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
592         return 0;
593 }
594
595 /**
596  *      t3_mac_disable - disable the MAC in the given directions
597  *      @mac: the MAC to configure
598  *      @which: bitmap indicating which directions to disable
599  *
600  *      Disables the MAC in the given directions.
601  *      %MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX
602  *      disables the Rx one.
603  */
604 int t3_mac_disable(struct cmac *mac, int which)
605 {
606         adapter_t *adap = mac->adapter;
607
608         if (mac->multiport)
609                 return t3_vsc7323_disable(adap, mac->ext_port, which);
610
611         if (which & MAC_DIRECTION_TX) {
612                 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
613                 mac->txen = 0;
614         }
615         if (which & MAC_DIRECTION_RX) {
616                 int val = F_MAC_RESET_;
617
618                 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
619                                  F_PCS_RESET_, 0);
620                 msleep(100);
621                 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
622                 if (is_10G(adap))
623                         val |= F_PCS_RESET_;
624                 else if (uses_xaui(adap))
625                         val |= F_PCS_RESET_ | F_XG2G_RESET_;
626                 else
627                         val |= F_RGMII_RESET_ | F_XG2G_RESET_;
628                 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
629         }
630         return 0;
631 }
632
633 int t3b2_mac_watchdog_task(struct cmac *mac)
634 {
635         int status;
636         unsigned int tx_tcnt, tx_xcnt;
637         adapter_t *adap = mac->adapter;
638         struct mac_stats *s = &mac->stats;
639         unsigned int tx_mcnt = (unsigned int)s->tx_frames;
640
641         if (mac->multiport) {
642           tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
643         } else {
644           tx_mcnt = (unsigned int)s->tx_frames;
645         }
646         status = 0;
647         tx_xcnt = 1; /* By default tx_xcnt is making progress*/
648         tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
649         if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
650                 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
651                                                 A_XGM_TX_SPI4_SOP_EOP_CNT +
652                                                 mac->offset)));
653                 if (tx_xcnt == 0) {
654                         t3_write_reg(adap, A_TP_PIO_ADDR,
655                                 A_TP_TX_DROP_CNT_CH0 + macidx(mac));
656                         tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
657                                 A_TP_PIO_DATA)));
658                 } else {
659                         goto out;
660                 }
661         } else {
662                 mac->toggle_cnt = 0;
663                 goto out;
664         }
665
666         if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
667                 if (mac->toggle_cnt > 4) {
668                         status = 2;
669                         goto out;
670                 } else {
671                         status = 1;
672                         goto out;
673                 }
674         } else {
675                 mac->toggle_cnt = 0;
676                 goto out;
677         }
678
679 out:
680         mac->tx_tcnt = tx_tcnt;
681         mac->tx_xcnt = tx_xcnt;
682         mac->tx_mcnt = s->tx_frames;
683         mac->rx_pause = s->rx_pause;
684         if (status == 1) {
685                 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
686                 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
687                 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
688                 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
689                 mac->toggle_cnt++;
690         } else if (status == 2) {
691                 t3b2_mac_reset(mac);
692                 mac->toggle_cnt = 0;
693         }
694         return status;
695 }
696
697 /**
698  *      t3_mac_update_stats - accumulate MAC statistics
699  *      @mac: the MAC handle
700  *
701  *      This function is called periodically to accumulate the current values
702  *      of the RMON counters into the port statistics.  Since the packet
703  *      counters are only 32 bits they can overflow in ~286 secs at 10G, so the
704  *      function should be called more frequently than that.  The byte counters
705  *      are 45-bit wide, they would overflow in ~7.8 hours.
706  */
707 const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
708 {
709 #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
710 #define RMON_UPDATE(mac, name, reg) \
711         (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
712 #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
713         (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
714                              ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
715
716         u32 v, lo;
717
718         if (mac->multiport)
719                 return t3_vsc7323_update_stats(mac);
720
721         RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
722         RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
723         RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
724         RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
725         RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
726         RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
727         RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
728         RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
729         RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
730
731         RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
732
733         v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
734         if (mac->adapter->params.rev == T3_REV_B2)
735                 v &= 0x7fffffff;
736         mac->stats.rx_too_long += v;
737
738         RMON_UPDATE(mac, rx_frames_64,        RX_64B_FRAMES);
739         RMON_UPDATE(mac, rx_frames_65_127,    RX_65_127B_FRAMES);
740         RMON_UPDATE(mac, rx_frames_128_255,   RX_128_255B_FRAMES);
741         RMON_UPDATE(mac, rx_frames_256_511,   RX_256_511B_FRAMES);
742         RMON_UPDATE(mac, rx_frames_512_1023,  RX_512_1023B_FRAMES);
743         RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
744         RMON_UPDATE(mac, rx_frames_1519_max,  RX_1519_MAXB_FRAMES);
745
746         RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
747         RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
748         RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
749         RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
750         RMON_UPDATE(mac, tx_pause, TX_PAUSE);
751         /* This counts error frames in general (bad FCS, underrun, etc). */
752         RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
753
754         RMON_UPDATE(mac, tx_frames_64,        TX_64B_FRAMES);
755         RMON_UPDATE(mac, tx_frames_65_127,    TX_65_127B_FRAMES);
756         RMON_UPDATE(mac, tx_frames_128_255,   TX_128_255B_FRAMES);
757         RMON_UPDATE(mac, tx_frames_256_511,   TX_256_511B_FRAMES);
758         RMON_UPDATE(mac, tx_frames_512_1023,  TX_512_1023B_FRAMES);
759         RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
760         RMON_UPDATE(mac, tx_frames_1519_max,  TX_1519_MAXB_FRAMES);
761
762         /* The next stat isn't clear-on-read. */
763         t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
764         v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
765         lo = (u32)mac->stats.rx_cong_drops;
766         mac->stats.rx_cong_drops += (u64)(v - lo);
767
768         return &mac->stats;
769 }