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
bnx_link_check(lm_device_t * const lmdevice)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
bnx_link_check2(lm_device_t * const lmdevice)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
bnx_timer(void * arg)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
bnx_timer_start(um_device_t * const umdevice)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
bnx_timer_stop(um_device_t * const umdevice)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
bnx_link_timer_restart(um_device_t * const umdevice)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
bnx_timer_init(um_device_t * const umdevice)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
bnx_timer_fini(um_device_t * const umdevice)250 bnx_timer_fini(um_device_t *const umdevice)
251 {
252 mutex_destroy(&umdevice->tmr_mutex);
253 }
254