1315333Serj/****************************************************************************** 2315333Serj 3315333Serj Copyright (c) 2001-2017, Intel Corporation 4315333Serj All rights reserved. 5315333Serj 6315333Serj Redistribution and use in source and binary forms, with or without 7315333Serj modification, are permitted provided that the following conditions are met: 8315333Serj 9315333Serj 1. Redistributions of source code must retain the above copyright notice, 10315333Serj this list of conditions and the following disclaimer. 11315333Serj 12315333Serj 2. Redistributions in binary form must reproduce the above copyright 13315333Serj notice, this list of conditions and the following disclaimer in the 14315333Serj documentation and/or other materials provided with the distribution. 15315333Serj 16315333Serj 3. Neither the name of the Intel Corporation nor the names of its 17315333Serj contributors may be used to endorse or promote products derived from 18315333Serj this software without specific prior written permission. 19315333Serj 20315333Serj THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21315333Serj AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22315333Serj IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23315333Serj ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24315333Serj LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25315333Serj CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26315333Serj SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27315333Serj INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28315333Serj CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29315333Serj ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30315333Serj POSSIBILITY OF SUCH DAMAGE. 31315333Serj 32315333Serj******************************************************************************/ 33315333Serj/*$FreeBSD: stable/10/sys/dev/ixgbe/if_bypass.c 315333 2017-03-15 21:20:17Z erj $*/ 34315333Serj 35315333Serj 36315333Serj#include "ixgbe.h" 37315333Serj 38315333Serj/************************************************************************ 39315333Serj * ixgbe_bypass_mutex_enter 40315333Serj * 41315333Serj * Mutex support for the bypass feature. Using a dual lock 42315333Serj * to facilitate a privileged access to the watchdog update 43315333Serj * over other threads. 44315333Serj ************************************************************************/ 45315333Serjstatic void 46315333Serjixgbe_bypass_mutex_enter(struct adapter *adapter) 47315333Serj{ 48315333Serj while (atomic_cmpset_int(&adapter->bypass.low, 0, 1) == 0) 49315333Serj usec_delay(3000); 50315333Serj while (atomic_cmpset_int(&adapter->bypass.high, 0, 1) == 0) 51315333Serj usec_delay(3000); 52315333Serj return; 53315333Serj} /* ixgbe_bypass_mutex_enter */ 54315333Serj 55315333Serj/************************************************************************ 56315333Serj * ixgbe_bypass_mutex_clear 57315333Serj ************************************************************************/ 58315333Serjstatic void 59315333Serjixgbe_bypass_mutex_clear(struct adapter *adapter) 60315333Serj{ 61315333Serj while (atomic_cmpset_int(&adapter->bypass.high, 1, 0) == 0) 62315333Serj usec_delay(6000); 63315333Serj while (atomic_cmpset_int(&adapter->bypass.low, 1, 0) == 0) 64315333Serj usec_delay(6000); 65315333Serj return; 66315333Serj} /* ixgbe_bypass_mutex_clear */ 67315333Serj 68315333Serj/************************************************************************ 69315333Serj * ixgbe_bypass_wd_mutex_enter 70315333Serj * 71315333Serj * Watchdog entry is allowed to simply grab the high priority 72315333Serj ************************************************************************/ 73315333Serjstatic void 74315333Serjixgbe_bypass_wd_mutex_enter(struct adapter *adapter) 75315333Serj{ 76315333Serj while (atomic_cmpset_int(&adapter->bypass.high, 0, 1) == 0) 77315333Serj usec_delay(3000); 78315333Serj return; 79315333Serj} /* ixgbe_bypass_wd_mutex_enter */ 80315333Serj 81315333Serj/************************************************************************ 82315333Serj * ixgbe_bypass_wd_mutex_clear 83315333Serj ************************************************************************/ 84315333Serjstatic void 85315333Serjixgbe_bypass_wd_mutex_clear(struct adapter *adapter) 86315333Serj{ 87315333Serj while (atomic_cmpset_int(&adapter->bypass.high, 1, 0) == 0) 88315333Serj usec_delay(6000); 89315333Serj return; 90315333Serj} /* ixgbe_bypass_wd_mutex_clear */ 91315333Serj 92315333Serj/************************************************************************ 93315333Serj * ixgbe_get_bypass_time 94315333Serj ************************************************************************/ 95315333Serjstatic void 96315333Serjixgbe_get_bypass_time(u32 *year, u32 *sec) 97315333Serj{ 98315333Serj struct timespec current; 99315333Serj 100315333Serj *year = 1970; /* time starts at 01/01/1970 */ 101315333Serj nanotime(¤t); 102315333Serj *sec = current.tv_sec; 103315333Serj 104315333Serj while(*sec > SEC_THIS_YEAR(*year)) { 105315333Serj *sec -= SEC_THIS_YEAR(*year); 106315333Serj (*year)++; 107315333Serj } 108315333Serj} /* ixgbe_get_bypass_time */ 109315333Serj 110315333Serj/************************************************************************ 111315333Serj * ixgbe_bp_version 112315333Serj * 113315333Serj * Display the feature version 114315333Serj ************************************************************************/ 115315333Serjstatic int 116315333Serjixgbe_bp_version(SYSCTL_HANDLER_ARGS) 117315333Serj{ 118315333Serj struct adapter *adapter = (struct adapter *) arg1; 119315333Serj struct ixgbe_hw *hw = &adapter->hw; 120315333Serj int error = 0; 121315333Serj static int version = 0; 122315333Serj u32 cmd; 123315333Serj 124315333Serj ixgbe_bypass_mutex_enter(adapter); 125315333Serj cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; 126315333Serj cmd |= (BYPASS_EEPROM_VER_ADD << BYPASS_CTL2_OFFSET_SHIFT) & 127315333Serj BYPASS_CTL2_OFFSET_M; 128315333Serj if ((error = hw->mac.ops.bypass_rw(hw, cmd, &version) != 0)) 129315333Serj goto err; 130315333Serj msec_delay(100); 131315333Serj cmd &= ~BYPASS_WE; 132315333Serj if ((error = hw->mac.ops.bypass_rw(hw, cmd, &version) != 0)) 133315333Serj goto err; 134315333Serj ixgbe_bypass_mutex_clear(adapter); 135315333Serj version &= BYPASS_CTL2_DATA_M; 136315333Serj error = sysctl_handle_int(oidp, &version, 0, req); 137315333Serj return (error); 138315333Serjerr: 139315333Serj ixgbe_bypass_mutex_clear(adapter); 140315333Serj return (error); 141315333Serj 142315333Serj} /* ixgbe_bp_version */ 143315333Serj 144315333Serj/************************************************************************ 145315333Serj * ixgbe_bp_set_state 146315333Serj * 147315333Serj * Show/Set the Bypass State: 148315333Serj * 1 = NORMAL 149315333Serj * 2 = BYPASS 150315333Serj * 3 = ISOLATE 151315333Serj * 152315333Serj * With no argument the state is displayed, 153315333Serj * passing a value will set it. 154315333Serj ************************************************************************/ 155315333Serjstatic int 156315333Serjixgbe_bp_set_state(SYSCTL_HANDLER_ARGS) 157315333Serj{ 158315333Serj struct adapter *adapter = (struct adapter *) arg1; 159315333Serj struct ixgbe_hw *hw = &adapter->hw; 160315333Serj int error = 0; 161315333Serj static int state = 0; 162315333Serj 163315333Serj /* Get the current state */ 164315333Serj ixgbe_bypass_mutex_enter(adapter); 165315333Serj error = hw->mac.ops.bypass_rw(hw, 166315333Serj BYPASS_PAGE_CTL0, &state); 167315333Serj ixgbe_bypass_mutex_clear(adapter); 168315333Serj if (error) 169315333Serj return (error); 170315333Serj state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3; 171315333Serj 172315333Serj error = sysctl_handle_int(oidp, &state, 0, req); 173315333Serj if ((error) || (req->newptr == NULL)) 174315333Serj return (error); 175315333Serj 176315333Serj /* Sanity check new state */ 177315333Serj switch (state) { 178315333Serj case BYPASS_NORM: 179315333Serj case BYPASS_BYPASS: 180315333Serj case BYPASS_ISOLATE: 181315333Serj break; 182315333Serj default: 183315333Serj return (EINVAL); 184315333Serj } 185315333Serj ixgbe_bypass_mutex_enter(adapter); 186315333Serj if ((error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 187315333Serj BYPASS_MODE_OFF_M, state) != 0)) 188315333Serj goto out; 189315333Serj /* Set AUTO back on so FW can receive events */ 190315333Serj error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 191315333Serj BYPASS_MODE_OFF_M, BYPASS_AUTO); 192315333Serjout: 193315333Serj ixgbe_bypass_mutex_clear(adapter); 194315333Serj usec_delay(6000); 195315333Serj return (error); 196315333Serj} /* ixgbe_bp_set_state */ 197315333Serj 198315333Serj/************************************************************************ 199315333Serj * The following routines control the operational 200315333Serj * "rules" of the feature, what behavior will occur 201315333Serj * when particular events occur. 202315333Serj * Values are: 203315333Serj * 0 - no change for the event (NOP) 204315333Serj * 1 - go to Normal operation 205315333Serj * 2 - go to Bypass operation 206315333Serj * 3 - go to Isolate operation 207315333Serj * Calling the entry with no argument just displays 208315333Serj * the current rule setting. 209315333Serj ************************************************************************/ 210315333Serj 211315333Serj/************************************************************************ 212315333Serj * ixgbe_bp_timeout 213315333Serj * 214315333Serj * This is to set the Rule for the watchdog, 215315333Serj * not the actual watchdog timeout value. 216315333Serj ************************************************************************/ 217315333Serjstatic int 218315333Serjixgbe_bp_timeout(SYSCTL_HANDLER_ARGS) 219315333Serj{ 220315333Serj struct adapter *adapter = (struct adapter *) arg1; 221315333Serj struct ixgbe_hw *hw = &adapter->hw; 222315333Serj int error = 0; 223315333Serj static int timeout = 0; 224315333Serj 225315333Serj /* Get the current value */ 226315333Serj ixgbe_bypass_mutex_enter(adapter); 227315333Serj error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &timeout); 228315333Serj ixgbe_bypass_mutex_clear(adapter); 229315333Serj if (error) 230315333Serj return (error); 231315333Serj timeout = (timeout >> BYPASS_WDTIMEOUT_SHIFT) & 0x3; 232315333Serj 233315333Serj error = sysctl_handle_int(oidp, &timeout, 0, req); 234315333Serj if ((error) || (req->newptr == NULL)) 235315333Serj return (error); 236315333Serj 237315333Serj /* Sanity check on the setting */ 238315333Serj switch (timeout) { 239315333Serj case BYPASS_NOP: 240315333Serj case BYPASS_NORM: 241315333Serj case BYPASS_BYPASS: 242315333Serj case BYPASS_ISOLATE: 243315333Serj break; 244315333Serj default: 245315333Serj return (EINVAL); 246315333Serj } 247315333Serj 248315333Serj /* Set the new state */ 249315333Serj ixgbe_bypass_mutex_enter(adapter); 250315333Serj error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 251315333Serj BYPASS_WDTIMEOUT_M, timeout << BYPASS_WDTIMEOUT_SHIFT); 252315333Serj ixgbe_bypass_mutex_clear(adapter); 253315333Serj usec_delay(6000); 254315333Serj return (error); 255315333Serj} /* ixgbe_bp_timeout */ 256315333Serj 257315333Serj/************************************************************************ 258315333Serj * ixgbe_bp_main_on 259315333Serj ************************************************************************/ 260315333Serjstatic int 261315333Serjixgbe_bp_main_on(SYSCTL_HANDLER_ARGS) 262315333Serj{ 263315333Serj struct adapter *adapter = (struct adapter *) arg1; 264315333Serj struct ixgbe_hw *hw = &adapter->hw; 265315333Serj int error = 0; 266315333Serj static int main_on = 0; 267315333Serj 268315333Serj ixgbe_bypass_mutex_enter(adapter); 269315333Serj error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_on); 270315333Serj main_on = (main_on >> BYPASS_MAIN_ON_SHIFT) & 0x3; 271315333Serj ixgbe_bypass_mutex_clear(adapter); 272315333Serj if (error) 273315333Serj return (error); 274315333Serj 275315333Serj error = sysctl_handle_int(oidp, &main_on, 0, req); 276315333Serj if ((error) || (req->newptr == NULL)) 277315333Serj return (error); 278315333Serj 279315333Serj /* Sanity check on the setting */ 280315333Serj switch (main_on) { 281315333Serj case BYPASS_NOP: 282315333Serj case BYPASS_NORM: 283315333Serj case BYPASS_BYPASS: 284315333Serj case BYPASS_ISOLATE: 285315333Serj break; 286315333Serj default: 287315333Serj return (EINVAL); 288315333Serj } 289315333Serj 290315333Serj /* Set the new state */ 291315333Serj ixgbe_bypass_mutex_enter(adapter); 292315333Serj error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 293315333Serj BYPASS_MAIN_ON_M, main_on << BYPASS_MAIN_ON_SHIFT); 294315333Serj ixgbe_bypass_mutex_clear(adapter); 295315333Serj usec_delay(6000); 296315333Serj return (error); 297315333Serj} /* ixgbe_bp_main_on */ 298315333Serj 299315333Serj/************************************************************************ 300315333Serj * ixgbe_bp_main_off 301315333Serj ************************************************************************/ 302315333Serjstatic int 303315333Serjixgbe_bp_main_off(SYSCTL_HANDLER_ARGS) 304315333Serj{ 305315333Serj struct adapter *adapter = (struct adapter *) arg1; 306315333Serj struct ixgbe_hw *hw = &adapter->hw; 307315333Serj int error = 0; 308315333Serj static int main_off = 0; 309315333Serj 310315333Serj ixgbe_bypass_mutex_enter(adapter); 311315333Serj error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_off); 312315333Serj ixgbe_bypass_mutex_clear(adapter); 313315333Serj if (error) 314315333Serj return (error); 315315333Serj main_off = (main_off >> BYPASS_MAIN_OFF_SHIFT) & 0x3; 316315333Serj 317315333Serj error = sysctl_handle_int(oidp, &main_off, 0, req); 318315333Serj if ((error) || (req->newptr == NULL)) 319315333Serj return (error); 320315333Serj 321315333Serj /* Sanity check on the setting */ 322315333Serj switch (main_off) { 323315333Serj case BYPASS_NOP: 324315333Serj case BYPASS_NORM: 325315333Serj case BYPASS_BYPASS: 326315333Serj case BYPASS_ISOLATE: 327315333Serj break; 328315333Serj default: 329315333Serj return (EINVAL); 330315333Serj } 331315333Serj 332315333Serj /* Set the new state */ 333315333Serj ixgbe_bypass_mutex_enter(adapter); 334315333Serj error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 335315333Serj BYPASS_MAIN_OFF_M, main_off << BYPASS_MAIN_OFF_SHIFT); 336315333Serj ixgbe_bypass_mutex_clear(adapter); 337315333Serj usec_delay(6000); 338315333Serj return (error); 339315333Serj} /* ixgbe_bp_main_off */ 340315333Serj 341315333Serj/************************************************************************ 342315333Serj * ixgbe_bp_aux_on 343315333Serj ************************************************************************/ 344315333Serjstatic int 345315333Serjixgbe_bp_aux_on(SYSCTL_HANDLER_ARGS) 346315333Serj{ 347315333Serj struct adapter *adapter = (struct adapter *) arg1; 348315333Serj struct ixgbe_hw *hw = &adapter->hw; 349315333Serj int error = 0; 350315333Serj static int aux_on = 0; 351315333Serj 352315333Serj ixgbe_bypass_mutex_enter(adapter); 353315333Serj error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_on); 354315333Serj ixgbe_bypass_mutex_clear(adapter); 355315333Serj if (error) 356315333Serj return (error); 357315333Serj aux_on = (aux_on >> BYPASS_AUX_ON_SHIFT) & 0x3; 358315333Serj 359315333Serj error = sysctl_handle_int(oidp, &aux_on, 0, req); 360315333Serj if ((error) || (req->newptr == NULL)) 361315333Serj return (error); 362315333Serj 363315333Serj /* Sanity check on the setting */ 364315333Serj switch (aux_on) { 365315333Serj case BYPASS_NOP: 366315333Serj case BYPASS_NORM: 367315333Serj case BYPASS_BYPASS: 368315333Serj case BYPASS_ISOLATE: 369315333Serj break; 370315333Serj default: 371315333Serj return (EINVAL); 372315333Serj } 373315333Serj 374315333Serj /* Set the new state */ 375315333Serj ixgbe_bypass_mutex_enter(adapter); 376315333Serj error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 377315333Serj BYPASS_AUX_ON_M, aux_on << BYPASS_AUX_ON_SHIFT); 378315333Serj ixgbe_bypass_mutex_clear(adapter); 379315333Serj usec_delay(6000); 380315333Serj return (error); 381315333Serj} /* ixgbe_bp_aux_on */ 382315333Serj 383315333Serj/************************************************************************ 384315333Serj * ixgbe_bp_aux_off 385315333Serj ************************************************************************/ 386315333Serjstatic int 387315333Serjixgbe_bp_aux_off(SYSCTL_HANDLER_ARGS) 388315333Serj{ 389315333Serj struct adapter *adapter = (struct adapter *) arg1; 390315333Serj struct ixgbe_hw *hw = &adapter->hw; 391315333Serj int error = 0; 392315333Serj static int aux_off = 0; 393315333Serj 394315333Serj ixgbe_bypass_mutex_enter(adapter); 395315333Serj error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_off); 396315333Serj ixgbe_bypass_mutex_clear(adapter); 397315333Serj if (error) 398315333Serj return (error); 399315333Serj aux_off = (aux_off >> BYPASS_AUX_OFF_SHIFT) & 0x3; 400315333Serj 401315333Serj error = sysctl_handle_int(oidp, &aux_off, 0, req); 402315333Serj if ((error) || (req->newptr == NULL)) 403315333Serj return (error); 404315333Serj 405315333Serj /* Sanity check on the setting */ 406315333Serj switch (aux_off) { 407315333Serj case BYPASS_NOP: 408315333Serj case BYPASS_NORM: 409315333Serj case BYPASS_BYPASS: 410315333Serj case BYPASS_ISOLATE: 411315333Serj break; 412315333Serj default: 413315333Serj return (EINVAL); 414315333Serj } 415315333Serj 416315333Serj /* Set the new state */ 417315333Serj ixgbe_bypass_mutex_enter(adapter); 418315333Serj error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, 419315333Serj BYPASS_AUX_OFF_M, aux_off << BYPASS_AUX_OFF_SHIFT); 420315333Serj ixgbe_bypass_mutex_clear(adapter); 421315333Serj usec_delay(6000); 422315333Serj return (error); 423315333Serj} /* ixgbe_bp_aux_off */ 424315333Serj 425315333Serj/************************************************************************ 426315333Serj * ixgbe_bp_wd_set - Set the Watchdog timer value 427315333Serj * 428315333Serj * Valid settings are: 429315333Serj * - 0 will disable the watchdog 430315333Serj * - 1, 2, 3, 4, 8, 16, 32 431315333Serj * - anything else is invalid and will be ignored 432315333Serj ************************************************************************/ 433315333Serjstatic int 434315333Serjixgbe_bp_wd_set(SYSCTL_HANDLER_ARGS) 435315333Serj{ 436315333Serj struct adapter *adapter = (struct adapter *) arg1; 437315333Serj struct ixgbe_hw *hw = &adapter->hw; 438315333Serj int error, tmp; 439315333Serj static int timeout = 0; 440315333Serj u32 mask, arg = BYPASS_PAGE_CTL0; 441315333Serj 442315333Serj /* Get the current hardware value */ 443315333Serj ixgbe_bypass_mutex_enter(adapter); 444315333Serj error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &tmp); 445315333Serj ixgbe_bypass_mutex_clear(adapter); 446315333Serj if (error) 447315333Serj return (error); 448315333Serj /* 449315333Serj * If armed keep the displayed value, 450315333Serj * else change the display to zero. 451315333Serj */ 452315333Serj if ((tmp & (0x1 << BYPASS_WDT_ENABLE_SHIFT)) == 0) 453315333Serj timeout = 0; 454315333Serj 455315333Serj error = sysctl_handle_int(oidp, &timeout, 0, req); 456315333Serj if ((error) || (req->newptr == NULL)) 457315333Serj return (error); 458315333Serj 459315333Serj mask = BYPASS_WDT_ENABLE_M; 460315333Serj switch (timeout) { 461315333Serj case 0: /* disables the timer */ 462315333Serj break; 463315333Serj case 1: 464315333Serj arg = BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT; 465315333Serj arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 466315333Serj mask |= BYPASS_WDT_VALUE_M; 467315333Serj break; 468315333Serj case 2: 469315333Serj arg = BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT; 470315333Serj arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 471315333Serj mask |= BYPASS_WDT_VALUE_M; 472315333Serj break; 473315333Serj case 3: 474315333Serj arg = BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT; 475315333Serj arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 476315333Serj mask |= BYPASS_WDT_VALUE_M; 477315333Serj break; 478315333Serj case 4: 479315333Serj arg = BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT; 480315333Serj arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 481315333Serj mask |= BYPASS_WDT_VALUE_M; 482315333Serj break; 483315333Serj case 8: 484315333Serj arg = BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT; 485315333Serj arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 486315333Serj mask |= BYPASS_WDT_VALUE_M; 487315333Serj break; 488315333Serj case 16: 489315333Serj arg = BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT; 490315333Serj arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 491315333Serj mask |= BYPASS_WDT_VALUE_M; 492315333Serj break; 493315333Serj case 32: 494315333Serj arg = BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT; 495315333Serj arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; 496315333Serj mask |= BYPASS_WDT_VALUE_M; 497315333Serj break; 498315333Serj default: 499315333Serj return (EINVAL); 500315333Serj } 501315333Serj /* Set the new watchdog */ 502315333Serj ixgbe_bypass_mutex_enter(adapter); 503315333Serj error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg); 504315333Serj ixgbe_bypass_mutex_clear(adapter); 505315333Serj 506315333Serj return (error); 507315333Serj} /* ixgbe_bp_wd_set */ 508315333Serj 509315333Serj/************************************************************************ 510315333Serj * ixgbe_bp_wd_reset - Reset the Watchdog timer 511315333Serj * 512315333Serj * To activate this it must be called with any argument. 513315333Serj ************************************************************************/ 514315333Serjstatic int 515315333Serjixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS) 516315333Serj{ 517315333Serj struct adapter *adapter = (struct adapter *) arg1; 518315333Serj struct ixgbe_hw *hw = &adapter->hw; 519315333Serj u32 sec, year; 520315333Serj int cmd, count = 0, error = 0; 521315333Serj int reset_wd = 0; 522315333Serj 523315333Serj error = sysctl_handle_int(oidp, &reset_wd, 0, req); 524315333Serj if ((error) || (req->newptr == NULL)) 525315333Serj return (error); 526315333Serj 527315333Serj cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET; 528315333Serj 529315333Serj /* Resync the FW time while writing to CTL1 anyway */ 530315333Serj ixgbe_get_bypass_time(&year, &sec); 531315333Serj 532315333Serj cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID; 533315333Serj cmd |= BYPASS_CTL1_OFFTRST; 534315333Serj 535315333Serj ixgbe_bypass_wd_mutex_enter(adapter); 536315333Serj error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd); 537315333Serj 538315333Serj /* Read until it matches what we wrote, or we time out */ 539315333Serj do { 540315333Serj if (count++ > 10) { 541315333Serj error = IXGBE_BYPASS_FW_WRITE_FAILURE; 542315333Serj break; 543315333Serj } 544315333Serj if (hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd)) { 545315333Serj error = IXGBE_ERR_INVALID_ARGUMENT; 546315333Serj break; 547315333Serj } 548315333Serj } while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd)); 549315333Serj 550315333Serj reset_wd = 0; 551315333Serj ixgbe_bypass_wd_mutex_clear(adapter); 552315333Serj return (error); 553315333Serj} /* ixgbe_bp_wd_reset */ 554315333Serj 555315333Serj/************************************************************************ 556315333Serj * ixgbe_bp_log - Display the bypass log 557315333Serj * 558315333Serj * You must pass a non-zero arg to sysctl 559315333Serj ************************************************************************/ 560315333Serjstatic int 561315333Serjixgbe_bp_log(SYSCTL_HANDLER_ARGS) 562315333Serj{ 563315333Serj struct adapter *adapter = (struct adapter *) arg1; 564315333Serj struct ixgbe_hw *hw = &adapter->hw; 565315333Serj u32 cmd, base, head; 566315333Serj u32 log_off, count = 0; 567315333Serj static int status = 0; 568315333Serj u8 data; 569315333Serj struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS]; 570315333Serj int i, error = 0; 571315333Serj 572315333Serj error = sysctl_handle_int(oidp, &status, 0, req); 573315333Serj if ((error) || (req->newptr == NULL)) 574315333Serj return (error); 575315333Serj 576315333Serj /* Keep the log display single-threaded */ 577315333Serj while (atomic_cmpset_int(&adapter->bypass.log, 0, 1) == 0) 578315333Serj usec_delay(3000); 579315333Serj 580315333Serj ixgbe_bypass_mutex_enter(adapter); 581315333Serj 582315333Serj /* Find Current head of the log eeprom offset */ 583315333Serj cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; 584315333Serj cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 585315333Serj error = hw->mac.ops.bypass_rw(hw, cmd, &status); 586315333Serj if (error) 587315333Serj goto unlock_err; 588315333Serj 589315333Serj /* wait for the write to stick */ 590315333Serj msec_delay(100); 591315333Serj 592315333Serj /* Now read the results */ 593315333Serj cmd &= ~BYPASS_WE; 594315333Serj error = hw->mac.ops.bypass_rw(hw, cmd, &status); 595315333Serj if (error) 596315333Serj goto unlock_err; 597315333Serj 598315333Serj ixgbe_bypass_mutex_clear(adapter); 599315333Serj 600315333Serj base = status & BYPASS_CTL2_DATA_M; 601315333Serj head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT; 602315333Serj 603315333Serj /* address of the first log */ 604315333Serj log_off = base + (head * 5); 605315333Serj 606315333Serj /* extract all the log entries */ 607315333Serj while (count < BYPASS_MAX_LOGS) { 608315333Serj eeprom[count].logs = 0; 609315333Serj eeprom[count].actions = 0; 610315333Serj 611315333Serj /* Log 5 bytes store in on u32 and a u8 */ 612315333Serj for (i = 0; i < 4; i++) { 613315333Serj ixgbe_bypass_mutex_enter(adapter); 614315333Serj error = hw->mac.ops.bypass_rd_eep(hw, log_off + i, 615315333Serj &data); 616315333Serj ixgbe_bypass_mutex_clear(adapter); 617315333Serj if (error) 618315333Serj return (-EINVAL); 619315333Serj eeprom[count].logs += data << (8 * i); 620315333Serj } 621315333Serj 622315333Serj ixgbe_bypass_mutex_enter(adapter); 623315333Serj error = hw->mac.ops.bypass_rd_eep(hw, 624315333Serj log_off + i, &eeprom[count].actions); 625315333Serj ixgbe_bypass_mutex_clear(adapter); 626315333Serj if (error) 627315333Serj return (-EINVAL); 628315333Serj 629315333Serj /* Quit if not a unread log */ 630315333Serj if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M)) 631315333Serj break; 632315333Serj /* 633315333Serj * Log looks good so store the address where it's 634315333Serj * Unread Log bit is so we can clear it after safely 635315333Serj * pulling out all of the log data. 636315333Serj */ 637315333Serj eeprom[count].clear_off = log_off; 638315333Serj 639315333Serj count++; 640315333Serj head = head ? head - 1 : BYPASS_MAX_LOGS; 641315333Serj log_off = base + (head * 5); 642315333Serj } 643315333Serj 644315333Serj /* reverse order (oldest first) for output */ 645315333Serj while (count--) { 646315333Serj int year; 647315333Serj u32 mon, days, hours, min, sec; 648315333Serj u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M; 649315333Serj u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >> 650315333Serj BYPASS_LOG_EVENT_SHIFT; 651315333Serj u8 action = eeprom[count].actions & BYPASS_LOG_ACTION_M; 652315333Serj u16 day_mon[2][13] = { 653315333Serj {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 654315333Serj {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} 655315333Serj }; 656315333Serj char *event_str[] = {"unknown", "main on", "aux on", 657315333Serj "main off", "aux off", "WDT", "user" }; 658315333Serj char *action_str[] = {"ignore", "normal", "bypass", "isolate",}; 659315333Serj 660315333Serj /* verify vaild data 1 - 6 */ 661315333Serj if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR) 662315333Serj event = 0; 663315333Serj 664315333Serj /* 665315333Serj * time is in sec's this year, so convert to something 666315333Serj * printable. 667315333Serj */ 668315333Serj ixgbe_get_bypass_time(&year, &sec); 669315333Serj days = time / SEC_PER_DAY; 670315333Serj for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--) 671315333Serj continue; 672315333Serj mon = i + 1; /* display month as 1-12 */ 673315333Serj time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY); 674315333Serj days = (time / SEC_PER_DAY) + 1; /* first day is 1 */ 675315333Serj time %= SEC_PER_DAY; 676315333Serj hours = time / (60 * 60); 677315333Serj time %= (60 * 60); 678315333Serj min = time / 60; 679315333Serj sec = time % 60; 680315333Serj device_printf(adapter->dev, 681315333Serj "UT %02d/%02d %02d:%02d:%02d %8.8s -> %7.7s\n", 682315333Serj mon, days, hours, min, sec, event_str[event], 683315333Serj action_str[action]); 684315333Serj cmd = BYPASS_PAGE_CTL2 | BYPASS_WE | BYPASS_CTL2_RW; 685315333Serj cmd |= ((eeprom[count].clear_off + 3) 686315333Serj << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 687315333Serj cmd |= ((eeprom[count].logs & ~BYPASS_LOG_CLEAR_M) >> 24); 688315333Serj 689315333Serj ixgbe_bypass_mutex_enter(adapter); 690315333Serj 691315333Serj error = hw->mac.ops.bypass_rw(hw, cmd, &status); 692315333Serj 693315333Serj /* wait for the write to stick */ 694315333Serj msec_delay(100); 695315333Serj 696315333Serj ixgbe_bypass_mutex_clear(adapter); 697315333Serj 698315333Serj if (error) 699315333Serj return (-EINVAL); 700315333Serj } 701315333Serj 702315333Serj status = 0; /* reset */ 703315333Serj /* Another log command can now run */ 704315333Serj while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0) 705315333Serj usec_delay(3000); 706315333Serj return(error); 707315333Serj 708315333Serjunlock_err: 709315333Serj ixgbe_bypass_mutex_clear(adapter); 710315333Serj status = 0; /* reset */ 711315333Serj while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0) 712315333Serj usec_delay(3000); 713315333Serj return (-EINVAL); 714315333Serj} /* ixgbe_bp_log */ 715315333Serj 716315333Serj/************************************************************************ 717315333Serj * ixgbe_bypass_init - Set up infrastructure for the bypass feature 718315333Serj * 719315333Serj * Do time and sysctl initialization here. This feature is 720315333Serj * only enabled for the first port of a bypass adapter. 721315333Serj ************************************************************************/ 722315333Serjvoid 723315333Serjixgbe_bypass_init(struct adapter *adapter) 724315333Serj{ 725315333Serj struct ixgbe_hw *hw = &adapter->hw; 726315333Serj device_t dev = adapter->dev; 727315333Serj struct sysctl_oid *bp_node; 728315333Serj struct sysctl_oid_list *bp_list; 729315333Serj u32 mask, value, sec, year; 730315333Serj 731315333Serj if (!(adapter->feat_cap & IXGBE_FEATURE_BYPASS)) 732315333Serj return; 733315333Serj 734315333Serj /* First set up time for the hardware */ 735315333Serj ixgbe_get_bypass_time(&year, &sec); 736315333Serj 737315333Serj mask = BYPASS_CTL1_TIME_M 738315333Serj | BYPASS_CTL1_VALID_M 739315333Serj | BYPASS_CTL1_OFFTRST_M; 740315333Serj 741315333Serj value = (sec & BYPASS_CTL1_TIME_M) 742315333Serj | BYPASS_CTL1_VALID 743315333Serj | BYPASS_CTL1_OFFTRST; 744315333Serj 745315333Serj ixgbe_bypass_mutex_enter(adapter); 746315333Serj hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value); 747315333Serj ixgbe_bypass_mutex_clear(adapter); 748315333Serj 749315333Serj /* Now set up the SYSCTL infrastructure */ 750315333Serj 751315333Serj /* 752315333Serj * The log routine is kept separate from the other 753315333Serj * children so a general display command like: 754315333Serj * `sysctl dev.ix.0.bypass` will not show the log. 755315333Serj */ 756315333Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 757315333Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 758315333Serj OID_AUTO, "bypass_log", CTLTYPE_INT | CTLFLAG_RW, 759315333Serj adapter, 0, ixgbe_bp_log, "I", "Bypass Log"); 760315333Serj 761315333Serj /* All other setting are hung from the 'bypass' node */ 762315333Serj bp_node = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), 763315333Serj SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 764315333Serj OID_AUTO, "bypass", CTLFLAG_RD, NULL, "Bypass"); 765315333Serj 766315333Serj bp_list = SYSCTL_CHILDREN(bp_node); 767315333Serj 768315333Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 769315333Serj OID_AUTO, "version", CTLTYPE_INT | CTLFLAG_RD, 770315333Serj adapter, 0, ixgbe_bp_version, "I", "Bypass Version"); 771315333Serj 772315333Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 773315333Serj OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RW, 774315333Serj adapter, 0, ixgbe_bp_set_state, "I", "Bypass State"); 775315333Serj 776315333Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 777315333Serj OID_AUTO, "timeout", CTLTYPE_INT | CTLFLAG_RW, 778315333Serj adapter, 0, ixgbe_bp_timeout, "I", "Bypass Timeout"); 779315333Serj 780315333Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 781315333Serj OID_AUTO, "main_on", CTLTYPE_INT | CTLFLAG_RW, 782315333Serj adapter, 0, ixgbe_bp_main_on, "I", "Bypass Main On"); 783315333Serj 784315333Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 785315333Serj OID_AUTO, "main_off", CTLTYPE_INT | CTLFLAG_RW, 786315333Serj adapter, 0, ixgbe_bp_main_off, "I", "Bypass Main Off"); 787315333Serj 788315333Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 789315333Serj OID_AUTO, "aux_on", CTLTYPE_INT | CTLFLAG_RW, 790315333Serj adapter, 0, ixgbe_bp_aux_on, "I", "Bypass Aux On"); 791315333Serj 792315333Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 793315333Serj OID_AUTO, "aux_off", CTLTYPE_INT | CTLFLAG_RW, 794315333Serj adapter, 0, ixgbe_bp_aux_off, "I", "Bypass Aux Off"); 795315333Serj 796315333Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 797315333Serj OID_AUTO, "wd_set", CTLTYPE_INT | CTLFLAG_RW, 798315333Serj adapter, 0, ixgbe_bp_wd_set, "I", "Set BP Watchdog"); 799315333Serj 800315333Serj SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, 801315333Serj OID_AUTO, "wd_reset", CTLTYPE_INT | CTLFLAG_WR, 802315333Serj adapter, 0, ixgbe_bp_wd_reset, "S", "Bypass WD Reset"); 803315333Serj 804315333Serj adapter->feat_en |= IXGBE_FEATURE_BYPASS; 805315333Serj 806315333Serj return; 807315333Serj} /* ixgbe_bypass_init */ 808315333Serj 809