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