xref: /illumos-gate/usr/src/uts/common/io/bnx/bnxtmr.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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 
35 typedef struct _bnx_fw_t {
36 	u32_t shmemaddr;
37 	u32_t length;
38 	u32_t nvramaddr;
39 } bnx_fw_t;
40 
41 static void
42 bnx_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 
72 static void
73 bnx_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  */
109 static void
110 bnx_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 
172 done:
173 	mutex_exit(&umdevice->tmr_mutex);
174 }
175 
176 void
177 bnx_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 
207 void
208 bnx_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  */
230 void
231 bnx_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 
240 void
241 bnx_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 
249 void
250 bnx_timer_fini(um_device_t *const umdevice)
251 {
252 	mutex_destroy(&umdevice->tmr_mutex);
253 }
254