1/*
2 * Copyright 2014-2017 Cavium, Inc.
3 * The contents of this file are subject to the terms of the Common Development
4 * and Distribution License, v.1,  (the "License").
5 *
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the License at available
9 * at http://opensource.org/licenses/CDDL-1.0
10 *
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14
15/*
16 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
17 * Copyright (c) 2019, Joyent, Inc.
18 */
19
20#include "bnxtmr.h"
21#include "bnxrcv.h"
22#include "bnxgld.h"
23
24
25/* 1.5 seconds */
26#define	BNX_LINK_CHECK_INTERVAL 10
27
28/* Approximately every second. */
29#define	BNX_LINK_CHECK_INTERVAL2 7
30
31/* 500 msecs */
32#define	BNX_TIMER_INTERVAL	500000
33
34
35typedef struct _bnx_fw_t {
36	u32_t shmemaddr;
37	u32_t length;
38	u32_t nvramaddr;
39} bnx_fw_t;
40
41static void
42bnx_link_check(lm_device_t *const lmdevice)
43{
44	if (lmdevice->vars.link_status == LM_STATUS_LINK_ACTIVE) {
45		/*
46		 * If we have link and we are in the fallback (1gb forced),
47		 * mode, we need to see if our link partner is sending us
48		 * configs.  If this is the case, we'll switch back to autoneg.
49		 */
50		if (lmdevice->vars.serdes_fallback_status) {
51			u32_t intr_exp_status;
52
53			(void) lm_mwrite(lmdevice, lmdevice->params.phy_addr,
54			    0x17, 0x0f01);
55			(void) lm_mread(lmdevice, lmdevice->params.phy_addr,
56			    0x15, &intr_exp_status);
57			(void) lm_mread(lmdevice, lmdevice->params.phy_addr,
58			    0x15, &intr_exp_status);
59
60			if (intr_exp_status & 0x20) {
61				(void) lm_mwrite(lmdevice,
62				    lmdevice->params.phy_addr,
63				    PHY_CTRL_REG, PHY_CTRL_AUTO_NEG_ENABLE |
64				    PHY_CTRL_RESTART_AUTO_NEG);
65			}
66		}
67	} else {
68		lm_service_phy_int(lmdevice, TRUE);
69	}
70}
71
72static void
73bnx_link_check2(lm_device_t *const lmdevice)
74{
75	if (lmdevice->vars.link_status == LM_STATUS_LINK_ACTIVE) {
76		u32_t val;
77		u32_t phy_addr;
78
79		phy_addr = lmdevice->params.phy_addr;
80
81		/* Is the link really up? */
82		(void) lm_mwrite(lmdevice, phy_addr, 0x1c, 0x6800);
83		(void) lm_mread(lmdevice, phy_addr, 0x1c, &val);
84		(void) lm_mread(lmdevice, phy_addr, 0x1c, &val);
85
86		if (val & 2) {
87			/* Nope.  Force the link down. */
88			(void) lm_mwrite(lmdevice, phy_addr, 0x17, 0x0f03);
89			(void) lm_mread(lmdevice, phy_addr, 0x15, &val);
90			(void) lm_mwrite(lmdevice, phy_addr, 0x15,
91			    val & 0xff0f);
92
93			lmdevice->vars.bcm5706s_tx_drv_cur = (u16_t)val;
94		}
95	}
96}
97
98
99
100/*
101 * Name:    bnx_timer
102 *
103 * Input:   ptr to device structure
104 *
105 * Return:  None
106 *
107 * Description: bnx_timer is the periodic timer callback funtion.
108 */
109static void
110bnx_timer(void *arg)
111{
112	lm_device_t *lmdevice;
113	um_device_t *umdevice;
114
115	umdevice = (um_device_t *)arg;
116	lmdevice = &(umdevice->lm_dev);
117
118	mutex_enter(&umdevice->tmr_mutex);
119
120	if (umdevice->timer_enabled != B_TRUE) {
121		goto done;
122	}
123
124	um_send_driver_pulse(umdevice);
125
126	/*
127	 * Take this opportunity to replenish any unused Rx Bds.  Don't
128	 * wait around for the rcv_mutex though.  We share the
129	 * responsibility of replenishing the rx buffers with the ISR.
130	 */
131	if (mutex_tryenter(&umdevice->os_param.rcv_mutex)) {
132		/* This function does an implicit *_fill(). */
133		bnx_rxpkts_post(umdevice);
134
135		mutex_exit(&umdevice->os_param.rcv_mutex);
136	}
137
138	if (umdevice->timer_link_check_interval2) {
139		/*
140		 * If enabled, check to see if the serdes
141		 * PHY can fallback to a forced mode.
142		 */
143		if (umdevice->timer_link_check_interval) {
144			if (umdevice->timer_link_check_counter) {
145				if (umdevice->timer_link_check_counter == 1) {
146					mutex_enter(
147					    &umdevice->os_param.phy_mutex);
148					bnx_link_check(lmdevice);
149					mutex_exit(
150					    &umdevice->os_param.phy_mutex);
151				}
152				umdevice->timer_link_check_counter--;
153			}
154		}
155
156		umdevice->timer_link_check_counter2--;
157		if (umdevice->timer_link_check_counter2 == 0) {
158			mutex_enter(&umdevice->os_param.phy_mutex);
159			bnx_link_check2(lmdevice);
160			mutex_exit(&umdevice->os_param.phy_mutex);
161
162			umdevice->timer_link_check_counter2 =
163			    umdevice->timer_link_check_interval2;
164		}
165	}
166
167	FLUSHPOSTEDWRITES(lmdevice);
168
169	umdevice->tmrtid = timeout(bnx_timer, (void *)umdevice,
170	    drv_usectohz(BNX_TIMER_INTERVAL));
171
172done:
173	mutex_exit(&umdevice->tmr_mutex);
174}
175
176void
177bnx_timer_start(um_device_t *const umdevice)
178{
179	lm_device_t *lmdevice;
180
181	lmdevice = &(umdevice->lm_dev);
182
183	umdevice->timer_enabled = B_TRUE;
184
185	if (CHIP_NUM(lmdevice) == CHIP_NUM_5706 &&
186	    umdevice->dev_var.isfiber == B_TRUE) {
187		if (lmdevice->vars.serdes_fallback_select !=
188		    SERDES_FALLBACK_NONE) {
189			umdevice->timer_link_check_interval =
190			    BNX_LINK_CHECK_INTERVAL;
191		} else {
192			umdevice->timer_link_check_interval = 0;
193		}
194
195		umdevice->timer_link_check_interval2 = BNX_LINK_CHECK_INTERVAL2;
196		umdevice->timer_link_check_counter2 =
197		    umdevice->timer_link_check_interval2;
198	} else {
199		umdevice->timer_link_check_interval2 = 0;
200	}
201
202	umdevice->tmrtid = timeout(bnx_timer, (void *)umdevice,
203	    drv_usectohz(BNX_TIMER_INTERVAL));
204}
205
206
207void
208bnx_timer_stop(um_device_t *const umdevice)
209{
210	mutex_enter(&umdevice->tmr_mutex);
211	umdevice->timer_enabled = B_FALSE;
212	mutex_exit(&umdevice->tmr_mutex);
213
214	(void) untimeout(umdevice->tmrtid);
215	umdevice->tmrtid = 0;
216}
217
218
219
220/*
221 * Name:	bnx_link_timer_restart
222 *
223 * Input:	ptr to device structure
224 *
225 * Return:	None
226 *
227 * Description:	This function restarts the link poll timer
228 *
229 */
230void
231bnx_link_timer_restart(um_device_t *const umdevice)
232{
233	/* FIXME -- Make timer_link_check_counter atomic */
234	umdevice->timer_link_check_counter =
235	    umdevice->timer_link_check_interval;
236}
237
238
239
240void
241bnx_timer_init(um_device_t *const umdevice)
242{
243	mutex_init(&umdevice->tmr_mutex, NULL, MUTEX_DRIVER,
244	    DDI_INTR_PRI(umdevice->intrPriority));
245}
246
247
248
249void
250bnx_timer_fini(um_device_t *const umdevice)
251{
252	mutex_destroy(&umdevice->tmr_mutex);
253}
254