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