]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cxgb/common/cxgb_xgmac.c
MFV r353619: 9691 fat zap should prefetch when iterating
[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 int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
412 {
413         u32 hash_lo, hash_hi;
414         adapter_t *adap = mac->adapter;
415         unsigned int oft = mac->offset;
416
417         if (promisc_rx_mode(rm))
418                 mac->promisc_map |= 1 << mac->ext_port;
419         else
420                 mac->promisc_map &= ~(1 << mac->ext_port);
421         t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
422                          mac->promisc_map ? F_COPYALLFRAMES : 0);
423
424         if (allmulti_rx_mode(rm) || mac->multiport)
425                 hash_lo = hash_hi = 0xffffffff;
426         else {
427                 u8 *addr;
428                 int exact_addr_idx = mac->nucast;
429
430                 hash_lo = hash_hi = 0;
431                 while ((addr = t3_get_next_mcaddr(rm)))
432                         if (exact_addr_idx < EXACT_ADDR_FILTERS)
433                                 set_addr_filter(mac, exact_addr_idx++, addr);
434                         else {
435                                 int hash = hash_hw_addr(addr);
436
437                                 if (hash < 32)
438                                         hash_lo |= (1 << hash);
439                                 else
440                                         hash_hi |= (1 << (hash - 32));
441                         }
442         }
443
444         t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
445         t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
446         return 0;
447 }
448
449 static int rx_fifo_hwm(int mtu)
450 {
451         int hwm;
452
453         hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
454         return min(hwm, MAC_RXFIFO_SIZE - 8192);
455 }
456
457 /**
458  *      t3_mac_set_mtu - set the MAC MTU
459  *      @mac: the MAC to configure
460  *      @mtu: the MTU
461  *
462  *      Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
463  */
464 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
465 {
466         int hwm, lwm;
467         int ipg;
468         unsigned int thres, v, reg;
469         adapter_t *adap = mac->adapter;
470         unsigned port_type = adap->params.vpd.port_type[macidx(mac)];
471         unsigned int orig_mtu=mtu;
472
473         /*
474          * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
475          * packet size register includes header, but not FCS.
476          */
477         mtu += 14;
478         if (mac->multiport)
479                 mtu += 8;                             /* for preamble */
480         if (mtu > MAX_FRAME_SIZE - 4)
481                 return -EINVAL;
482         if (mac->multiport)
483                 return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
484
485         /* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */
486         if (port_type == 2) {
487                 int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac));
488
489                 if (err)
490                         return err;
491         }
492
493         if (adap->params.rev >= T3_REV_B2 &&
494             (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
495                 t3_mac_disable_exact_filters(mac);
496                 v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
497                 t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
498                                  F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
499
500                 reg = adap->params.rev == T3_REV_B2 ?
501                         A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
502
503                 /* drain RX FIFO */
504                 if (t3_wait_op_done(adap, reg + mac->offset,
505                                     F_RXFIFO_EMPTY, 1, 20, 5)) {
506                         t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
507                         t3_mac_enable_exact_filters(mac);
508                         return -EIO;
509                 }
510                 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
511                                  V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
512                                  V_RXMAXPKTSIZE(mtu));
513                 t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
514                 t3_mac_enable_exact_filters(mac);
515         } else
516                 t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
517                                  V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
518                                  V_RXMAXPKTSIZE(mtu));
519         /*
520          * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
521          * HWM only if flow-control is enabled.
522          */
523         hwm = rx_fifo_hwm(mtu);
524         lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
525         v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
526         v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
527         v |= V_RXFIFOPAUSELWM(lwm / 8);
528         if (G_RXFIFOPAUSEHWM(v))
529                 v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
530                     V_RXFIFOPAUSEHWM(hwm / 8);
531
532         t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
533
534         /* Adjust the TX FIFO threshold based on the MTU */
535         thres = (adap->params.vpd.cclk * 1000) / 15625;
536         thres = (thres * mtu) / 1000;
537         if (is_10G(adap))
538                 thres /= 10;
539         thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
540         thres = max(thres, 8U);                          /* need at least 8 */
541         ipg = (port_type == 9 || adap->params.rev != T3_REV_C) ? 1 : 0;
542         t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
543                          V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
544                          V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
545         return 0;
546 }
547
548 /**
549  *      t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control
550  *      @mac: the MAC to configure
551  *      @speed: the desired speed (10/100/1000/10000)
552  *      @duplex: the desired duplex
553  *      @fc: desired Tx/Rx PAUSE configuration
554  *
555  *      Set the MAC speed, duplex (actually only full-duplex is supported), and
556  *      flow control.  If a parameter value is negative the corresponding
557  *      MAC setting is left at its current value.
558  */
559 int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
560 {
561         u32 val;
562         adapter_t *adap = mac->adapter;
563         unsigned int oft = mac->offset;
564         unsigned int pause_bits;
565
566         if (duplex >= 0 && duplex != DUPLEX_FULL)
567                 return -EINVAL;
568
569         pause_bits = MAC_RXFIFO_SIZE * 4 * 8;
570         t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
571                      pause_bits / 512);
572         t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
573                      (pause_bits >> (adap->params.rev == T3_REV_C ? 10 : 7)));
574
575         if (mac->multiport) {
576                 u32 rx_max_pkt_size =
577                     G_RXMAXPKTSIZE(t3_read_reg(adap,
578                                                A_XGM_RX_MAX_PKT_SIZE + oft));
579                 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
580                 val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
581                 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
582                 t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
583                 t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
584                                         F_TXPAUSEEN);
585
586                 return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
587         }
588         if (speed >= 0) {
589                 if (speed == SPEED_10)
590                         val = V_PORTSPEED(0);
591                 else if (speed == SPEED_100)
592                         val = V_PORTSPEED(1);
593                 else if (speed == SPEED_1000)
594                         val = V_PORTSPEED(2);
595                 else if (speed == SPEED_10000)
596                         val = V_PORTSPEED(3);
597                 else
598                         return -EINVAL;
599
600                 if (!uses_xaui(adap)) /* T302 */
601                         t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
602                             V_PORTSPEED(M_PORTSPEED), val);
603                 else {
604                         u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft);
605
606                         if ((old & V_PORTSPEED(M_PORTSPEED)) != val) {
607                                 t3_mac_reset(mac, val);
608                                 mac->was_reset = 1;
609                         }
610                 }
611         }
612
613         val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
614         val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
615         if (fc & PAUSE_TX) {
616                 u32 rx_max_pkt_size =
617                     G_RXMAXPKTSIZE(t3_read_reg(adap,
618                                                A_XGM_RX_MAX_PKT_SIZE + oft));
619                 val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
620         }
621         t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
622
623         t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
624                         (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
625         return 0;
626 }
627
628 /**
629  *      t3_mac_enable - enable the MAC in the given directions
630  *      @mac: the MAC to configure
631  *      @which: bitmap indicating which directions to enable
632  *
633  *      Enables the MAC for operation in the given directions.
634  *      %MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX
635  *      enables the Rx one.
636  */
637 int t3_mac_enable(struct cmac *mac, int which)
638 {
639         int idx = macidx(mac);
640         adapter_t *adap = mac->adapter;
641         unsigned int oft = mac->offset;
642         struct mac_stats *s = &mac->stats;
643
644         if (mac->multiport)
645                 return t3_vsc7323_enable(adap, mac->ext_port, which);
646
647         if (which & MAC_DIRECTION_TX) {
648                 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
649                 t3_write_reg(adap, A_TP_PIO_DATA,
650                              adap->params.rev == T3_REV_C ?
651                              0xc4ffff01 : 0xc0ede401);
652                 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
653                 t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
654                                  adap->params.rev == T3_REV_C ?
655                                  0 : 1 << idx);
656
657                 t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
658
659                 t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
660                 mac->tx_mcnt = s->tx_frames;
661                 mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
662                                                                A_TP_PIO_DATA)));
663                 mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
664                                                 A_XGM_TX_SPI4_SOP_EOP_CNT +
665                                                 oft)));
666                 mac->rx_mcnt = s->rx_frames;
667                 mac->rx_pause = s->rx_pause;
668                 mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
669                                                 A_XGM_RX_SPI4_SOP_EOP_CNT +
670                                                 oft)));
671                 mac->rx_ocnt = s->rx_fifo_ovfl;
672                 mac->txen = F_TXEN;
673                 mac->toggle_cnt = 0;
674         }
675         if (which & MAC_DIRECTION_RX)
676                 t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
677         return 0;
678 }
679
680 /**
681  *      t3_mac_disable - disable the MAC in the given directions
682  *      @mac: the MAC to configure
683  *      @which: bitmap indicating which directions to disable
684  *
685  *      Disables the MAC in the given directions.
686  *      %MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX
687  *      disables the Rx one.
688  */
689 int t3_mac_disable(struct cmac *mac, int which)
690 {
691         adapter_t *adap = mac->adapter;
692
693         if (mac->multiport)
694                 return t3_vsc7323_disable(adap, mac->ext_port, which);
695
696         if (which & MAC_DIRECTION_TX) {
697                 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
698                 mac->txen = 0;
699         }
700         if (which & MAC_DIRECTION_RX) {
701                 int val = xgm_reset_ctrl(mac);
702
703                 t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
704                                  F_PCS_RESET_, 0);
705                 msleep(100);
706                 t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
707                 t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
708         }
709         return 0;
710 }
711
712 int t3b2_mac_watchdog_task(struct cmac *mac)
713 {
714         int status;
715         unsigned int tx_tcnt, tx_xcnt;
716         adapter_t *adap = mac->adapter;
717         struct mac_stats *s = &mac->stats;
718         u64 tx_mcnt = s->tx_frames;
719
720         if (mac->multiport)
721                 tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
722
723         status = 0;
724         tx_xcnt = 1; /* By default tx_xcnt is making progress*/
725         tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
726         if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
727                 u32 cfg, active, enforcepkt;
728
729                 tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
730                                                       A_XGM_TX_SPI4_SOP_EOP_CNT +
731                                                       mac->offset)));
732                 cfg = t3_read_reg(adap, A_MPS_CFG);
733                 active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE;
734                 enforcepkt = cfg & F_ENFORCEPKT;        
735                 if (active && enforcepkt && (tx_xcnt == 0)) {
736                         t3_write_reg(adap, A_TP_PIO_ADDR,
737                                 A_TP_TX_DROP_CNT_CH0 + macidx(mac));
738                         tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
739                                 A_TP_PIO_DATA)));
740                 } else
741                         goto out;
742
743         } else {
744                 mac->toggle_cnt = 0;
745                 goto out;
746         }
747
748         if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
749                 if (mac->toggle_cnt > 4) {
750                         status = 2;
751                         goto out;
752                 } else {
753                         status = 1;
754                         goto out;
755                 }
756         } else {
757                 mac->toggle_cnt = 0;
758                 goto out;
759         }
760
761 out:
762         mac->tx_tcnt = tx_tcnt;
763         mac->tx_xcnt = tx_xcnt;
764         mac->tx_mcnt = s->tx_frames;
765         mac->rx_pause = s->rx_pause;
766         if (status == 1) {
767                 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
768                 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
769                 t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
770                 t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
771                 mac->toggle_cnt++;
772         } else if (status == 2) {
773                 t3_mac_reset(mac, -1);
774                 mac->toggle_cnt = 0;
775         }
776         return status;
777 }
778
779 /**
780  *      t3_mac_update_stats - accumulate MAC statistics
781  *      @mac: the MAC handle
782  *
783  *      This function is called periodically to accumulate the current values
784  *      of the RMON counters into the port statistics.  Since the packet
785  *      counters are only 32 bits they can overflow in ~286 secs at 10G, so the
786  *      function should be called more frequently than that.  The byte counters
787  *      are 45-bit wide, they would overflow in ~7.8 hours.
788  */
789 const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
790 {
791 #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
792 #define RMON_UPDATE(mac, name, reg) \
793         (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
794 #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
795         (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
796                              ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
797
798         u32 v, lo;
799
800         if (mac->multiport)
801                 return t3_vsc7323_update_stats(mac);
802
803         RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
804         RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
805         RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
806         RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
807         RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
808         RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
809         RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
810         RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
811         RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
812
813         RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
814
815         v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
816         if (mac->adapter->params.rev == T3_REV_B2)
817                 v &= 0x7fffffff;
818         mac->stats.rx_too_long += v;
819
820         RMON_UPDATE(mac, rx_frames_64,        RX_64B_FRAMES);
821         RMON_UPDATE(mac, rx_frames_65_127,    RX_65_127B_FRAMES);
822         RMON_UPDATE(mac, rx_frames_128_255,   RX_128_255B_FRAMES);
823         RMON_UPDATE(mac, rx_frames_256_511,   RX_256_511B_FRAMES);
824         RMON_UPDATE(mac, rx_frames_512_1023,  RX_512_1023B_FRAMES);
825         RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
826         RMON_UPDATE(mac, rx_frames_1519_max,  RX_1519_MAXB_FRAMES);
827
828         RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
829         RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
830         RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
831         RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
832         RMON_UPDATE(mac, tx_pause, TX_PAUSE);
833         /* This counts error frames in general (bad FCS, underrun, etc). */
834         RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
835
836         RMON_UPDATE(mac, tx_frames_64,        TX_64B_FRAMES);
837         RMON_UPDATE(mac, tx_frames_65_127,    TX_65_127B_FRAMES);
838         RMON_UPDATE(mac, tx_frames_128_255,   TX_128_255B_FRAMES);
839         RMON_UPDATE(mac, tx_frames_256_511,   TX_256_511B_FRAMES);
840         RMON_UPDATE(mac, tx_frames_512_1023,  TX_512_1023B_FRAMES);
841         RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
842         RMON_UPDATE(mac, tx_frames_1519_max,  TX_1519_MAXB_FRAMES);
843
844         /* The next stat isn't clear-on-read. */
845         t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
846         v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
847         lo = (u32)mac->stats.rx_cong_drops;
848         mac->stats.rx_cong_drops += (u64)(v - lo);
849
850         return &mac->stats;
851 }