diff options
Diffstat (limited to 'usr/src/uts/common/io/bnx/bnxtmr.c')
-rw-r--r-- | usr/src/uts/common/io/bnx/bnxtmr.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/usr/src/uts/common/io/bnx/bnxtmr.c b/usr/src/uts/common/io/bnx/bnxtmr.c new file mode 100644 index 0000000000..1a5d142d84 --- /dev/null +++ b/usr/src/uts/common/io/bnx/bnxtmr.c @@ -0,0 +1,253 @@ +/* + * Copyright 2014-2017 Cavium, Inc. + * The contents of this file are subject to the terms of the Common Development + * and Distribution License, v.1, (the "License"). + * + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the License at available + * at http://opensource.org/licenses/CDDL-1.0 + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Joyent, Inc. + */ + +#include "bnxtmr.h" +#include "bnxrcv.h" +#include "bnxgld.h" + + +/* 1.5 seconds */ +#define BNX_LINK_CHECK_INTERVAL 10 + +/* Approximately every second. */ +#define BNX_LINK_CHECK_INTERVAL2 7 + +/* 500 msecs */ +#define BNX_TIMER_INTERVAL 500000 + + +typedef struct _bnx_fw_t { + u32_t shmemaddr; + u32_t length; + u32_t nvramaddr; +} bnx_fw_t; + +static void +bnx_link_check(lm_device_t *const lmdevice) +{ + if (lmdevice->vars.link_status == LM_STATUS_LINK_ACTIVE) { + /* + * If we have link and we are in the fallback (1gb forced), + * mode, we need to see if our link partner is sending us + * configs. If this is the case, we'll switch back to autoneg. + */ + if (lmdevice->vars.serdes_fallback_status) { + u32_t intr_exp_status; + + (void) lm_mwrite(lmdevice, lmdevice->params.phy_addr, + 0x17, 0x0f01); + (void) lm_mread(lmdevice, lmdevice->params.phy_addr, + 0x15, &intr_exp_status); + (void) lm_mread(lmdevice, lmdevice->params.phy_addr, + 0x15, &intr_exp_status); + + if (intr_exp_status & 0x20) { + (void) lm_mwrite(lmdevice, + lmdevice->params.phy_addr, + PHY_CTRL_REG, PHY_CTRL_AUTO_NEG_ENABLE | + PHY_CTRL_RESTART_AUTO_NEG); + } + } + } else { + lm_service_phy_int(lmdevice, TRUE); + } +} + +static void +bnx_link_check2(lm_device_t *const lmdevice) +{ + if (lmdevice->vars.link_status == LM_STATUS_LINK_ACTIVE) { + u32_t val; + u32_t phy_addr; + + phy_addr = lmdevice->params.phy_addr; + + /* Is the link really up? */ + (void) lm_mwrite(lmdevice, phy_addr, 0x1c, 0x6800); + (void) lm_mread(lmdevice, phy_addr, 0x1c, &val); + (void) lm_mread(lmdevice, phy_addr, 0x1c, &val); + + if (val & 2) { + /* Nope. Force the link down. */ + (void) lm_mwrite(lmdevice, phy_addr, 0x17, 0x0f03); + (void) lm_mread(lmdevice, phy_addr, 0x15, &val); + (void) lm_mwrite(lmdevice, phy_addr, 0x15, + val & 0xff0f); + + lmdevice->vars.bcm5706s_tx_drv_cur = (u16_t)val; + } + } +} + + + +/* + * Name: bnx_timer + * + * Input: ptr to device structure + * + * Return: None + * + * Description: bnx_timer is the periodic timer callback funtion. + */ +static void +bnx_timer(void *arg) +{ + lm_device_t *lmdevice; + um_device_t *umdevice; + + umdevice = (um_device_t *)arg; + lmdevice = &(umdevice->lm_dev); + + mutex_enter(&umdevice->tmr_mutex); + + if (umdevice->timer_enabled != B_TRUE) { + goto done; + } + + um_send_driver_pulse(umdevice); + + /* + * Take this opportunity to replenish any unused Rx Bds. Don't + * wait around for the rcv_mutex though. We share the + * responsibility of replenishing the rx buffers with the ISR. + */ + if (mutex_tryenter(&umdevice->os_param.rcv_mutex)) { + /* This function does an implicit *_fill(). */ + bnx_rxpkts_post(umdevice); + + mutex_exit(&umdevice->os_param.rcv_mutex); + } + + if (umdevice->timer_link_check_interval2) { + /* + * If enabled, check to see if the serdes + * PHY can fallback to a forced mode. + */ + if (umdevice->timer_link_check_interval) { + if (umdevice->timer_link_check_counter) { + if (umdevice->timer_link_check_counter == 1) { + mutex_enter( + &umdevice->os_param.phy_mutex); + bnx_link_check(lmdevice); + mutex_exit( + &umdevice->os_param.phy_mutex); + } + umdevice->timer_link_check_counter--; + } + } + + umdevice->timer_link_check_counter2--; + if (umdevice->timer_link_check_counter2 == 0) { + mutex_enter(&umdevice->os_param.phy_mutex); + bnx_link_check2(lmdevice); + mutex_exit(&umdevice->os_param.phy_mutex); + + umdevice->timer_link_check_counter2 = + umdevice->timer_link_check_interval2; + } + } + + FLUSHPOSTEDWRITES(lmdevice); + + umdevice->tmrtid = timeout(bnx_timer, (void *)umdevice, + drv_usectohz(BNX_TIMER_INTERVAL)); + +done: + mutex_exit(&umdevice->tmr_mutex); +} + +void +bnx_timer_start(um_device_t *const umdevice) +{ + lm_device_t *lmdevice; + + lmdevice = &(umdevice->lm_dev); + + umdevice->timer_enabled = B_TRUE; + + if (CHIP_NUM(lmdevice) == CHIP_NUM_5706 && + umdevice->dev_var.isfiber == B_TRUE) { + if (lmdevice->vars.serdes_fallback_select != + SERDES_FALLBACK_NONE) { + umdevice->timer_link_check_interval = + BNX_LINK_CHECK_INTERVAL; + } else { + umdevice->timer_link_check_interval = 0; + } + + umdevice->timer_link_check_interval2 = BNX_LINK_CHECK_INTERVAL2; + umdevice->timer_link_check_counter2 = + umdevice->timer_link_check_interval2; + } else { + umdevice->timer_link_check_interval2 = 0; + } + + umdevice->tmrtid = timeout(bnx_timer, (void *)umdevice, + drv_usectohz(BNX_TIMER_INTERVAL)); +} + + +void +bnx_timer_stop(um_device_t *const umdevice) +{ + mutex_enter(&umdevice->tmr_mutex); + umdevice->timer_enabled = B_FALSE; + mutex_exit(&umdevice->tmr_mutex); + + (void) untimeout(umdevice->tmrtid); + umdevice->tmrtid = 0; +} + + + +/* + * Name: bnx_link_timer_restart + * + * Input: ptr to device structure + * + * Return: None + * + * Description: This function restarts the link poll timer + * + */ +void +bnx_link_timer_restart(um_device_t *const umdevice) +{ + /* FIXME -- Make timer_link_check_counter atomic */ + umdevice->timer_link_check_counter = + umdevice->timer_link_check_interval; +} + + + +void +bnx_timer_init(um_device_t *const umdevice) +{ + mutex_init(&umdevice->tmr_mutex, NULL, MUTEX_DRIVER, + DDI_INTR_PRI(umdevice->intrPriority)); +} + + + +void +bnx_timer_fini(um_device_t *const umdevice) +{ + mutex_destroy(&umdevice->tmr_mutex); +} |