]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cxgb/common/cxgb_tn1010.c
MFV r353619: 9691 fat zap should prefetch when iterating
[FreeBSD/FreeBSD.git] / sys / dev / cxgb / common / cxgb_tn1010.c
1 /**************************************************************************
2 SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3
4 Copyright (c) 2008, 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 /* TN1010 PHY specific registers. */
40 enum {
41         TN1010_VEND1_STAT = 1,
42 };
43
44 /* IEEE auto-negotiation 10GBASE-T registers */
45 enum {
46         ANEG_ADVER    = 16,
47         ANEG_LPA      = 19,
48         ANEG_10G_CTRL = 32,
49         ANEG_10G_STAT = 33
50 };
51
52 #define ADVERTISE_ENPAGE      (1 << 12)
53 #define ADVERTISE_10000FULL   (1 << 12)
54 #define ADVERTISE_LOOP_TIMING (1 << 0)
55
56 /* vendor specific status register fields */
57 #define F_XS_LANE_ALIGN_STAT (1 << 0)
58 #define F_PCS_BLK_LOCK       (1 << 1)
59 #define F_PMD_SIGNAL_OK      (1 << 2)
60 #define F_LINK_STAT          (1 << 3)
61 #define F_ANEG_SPEED_1G      (1 << 4)
62 #define F_ANEG_MASTER        (1 << 5)
63
64 #define S_ANEG_STAT    6
65 #define M_ANEG_STAT    0x3
66 #define G_ANEG_STAT(x) (((x) >> S_ANEG_STAT) & M_ANEG_STAT)
67
68 enum {                        /* autonegotiation status */
69         ANEG_IN_PROGR = 0,
70         ANEG_COMPLETE = 1,
71         ANEG_FAILED   = 3
72 };
73
74 /*
75  * Reset the PHY.  May take up to 500ms to complete.
76  */
77 static int tn1010_reset(struct cphy *phy, int wait)
78 {
79         int err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
80         msleep(500);
81         return err;
82 }
83
84 static int tn1010_power_down(struct cphy *phy, int enable)
85 {
86         return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
87                                    BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
88 }
89
90 static int tn1010_autoneg_enable(struct cphy *phy)
91 {
92         int err;
93
94         err = tn1010_power_down(phy, 0);
95         if (!err)
96                 err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR, 0,
97                                           BMCR_ANENABLE | BMCR_ANRESTART);
98         return err;
99 }
100
101 static int tn1010_autoneg_restart(struct cphy *phy)
102 {
103         int err;
104
105         err = tn1010_power_down(phy, 0);
106         if (!err)
107                 err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR, 0,
108                                           BMCR_ANRESTART);
109         return err;
110 }
111
112 static int tn1010_advertise(struct cphy *phy, unsigned int advert)
113 {
114         int err, val;
115
116         if (!(advert & ADVERTISED_1000baseT_Full))
117                 return -EINVAL;               /* PHY can't disable 1000BASE-T */
118
119         val = ADVERTISE_CSMA | ADVERTISE_ENPAGE | ADVERTISE_NPAGE;
120         if (advert & ADVERTISED_Pause)
121                 val |= ADVERTISE_PAUSE_CAP;
122         if (advert & ADVERTISED_Asym_Pause)
123                 val |= ADVERTISE_PAUSE_ASYM;
124         err = mdio_write(phy, MDIO_DEV_ANEG, ANEG_ADVER, val);
125         if (err)
126                 return err;
127
128         val = (advert & ADVERTISED_10000baseT_Full) ? ADVERTISE_10000FULL : 0;
129         return mdio_write(phy, MDIO_DEV_ANEG, ANEG_10G_CTRL, val |
130                           ADVERTISE_LOOP_TIMING);
131 }
132
133 static int tn1010_get_link_status(struct cphy *phy, int *link_state,
134                                   int *speed, int *duplex, int *fc)
135 {
136         unsigned int status, lpa, adv;
137         int err, sp = -1, pause = 0;
138
139         err = mdio_read(phy, MDIO_DEV_VEND1, TN1010_VEND1_STAT, &status);
140         if (err)
141                 return err;
142
143         if (link_state)
144                 *link_state = status & F_LINK_STAT ? PHY_LINK_UP :
145                     PHY_LINK_DOWN;
146
147         if (G_ANEG_STAT(status) == ANEG_COMPLETE) {
148                 sp = (status & F_ANEG_SPEED_1G) ? SPEED_1000 : SPEED_10000;
149
150                 if (fc) {
151                         err = mdio_read(phy, MDIO_DEV_ANEG, ANEG_LPA, &lpa);
152                         if (!err)
153                                 err = mdio_read(phy, MDIO_DEV_ANEG, ANEG_ADVER,
154                                                 &adv);
155                         if (err)
156                                 return err;
157
158                         if (lpa & adv & ADVERTISE_PAUSE_CAP)
159                                 pause = PAUSE_RX | PAUSE_TX;
160                         else if ((lpa & ADVERTISE_PAUSE_CAP) &&
161                                  (lpa & ADVERTISE_PAUSE_ASYM) &&
162                                  (adv & ADVERTISE_PAUSE_ASYM))
163                                 pause = PAUSE_TX;
164                         else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
165                                  (adv & ADVERTISE_PAUSE_CAP))
166                                 pause = PAUSE_RX;
167                 }
168         }
169         if (speed)
170                 *speed = sp;
171         if (duplex)
172                 *duplex = DUPLEX_FULL;
173         if (fc)
174                 *fc = pause;
175         return 0;
176 }
177
178 static int tn1010_set_speed_duplex(struct cphy *phy, int speed, int duplex)
179 {
180         return -EINVAL;    /* require autoneg */
181 }
182
183 #ifdef C99_NOT_SUPPORTED
184 static struct cphy_ops tn1010_ops = {
185         tn1010_reset,
186         t3_phy_lasi_intr_enable,
187         t3_phy_lasi_intr_disable,
188         t3_phy_lasi_intr_clear,
189         t3_phy_lasi_intr_handler,
190         tn1010_autoneg_enable,
191         tn1010_autoneg_restart,
192         tn1010_advertise,
193         NULL,
194         tn1010_set_speed_duplex,
195         tn1010_get_link_status,
196         tn1010_power_down,
197 };
198 #else
199 static struct cphy_ops tn1010_ops = {
200         .reset             = tn1010_reset,
201         .intr_enable       = t3_phy_lasi_intr_enable,
202         .intr_disable      = t3_phy_lasi_intr_disable,
203         .intr_clear        = t3_phy_lasi_intr_clear,
204         .intr_handler      = t3_phy_lasi_intr_handler,
205         .autoneg_enable    = tn1010_autoneg_enable,
206         .autoneg_restart   = tn1010_autoneg_restart,
207         .advertise         = tn1010_advertise,
208         .set_speed_duplex  = tn1010_set_speed_duplex,
209         .get_link_status   = tn1010_get_link_status,
210         .power_down        = tn1010_power_down,
211 };
212 #endif
213
214 int t3_tn1010_phy_prep(pinfo_t *pinfo, int phy_addr,
215                        const struct mdio_ops *mdio_ops)
216 {
217         cphy_init(&pinfo->phy, pinfo->adapter, pinfo, phy_addr, &tn1010_ops, mdio_ops,
218                   SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
219                   SUPPORTED_Autoneg | SUPPORTED_AUI | SUPPORTED_TP,
220                   "1000/10GBASE-T");
221         msleep(500);    /* PHY needs up to 500ms to start responding to MDIO */
222         return 0;
223 }