net/sfc/base: import libefx base
[dpdk.git] / drivers / net / sfc / base / efx_phy.c
1 /*
2  * Copyright (c) 2007-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include "efx.h"
32 #include "efx_impl.h"
33
34
35         __checkReturn   efx_rc_t
36 efx_phy_probe(
37         __in            efx_nic_t *enp)
38 {
39         efx_port_t *epp = &(enp->en_port);
40         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
41         const efx_phy_ops_t *epop;
42         efx_rc_t rc;
43
44         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
45
46         epp->ep_port = encp->enc_port;
47         epp->ep_phy_type = encp->enc_phy_type;
48
49         /* Hook in operations structure */
50         switch (enp->en_family) {
51         default:
52                 rc = ENOTSUP;
53                 goto fail1;
54         }
55
56         epp->ep_epop = epop;
57
58         return (0);
59
60 fail1:
61         EFSYS_PROBE1(fail1, efx_rc_t, rc);
62
63         epp->ep_port = 0;
64         epp->ep_phy_type = 0;
65
66         return (rc);
67 }
68
69         __checkReturn   efx_rc_t
70 efx_phy_verify(
71         __in            efx_nic_t *enp)
72 {
73         efx_port_t *epp = &(enp->en_port);
74         const efx_phy_ops_t *epop = epp->ep_epop;
75
76         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
77         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
78
79         return (epop->epo_verify(enp));
80 }
81
82                         void
83 efx_phy_adv_cap_get(
84         __in            efx_nic_t *enp,
85         __in            uint32_t flag,
86         __out           uint32_t *maskp)
87 {
88         efx_port_t *epp = &(enp->en_port);
89
90         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
91         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
92
93         switch (flag) {
94         case EFX_PHY_CAP_CURRENT:
95                 *maskp = epp->ep_adv_cap_mask;
96                 break;
97         case EFX_PHY_CAP_DEFAULT:
98                 *maskp = epp->ep_default_adv_cap_mask;
99                 break;
100         case EFX_PHY_CAP_PERM:
101                 *maskp = epp->ep_phy_cap_mask;
102                 break;
103         default:
104                 EFSYS_ASSERT(B_FALSE);
105                 break;
106         }
107 }
108
109         __checkReturn   efx_rc_t
110 efx_phy_adv_cap_set(
111         __in            efx_nic_t *enp,
112         __in            uint32_t mask)
113 {
114         efx_port_t *epp = &(enp->en_port);
115         const efx_phy_ops_t *epop = epp->ep_epop;
116         uint32_t old_mask;
117         efx_rc_t rc;
118
119         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
120         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
121
122         if ((mask & ~epp->ep_phy_cap_mask) != 0) {
123                 rc = ENOTSUP;
124                 goto fail1;
125         }
126
127         if (epp->ep_adv_cap_mask == mask)
128                 goto done;
129
130         old_mask = epp->ep_adv_cap_mask;
131         epp->ep_adv_cap_mask = mask;
132
133         if ((rc = epop->epo_reconfigure(enp)) != 0)
134                 goto fail2;
135
136 done:
137         return (0);
138
139 fail2:
140         EFSYS_PROBE(fail2);
141
142         epp->ep_adv_cap_mask = old_mask;
143         /* Reconfigure for robustness */
144         if (epop->epo_reconfigure(enp) != 0) {
145                 /*
146                  * We may have an inconsistent view of our advertised speed
147                  * capabilities.
148                  */
149                 EFSYS_ASSERT(0);
150         }
151
152 fail1:
153         EFSYS_PROBE1(fail1, efx_rc_t, rc);
154
155         return (rc);
156 }
157
158         void
159 efx_phy_lp_cap_get(
160         __in            efx_nic_t *enp,
161         __out           uint32_t *maskp)
162 {
163         efx_port_t *epp = &(enp->en_port);
164
165         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
166         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
167
168         *maskp = epp->ep_lp_cap_mask;
169 }
170
171         __checkReturn   efx_rc_t
172 efx_phy_oui_get(
173         __in            efx_nic_t *enp,
174         __out           uint32_t *ouip)
175 {
176         efx_port_t *epp = &(enp->en_port);
177         const efx_phy_ops_t *epop = epp->ep_epop;
178
179         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
180         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
181
182         return (epop->epo_oui_get(enp, ouip));
183 }
184
185                         void
186 efx_phy_media_type_get(
187         __in            efx_nic_t *enp,
188         __out           efx_phy_media_type_t *typep)
189 {
190         efx_port_t *epp = &(enp->en_port);
191
192         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
193         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
194
195         if (epp->ep_module_type != EFX_PHY_MEDIA_INVALID)
196                 *typep = epp->ep_module_type;
197         else
198                 *typep = epp->ep_fixed_port_type;
199 }
200
201         __checkReturn   efx_rc_t
202 efx_phy_module_get_info(
203         __in                    efx_nic_t *enp,
204         __in                    uint8_t dev_addr,
205         __in                    uint8_t offset,
206         __in                    uint8_t len,
207         __out_bcount(len)       uint8_t *data)
208 {
209         efx_rc_t rc;
210
211         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
212         EFSYS_ASSERT(data != NULL);
213
214         if ((uint32_t)offset + len > 0xff) {
215                 rc = EINVAL;
216                 goto fail1;
217         }
218
219         if ((rc = efx_mcdi_phy_module_get_info(enp, dev_addr,
220             offset, len, data)) != 0)
221                 goto fail2;
222
223         return (0);
224
225 fail2:
226         EFSYS_PROBE(fail2);
227 fail1:
228         EFSYS_PROBE1(fail1, efx_rc_t, rc);
229
230         return (rc);
231 }
232
233
234                         void
235 efx_phy_unprobe(
236         __in    efx_nic_t *enp)
237 {
238         efx_port_t *epp = &(enp->en_port);
239
240         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
241
242         epp->ep_epop = NULL;
243
244         epp->ep_adv_cap_mask = 0;
245
246         epp->ep_port = 0;
247         epp->ep_phy_type = 0;
248 }