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 */
50static 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
57static 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
73static int
74sfxge_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
111done:
112	return (0);
113
114fail2:
115	DTRACE_PROBE(fail2);
116fail1:
117	DTRACE_PROBE1(fail1, int, rc);
118
119	return (rc);
120}
121
122int
123sfxge_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
173fail2:
174	DTRACE_PROBE(fail2)
175	kmem_free(spp->sp_statbuf, sizeof (uint32_t) * EFX_PHY_NSTATS);
176
177fail1:
178	DTRACE_PROBE1(fail1, int, rc);
179
180	return (rc);
181}
182
183void
184sfxge_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
197int
198sfxge_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
220fail1:
221	DTRACE_PROBE1(fail1, int, rc);
222	SFXGE_OBJ_CHECK(spp, sfxge_phy_t);
223
224	return (rc);
225}
226
227uint8_t
228sfxge_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
240done:
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 */
251int
252sfxge_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
300fail2:
301	DTRACE_PROBE(fail2);
302
303fail1:
304	DTRACE_PROBE1(fail1, int, rc);
305
306	return (rc);
307}
308
309uint8_t
310sfxge_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
327done:
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
337int
338sfxge_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);
364done:
365	mutex_exit(&(smp->sm_lock));
366
367	return (rc);
368}
369
370
371void
372sfxge_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