HW lock mechanism
Enhancing the HW lock to work per function and not only per port - this
is needed for the next patch that protects races over HW attention
detection between the different functions. At this chance, changing the
functions names to be more inline with the current naming convention

Signed-off-by: Yitchak Gertner <gertner@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Yitchak Gertner 2008-08-13 15:50:23 -07:00 коммит произвёл David S. Miller
Родитель da5a662a23
Коммит 4a37fb660c
2 изменённых файлов: 75 добавлений и 44 удалений

Просмотреть файл

@ -1693,11 +1693,12 @@ static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
* General service functions
*/
static int bnx2x_hw_lock(struct bnx2x *bp, u32 resource)
static int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource)
{
u32 lock_status;
u32 resource_bit = (1 << resource);
u8 port = BP_PORT(bp);
int func = BP_FUNC(bp);
u32 hw_lock_control_reg;
int cnt;
/* Validating that the resource is within range */
@ -1708,8 +1709,15 @@ static int bnx2x_hw_lock(struct bnx2x *bp, u32 resource)
return -EINVAL;
}
if (func <= 5) {
hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
} else {
hw_lock_control_reg =
(MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
}
/* Validating that the resource is not already taken */
lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + port*8);
lock_status = REG_RD(bp, hw_lock_control_reg);
if (lock_status & resource_bit) {
DP(NETIF_MSG_HW, "lock_status 0x%x resource_bit 0x%x\n",
lock_status, resource_bit);
@ -1719,9 +1727,8 @@ static int bnx2x_hw_lock(struct bnx2x *bp, u32 resource)
/* Try for 1 second every 5ms */
for (cnt = 0; cnt < 200; cnt++) {
/* Try to acquire the lock */
REG_WR(bp, MISC_REG_DRIVER_CONTROL_1 + port*8 + 4,
resource_bit);
lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + port*8);
REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
lock_status = REG_RD(bp, hw_lock_control_reg);
if (lock_status & resource_bit)
return 0;
@ -1731,11 +1738,12 @@ static int bnx2x_hw_lock(struct bnx2x *bp, u32 resource)
return -EAGAIN;
}
static int bnx2x_hw_unlock(struct bnx2x *bp, u32 resource)
static int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
{
u32 lock_status;
u32 resource_bit = (1 << resource);
u8 port = BP_PORT(bp);
int func = BP_FUNC(bp);
u32 hw_lock_control_reg;
/* Validating that the resource is within range */
if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
@ -1745,20 +1753,27 @@ static int bnx2x_hw_unlock(struct bnx2x *bp, u32 resource)
return -EINVAL;
}
if (func <= 5) {
hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
} else {
hw_lock_control_reg =
(MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
}
/* Validating that the resource is currently taken */
lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + port*8);
lock_status = REG_RD(bp, hw_lock_control_reg);
if (!(lock_status & resource_bit)) {
DP(NETIF_MSG_HW, "lock_status 0x%x resource_bit 0x%x\n",
lock_status, resource_bit);
return -EFAULT;
}
REG_WR(bp, MISC_REG_DRIVER_CONTROL_1 + port*8, resource_bit);
REG_WR(bp, hw_lock_control_reg, resource_bit);
return 0;
}
/* HW Lock for shared dual port PHYs */
static void bnx2x_phy_hw_lock(struct bnx2x *bp)
static void bnx2x_acquire_phy_lock(struct bnx2x *bp)
{
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
@ -1766,16 +1781,16 @@ static void bnx2x_phy_hw_lock(struct bnx2x *bp)
if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) ||
(ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073))
bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO);
bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO);
}
static void bnx2x_phy_hw_unlock(struct bnx2x *bp)
static void bnx2x_release_phy_lock(struct bnx2x *bp)
{
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) ||
(ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073))
bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO);
bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO);
mutex_unlock(&bp->port.phy_mutex);
}
@ -1795,7 +1810,7 @@ int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode)
return -EINVAL;
}
bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
/* read GPIO and mask except the float bits */
gpio_reg = (REG_RD(bp, MISC_REG_GPIO) & MISC_REGISTERS_GPIO_FLOAT);
@ -1828,7 +1843,7 @@ int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode)
}
REG_WR(bp, MISC_REG_GPIO, gpio_reg);
bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_GPIO);
bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
return 0;
}
@ -1844,7 +1859,7 @@ static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
return -EINVAL;
}
bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
/* read SPIO and mask except the float bits */
spio_reg = (REG_RD(bp, MISC_REG_SPIO) & MISC_REGISTERS_SPIO_FLOAT);
@ -1874,7 +1889,7 @@ static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
}
REG_WR(bp, MISC_REG_SPIO, spio_reg);
bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_SPIO);
bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
return 0;
}
@ -1940,9 +1955,9 @@ static u8 bnx2x_initial_phy_init(struct bnx2x *bp)
/* Initialize link parameters structure variables */
bp->link_params.mtu = bp->dev->mtu;
bnx2x_phy_hw_lock(bp);
bnx2x_acquire_phy_lock(bp);
rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars);
bnx2x_phy_hw_unlock(bp);
bnx2x_release_phy_lock(bp);
if (bp->link_vars.link_up)
bnx2x_link_report(bp);
@ -1958,9 +1973,9 @@ static u8 bnx2x_initial_phy_init(struct bnx2x *bp)
static void bnx2x_link_set(struct bnx2x *bp)
{
if (!BP_NOMCP(bp)) {
bnx2x_phy_hw_lock(bp);
bnx2x_acquire_phy_lock(bp);
bnx2x_phy_init(&bp->link_params, &bp->link_vars);
bnx2x_phy_hw_unlock(bp);
bnx2x_release_phy_lock(bp);
bnx2x_calc_fc_adv(bp);
} else
@ -1970,9 +1985,9 @@ static void bnx2x_link_set(struct bnx2x *bp)
static void bnx2x__link_reset(struct bnx2x *bp)
{
if (!BP_NOMCP(bp)) {
bnx2x_phy_hw_lock(bp);
bnx2x_acquire_phy_lock(bp);
bnx2x_link_reset(&bp->link_params, &bp->link_vars);
bnx2x_phy_hw_unlock(bp);
bnx2x_release_phy_lock(bp);
} else
BNX2X_ERR("Bootcode is missing -not resetting link\n");
}
@ -1981,9 +1996,9 @@ static u8 bnx2x_link_test(struct bnx2x *bp)
{
u8 rc;
bnx2x_phy_hw_lock(bp);
bnx2x_acquire_phy_lock(bp);
rc = bnx2x_test_link(&bp->link_params, &bp->link_vars);
bnx2x_phy_hw_unlock(bp);
bnx2x_release_phy_lock(bp);
return rc;
}
@ -2207,9 +2222,9 @@ static void bnx2x_link_attn(struct bnx2x *bp)
/* Make sure that we are synced with the current statistics */
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
bnx2x_phy_hw_lock(bp);
bnx2x_acquire_phy_lock(bp);
bnx2x_link_update(&bp->link_params, &bp->link_vars);
bnx2x_phy_hw_unlock(bp);
bnx2x_release_phy_lock(bp);
if (bp->link_vars.link_up) {
@ -2361,7 +2376,7 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
}
/* acquire split MCP access lock register */
static int bnx2x_lock_alr(struct bnx2x *bp)
static int bnx2x_acquire_alr(struct bnx2x *bp)
{
u32 i, j, val;
int rc = 0;
@ -2385,8 +2400,8 @@ static int bnx2x_lock_alr(struct bnx2x *bp)
return rc;
}
/* Release split MCP access lock register */
static void bnx2x_unlock_alr(struct bnx2x *bp)
/* release split MCP access lock register */
static void bnx2x_release_alr(struct bnx2x *bp)
{
u32 val = 0;
@ -2399,7 +2414,6 @@ static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp)
u16 rc = 0;
barrier(); /* status block is written to by the chip */
if (bp->def_att_idx != def_sb->atten_status_block.attn_bits_index) {
bp->def_att_idx = def_sb->atten_status_block.attn_bits_index;
rc |= 1;
@ -2706,7 +2720,7 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
/* need to take HW lock because MCP or other port might also
try to handle this event */
bnx2x_lock_alr(bp);
bnx2x_acquire_alr(bp);
attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4);
attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4);
@ -2742,7 +2756,7 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
}
}
bnx2x_unlock_alr(bp);
bnx2x_release_alr(bp);
reg_addr = (IGU_ADDR_ATTN_BITS_CLR + IGU_FUNC_BASE * BP_FUNC(bp)) * 8;
@ -6767,7 +6781,7 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
/* Check if it is the UNDI driver
* UNDI driver initializes CID offset for normal bell to 0x7
*/
bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
val = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
if (val == 0x7) {
u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
@ -6846,7 +6860,7 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
(SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
DRV_MSG_SEQ_NUMBER_MASK);
}
bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_UNDI);
bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
}
}
@ -7703,11 +7717,11 @@ static void bnx2x_get_drvinfo(struct net_device *dev,
phy_fw_ver[0] = '\0';
if (bp->port.pmf) {
bnx2x_phy_hw_lock(bp);
bnx2x_acquire_phy_lock(bp);
bnx2x_get_ext_phy_fw_version(&bp->link_params,
(bp->state != BNX2X_STATE_CLOSED),
phy_fw_ver, PHY_FW_VER_LEN);
bnx2x_phy_hw_unlock(bp);
bnx2x_release_phy_lock(bp);
}
snprintf(info->fw_version, 32, "%d.%d.%d:%d BC:%x%s%s",
@ -8165,7 +8179,7 @@ static int bnx2x_set_eeprom(struct net_device *dev,
if (eeprom->magic == 0x00504859)
if (bp->port.pmf) {
bnx2x_phy_hw_lock(bp);
bnx2x_acquire_phy_lock(bp);
rc = bnx2x_flash_download(bp, BP_PORT(bp),
bp->link_params.ext_phy_config,
(bp->state != BNX2X_STATE_CLOSED),
@ -8177,7 +8191,7 @@ static int bnx2x_set_eeprom(struct net_device *dev,
rc |= bnx2x_phy_init(&bp->link_params,
&bp->link_vars);
}
bnx2x_phy_hw_unlock(bp);
bnx2x_release_phy_lock(bp);
} else /* Only the PMF can access the PHY */
return -EINVAL;
@ -8601,15 +8615,15 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
if (loopback_mode == BNX2X_MAC_LOOPBACK) {
bp->link_params.loopback_mode = LOOPBACK_BMAC;
bnx2x_phy_hw_lock(bp);
bnx2x_acquire_phy_lock(bp);
bnx2x_phy_init(&bp->link_params, &bp->link_vars);
bnx2x_phy_hw_unlock(bp);
bnx2x_release_phy_lock(bp);
} else if (loopback_mode == BNX2X_PHY_LOOPBACK) {
bp->link_params.loopback_mode = LOOPBACK_XGXS_10;
bnx2x_phy_hw_lock(bp);
bnx2x_acquire_phy_lock(bp);
bnx2x_phy_init(&bp->link_params, &bp->link_vars);
bnx2x_phy_hw_unlock(bp);
bnx2x_release_phy_lock(bp);
/* wait until link state is restored */
bnx2x_wait_for_link(bp, link_up);

Просмотреть файл

@ -1372,6 +1372,23 @@
be asserted). */
#define MISC_REG_DRIVER_CONTROL_16 0xa5f0
#define MISC_REG_DRIVER_CONTROL_16_SIZE 2
/* [RW 32] The following driver registers(1...16) represent 16 drivers and
32 clients. Each client can be controlled by one driver only. One in each
bit represent that this driver control the appropriate client (Ex: bit 5
is set means this driver control client number 5). addr1 = set; addr0 =
clear; read from both addresses will give the same result = status. write
to address 1 will set a request to control all the clients that their
appropriate bit (in the write command) is set. if the client is free (the
appropriate bit in all the other drivers is clear) one will be written to
that driver register; if the client isn't free the bit will remain zero.
if the appropriate bit is set (the driver request to gain control on a
client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW
interrupt will be asserted). write to address 0 will set a request to
free all the clients that their appropriate bit (in the write command) is
set. if the appropriate bit is clear (the driver request to free a client
it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will
be asserted). */
#define MISC_REG_DRIVER_CONTROL_7 0xa3c8
/* [RW 1] e1hmf for WOL. If clr WOL signal o the PXP will be send on bit 0
only. */
#define MISC_REG_E1HMF_MODE 0xa5f8