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