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