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