1 /*
2 * Copyright (c) 2008-2015 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 <sys/types.h>
32 #include <sys/sysmacros.h>
33 #include <sys/ddi.h>
34 #include <sys/sunddi.h>
35 #include <sys/cyclic.h>
36
37 #include "sfxge.h"
38 #include "efx.h"
39
40 /*
41 * All efx_phy_*() must be after efx_port_init()
42 *
43 * LOCKING STRATEGY: Aquire sm_lock and test sm_state==SFXGE_MAC_STARTED
44 * to serialise against sfxge_restart()
45 *
46 * Note that there is no seperate PHY lock
47 * Everything is driven from MAC code and the MAC lock is used
48 */
49
50 /* PHY DMA attributes */
51 static ddi_device_acc_attr_t sfxge_phy_devacc = {
52
53 DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
54 DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
55 DDI_STRICTORDER_ACC /* devacc_attr_dataorder */
56 };
57
58 static ddi_dma_attr_t sfxge_phy_dma_attr = {
59 DMA_ATTR_V0, /* dma_attr_version */
60 0, /* dma_attr_addr_lo */
61 0xffffffffffffffffull, /* dma_attr_addr_hi */
62 0xffffffffffffffffull, /* dma_attr_count_max */
63 0x1000, /* dma_attr_align */
64 0xffffffff, /* dma_attr_burstsizes */
65 1, /* dma_attr_minxfer */
66 0xffffffffffffffffull, /* dma_attr_maxxfer */
67 0xffffffffffffffffull, /* dma_attr_seg */
68 1, /* dma_attr_sgllen */
69 1, /* dma_attr_granular */
70 0 /* dma_attr_flags */
71 };
72
73
74 static int
75 sfxge_phy_kstat_update(kstat_t *ksp, int rw)
76 {
77 sfxge_t *sp = ksp->ks_private;
78 sfxge_mac_t *smp = &(sp->s_mac);
79 sfxge_phy_t *spp = &(smp->sm_phy);
80 efx_nic_t *enp = sp->s_enp;
81 kstat_named_t *knp;
82 const efx_nic_cfg_t *encp;
83 int rc, sn;
84
85 if (rw != KSTAT_READ) {
86 rc = EACCES;
87 goto fail1;
88 }
89
90 ASSERT(mutex_owned(&(smp->sm_lock)));
91
92 if (smp->sm_state != SFXGE_MAC_STARTED)
93 goto done;
94
95 /* Synchronize the DMA memory for reading */
96 (void) ddi_dma_sync(spp->sp_mem.esm_dma_handle,
97 0, EFX_PHY_STATS_SIZE, DDI_DMA_SYNC_FORKERNEL);
98
99 if ((rc = efx_phy_stats_update(enp, &spp->sp_mem, spp->sp_statbuf))
100 != 0)
101 goto fail2;
102
103 knp = spp->sp_stat;
104 for (sn = 0; sn < EFX_PHY_NSTATS; sn++) {
105 knp->value.ui64 = spp->sp_statbuf[sn];
106 knp++;
107 }
108
109 encp = efx_nic_cfg_get(enp);
110 knp->value.ui64 = encp->enc_port;
111
112 done:
113 return (0);
114
115 fail2:
116 DTRACE_PROBE(fail2);
117 fail1:
118 DTRACE_PROBE1(fail1, int, rc);
119
120 return (rc);
121 }
122
123 int
124 sfxge_phy_kstat_init(sfxge_t *sp)
125 {
126 dev_info_t *dip = sp->s_dip;
127 sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
128 efx_nic_t *enp = sp->s_enp;
129 kstat_t *ksp;
130 kstat_named_t *knp;
131 const efx_nic_cfg_t *encp;
132 unsigned int id;
133 char name[MAXNAMELEN];
134 int rc;
135
136 if ((spp->sp_statbuf = kmem_zalloc(sizeof (uint32_t) * EFX_PHY_NSTATS,
137 KM_NOSLEEP)) == NULL) {
138 rc = ENOMEM;
139 goto fail1;
140 }
141
142 encp = efx_nic_cfg_get(enp);
143
144 (void) snprintf(name, MAXNAMELEN - 1, "%s_%s", ddi_driver_name(dip),
145 encp->enc_phy_name);
146
147 /* Create the set */
148 if ((ksp = kstat_create((char *)ddi_driver_name(dip),
149 ddi_get_instance(dip), name, "phy", KSTAT_TYPE_NAMED,
150 EFX_PHY_NSTATS + 1, 0)) == NULL) {
151 rc = ENOMEM;
152 goto fail2;
153 }
154
155 spp->sp_ksp = ksp;
156
157 ksp->ks_update = sfxge_phy_kstat_update;
158 ksp->ks_private = sp;
159 ksp->ks_lock = &(sp->s_mac.sm_lock);
160
161 /* Initialise the named stats */
162 spp->sp_stat = knp = ksp->ks_data;
163 for (id = 0; id < EFX_PHY_NSTATS; id++) {
164 kstat_named_init(knp, (char *)efx_phy_stat_name(enp, id),
165 KSTAT_DATA_UINT64);
166 knp++;
167 }
168
169 kstat_named_init(knp, "port", KSTAT_DATA_UINT64);
170 kstat_install(ksp);
171
172 return (0);
173
174 fail2:
175 DTRACE_PROBE(fail2)
176 kmem_free(spp->sp_statbuf, sizeof (uint32_t) * EFX_PHY_NSTATS);
177
178 fail1:
179 DTRACE_PROBE1(fail1, int, rc);
180
181 return (rc);
182 }
183
184 void
185 sfxge_phy_kstat_fini(sfxge_t *sp)
186 {
187 sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
188
189 /* Destroy the set */
190 kstat_delete(spp->sp_ksp);
191 spp->sp_ksp = NULL;
192 spp->sp_stat = NULL;
193
194 kmem_free(spp->sp_statbuf, sizeof (uint32_t) * EFX_PHY_NSTATS);
195 }
196
197
198 int
199 sfxge_phy_init(sfxge_t *sp)
200 {
201 sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
202 efsys_mem_t *esmp = &(spp->sp_mem);
203 sfxge_dma_buffer_attr_t dma_attr;
204 int rc;
205
206 dma_attr.sdba_dip = sp->s_dip;
207 dma_attr.sdba_dattrp = &sfxge_phy_dma_attr;
208 dma_attr.sdba_callback = DDI_DMA_SLEEP;
209 dma_attr.sdba_length = EFX_PHY_STATS_SIZE;
210 dma_attr.sdba_memflags = DDI_DMA_CONSISTENT;
211 dma_attr.sdba_devaccp = &sfxge_phy_devacc;
212 dma_attr.sdba_bindflags = DDI_DMA_READ | DDI_DMA_CONSISTENT;
213 dma_attr.sdba_maxcookies = 1;
214 dma_attr.sdba_zeroinit = B_TRUE;
215
216 if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
217 goto fail1;
218
219 return (0);
220
221 fail1:
222 DTRACE_PROBE1(fail1, int, rc);
223 SFXGE_OBJ_CHECK(spp, sfxge_phy_t);
224
225 return (rc);
226 }
227
228 uint8_t
229 sfxge_phy_lp_cap_test(sfxge_t *sp, uint32_t field)
230 {
231 sfxge_mac_t *smp = &(sp->s_mac);
232 uint32_t cap = 0;
233
234 mutex_enter(&(smp->sm_lock));
235
236 if (smp->sm_state != SFXGE_MAC_STARTED)
237 goto done;
238
239 efx_phy_lp_cap_get(sp->s_enp, &cap);
240
241 done:
242 mutex_exit(&(smp->sm_lock));
243
244 return (cap & (1 << field));
245 }
246
247 /*
248 * Set up the advertised capabilities that may have been asked for
249 * when the mac was not in the state SFXGE_MAC_STARTED.
250 * Must be called after efx_port_init().
251 */
252 int
253 sfxge_phy_cap_apply(sfxge_t *sp, boolean_t use_default)
254 {
255 sfxge_mac_t *smp = &(sp->s_mac);
256 efx_nic_t *enp;
257 uint32_t adv_cap;
258 int rc;
259 int err;
260
261 ASSERT(mutex_owned(&(smp->sm_lock)));
262
263 enp = sp->s_enp;
264
265 if (use_default)
266 efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &adv_cap);
267 else
268 efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &adv_cap);
269
270 adv_cap |= smp->sm_phy_cap_to_set;
271 smp->sm_phy_cap_to_set = 0;
272 adv_cap &= ~(smp->sm_phy_cap_to_unset);
273 smp->sm_phy_cap_to_unset = 0;
274 if ((err = efx_phy_adv_cap_set(enp, adv_cap)) != 0) {
275 if (err == EINVAL) {
276 /*
277 * The configuation wasn't accepted, so set to
278 * defaults.
279 */
280 uint32_t requested = adv_cap;
281 uint32_t supported;
282 efx_phy_adv_cap_get(enp, EFX_PHY_CAP_PERM, &supported);
283 efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &adv_cap);
284 if ((rc = efx_phy_adv_cap_set(enp, adv_cap)) != 0)
285 goto fail1;
286 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
287 "Setting of advertised link capabilities failed. "
288 "Using default settings. "
289 "(Requested 0x%x Given 0x%x Supported 0x%x)",
290 requested,
291 adv_cap,
292 supported);
293 } else {
294 rc = err;
295 goto fail2;
296 }
297 }
298
299 return (0);
300
301 fail2:
302 DTRACE_PROBE(fail2);
303
304 fail1:
305 DTRACE_PROBE1(fail1, int, rc);
306
307 return (rc);
308 }
309
310 uint8_t
311 sfxge_phy_cap_test(sfxge_t *sp, uint32_t flag, uint32_t field,
312 boolean_t *mutablep)
313 {
314 sfxge_mac_t *smp = &(sp->s_mac);
315 efx_nic_t *enp;
316 uint32_t cap = 0;
317 uint32_t perm = 0;
318
319 mutex_enter(&(smp->sm_lock));
320 enp = sp->s_enp;
321
322 if (smp->sm_state != SFXGE_MAC_STARTED)
323 goto done;
324
325 efx_phy_adv_cap_get(enp, flag, &cap);
326 efx_phy_adv_cap_get(enp, EFX_PHY_CAP_PERM, &perm);
327
328 done:
329 mutex_exit(&(smp->sm_lock));
330
331 if (mutablep)
332 *mutablep = (perm & (1 << field)) ? B_TRUE : B_FALSE;
333
334 return ((cap & (1 << field)) ? 1 : 0);
335 }
336
337
338 int
339 sfxge_phy_cap_set(sfxge_t *sp, uint32_t field, int set)
340 {
341 sfxge_mac_t *smp = &(sp->s_mac);
342 efx_nic_t *enp = sp->s_enp;
343 uint32_t cap;
344 int rc = 0;
345
346 mutex_enter(&(smp->sm_lock));
347
348 if (smp->sm_state != SFXGE_MAC_STARTED) {
349 /* Store the request for when the mac is started */
350 if (set)
351 smp->sm_phy_cap_to_set |= (1 << field);
352 else
353 smp->sm_phy_cap_to_unset |= (1 << field);
354 goto done;
355 }
356
357 efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &cap);
358
359 if (set)
360 cap |= (1 << field);
361 else
362 cap &= ~(1 << field);
363
364 rc = efx_phy_adv_cap_set(enp, cap);
365 done:
366 mutex_exit(&(smp->sm_lock));
367
368 return (rc);
369 }
370
371
372 void
373 sfxge_phy_fini(sfxge_t *sp)
374 {
375 sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
376 efsys_mem_t *esmp = &(spp->sp_mem);
377
378 sfxge_dma_buffer_destroy(esmp);
379 }