FreeBSD/sys/dev/bxe/bxe.c
/*
 * Per pf misc lock must be acquired before the per port mcp lock. Otherwise,
 * had we done things the other way around, if two pfs from the same port
 * would attempt to access nvram at the same time, we could run into a
 * scenario such as:
 * pf A takes the port lock.
 * pf B succeeds in taking the same lock since they are from the same port.
 * pf A takes the per pf misc lock. Performs eeprom access.
 * pf A finishes. Unlocks the per pf misc lock.
 * Pf B takes the lock and proceeds to perform it's own access.
 * pf A unlocks the per port lock, while pf B is still working (!).
 * mcp takes the per port lock and corrupts pf B's access (and/or has it's own
 * access corrupted by pf B).*
 */
Per pf misc lock must be acquired before the per port mcp lock. Otherwise,
had we done things the other way around, if two pfs from the same port
would attempt to access nvram at the same time, we could run into a
scenario such as:
pf A takes the port lock.
pf B succeeds in taking the same lock since they are from the same port.
pf A takes the per pf misc lock. Performs eeprom access.
pf A finishes. Unlocks the per pf misc lock.
Pf B takes the lock and proceeds to perform it's own access.
pf A unlocks the per port lock, while pf B is still working (!).
mcp takes the per port lock and corrupts pf B's access (and/or has it's own
access corrupted by pf B).
Per pf misc lock must be acquired before the per port mcp lock . Otherwise had we done things the other way around if two pfs from the same port would attempt to access nvram at the same time we could run into a scenario such as : pf A takes the port lock . pf B succeeds in taking the same lock since they are from the same port . pf A takes the per pf misc lock . Performs eeprom access . pf A finishes . Unlocks the per pf misc lock . Pf B takes the lock and proceeds to perform it ' s own access . pf A unlocks the per port lock while pf B is still working ( ! ) . mcp takes the per port lock and corrupts pf B ' s access ( and / or has it ' s own access corrupted by pf B ) .
static int
bxe_acquire_nvram_lock(struct bxe_softc *sc)
{
    int port = SC_PORT(sc);
    int count, i;
    uint32_t val = 0;
    bxe_acquire_hw_lock(sc, HW_LOCK_RESOURCE_NVRAM);
    count = NVRAM_TIMEOUT_COUNT;
    if (CHIP_REV_IS_SLOW(sc)) {
        count *= 100;
    }
    REG_WR(sc, MCP_REG_MCPR_NVM_SW_ARB,
           (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port));
    for (i = 0; i < count*10; i++) {
        val = REG_RD(sc, MCP_REG_MCPR_NVM_SW_ARB);
        if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) {
            break;
        }
        DELAY(5);
    }
    if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) {
        BLOGE(sc, "Cannot get access to nvram interface "
            "port %d val 0x%x (MCPR_NVM_SW_ARB_ARB_ARB1 << port)\n",
            port, val);
        return (-1);
    }
    return (0);
}
static int bxe_acquire_nvram_lock ( struct bxe_softc * sc ) { int port = SC_PORT ( sc ) ; int count , i ; uint32_t val = 0 ; bxe_acquire_hw_lock ( sc , HW_LOCK_RESOURCE_NVRAM ) ; count = NVRAM_TIMEOUT_COUNT ; if ( CHIP_REV_IS_SLOW ( sc ) ) { count *= 100 ; } REG_WR ( sc , MCP_REG_MCPR_NVM_SW_ARB , ( MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port ) ) ; for ( i = 0 ; i < count * 10 ; i ++ ) { val = REG_RD ( sc , MCP_REG_MCPR_NVM_SW_ARB ) ; if ( val & ( MCPR_NVM_SW_ARB_ARB_ARB1 << port ) ) { break ; } DELAY ( 5 ) ; } if ( ! ( val & ( MCPR_NVM_SW_ARB_ARB_ARB1 << port ) ) ) { BLOGE ( sc , " " " \n " , port , val ) ; return ( -1 ) ; } return ( 0 ) ; }
Per pf misc lock must be acquired before the per port mcp lock.
Per pf misc lock must be acquired before the per port mcp lock .
/* acquire HW lock: protect against other PFs in PF Direct Assignment */ /* adjust timeout for emulation/FPGA */ /* request access to nvram interface */