Commit 42f8277f authored by Yuval Mintz's avatar Yuval Mintz Committed by David S. Miller

bnx2x: Support mng. request for driver version

This adds support in a new management feature which needs the driver versions
(bnx2x, bnx2fc and bnx2i) loaded for each interface.
Signed-off-by: default avatarYuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: default avatarAriel Elior <Ariel.Elior@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 869f2739
...@@ -1413,6 +1413,7 @@ enum sp_rtnl_flag { ...@@ -1413,6 +1413,7 @@ enum sp_rtnl_flag {
BNX2X_SP_RTNL_RX_MODE, BNX2X_SP_RTNL_RX_MODE,
BNX2X_SP_RTNL_HYPERVISOR_VLAN, BNX2X_SP_RTNL_HYPERVISOR_VLAN,
BNX2X_SP_RTNL_TX_STOP, BNX2X_SP_RTNL_TX_STOP,
BNX2X_SP_RTNL_GET_DRV_VERSION,
}; };
struct bnx2x_prev_path_list { struct bnx2x_prev_path_list {
...@@ -1703,6 +1704,10 @@ struct bnx2x { ...@@ -1703,6 +1704,10 @@ struct bnx2x {
struct bnx2x_slowpath *slowpath; struct bnx2x_slowpath *slowpath;
dma_addr_t slowpath_mapping; dma_addr_t slowpath_mapping;
/* Mechanism protecting the drv_info_to_mcp */
struct mutex drv_info_mutex;
bool drv_info_mng_owner;
/* Total number of FW statistics requests */ /* Total number of FW statistics requests */
u8 fw_stats_num; u8 fw_stats_num;
...@@ -2535,6 +2540,8 @@ enum { ...@@ -2535,6 +2540,8 @@ enum {
void bnx2x_set_local_cmng(struct bnx2x *bp); void bnx2x_set_local_cmng(struct bnx2x *bp);
void bnx2x_update_mng_version(struct bnx2x *bp);
#define MCPR_SCRATCH_BASE(bp) \ #define MCPR_SCRATCH_BASE(bp) \
(CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH) (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH)
......
...@@ -2804,6 +2804,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) ...@@ -2804,6 +2804,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
if (CNIC_ENABLED(bp)) if (CNIC_ENABLED(bp))
bnx2x_load_cnic(bp); bnx2x_load_cnic(bp);
if (IS_PF(bp))
bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) { if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
/* mark driver is loaded in shmem2 */ /* mark driver is loaded in shmem2 */
u32 val; u32 val;
...@@ -3030,6 +3033,10 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link) ...@@ -3030,6 +3033,10 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
bp->state = BNX2X_STATE_CLOSED; bp->state = BNX2X_STATE_CLOSED;
bp->cnic_loaded = false; bp->cnic_loaded = false;
/* Clear driver version indication in shmem */
if (IS_PF(bp))
bnx2x_update_mng_version(bp);
/* Check if there are pending parity attentions. If there are - set /* Check if there are pending parity attentions. If there are - set
* RECOVERY_IN_PROGRESS. * RECOVERY_IN_PROGRESS.
*/ */
......
...@@ -2003,6 +2003,23 @@ struct shmem_lfa { ...@@ -2003,6 +2003,23 @@ struct shmem_lfa {
#define SHMEM_LFA_DONT_CLEAR_STAT (1<<24) #define SHMEM_LFA_DONT_CLEAR_STAT (1<<24)
}; };
/* Used to support NSCI get OS driver version
* on driver load the version value will be set
* on driver unload driver value of 0x0 will be set.
*/
struct os_drv_ver {
#define DRV_VER_NOT_LOADED 0
/* personalties order is important */
#define DRV_PERS_ETHERNET 0
#define DRV_PERS_ISCSI 1
#define DRV_PERS_FCOE 2
/* shmem2 struct is constant can't add more personalties here */
#define MAX_DRV_PERS 3
u32 versions[MAX_DRV_PERS];
};
struct ncsi_oem_fcoe_features { struct ncsi_oem_fcoe_features {
u32 fcoe_features1; u32 fcoe_features1;
#define FCOE_FEATURES1_IOS_PER_CONNECTION_MASK 0x0000FFFF #define FCOE_FEATURES1_IOS_PER_CONNECTION_MASK 0x0000FFFF
...@@ -2217,6 +2234,18 @@ struct shmem2_region { ...@@ -2217,6 +2234,18 @@ struct shmem2_region {
u32 reserved4; /* Offset 0x150 */ u32 reserved4; /* Offset 0x150 */
u32 link_attr_sync[PORT_MAX]; /* Offset 0x154 */ u32 link_attr_sync[PORT_MAX]; /* Offset 0x154 */
#define LINK_ATTR_SYNC_KR2_ENABLE (1<<0) #define LINK_ATTR_SYNC_KR2_ENABLE (1<<0)
u32 reserved5[2];
u32 reserved6[PORT_MAX];
/* driver version for each personality */
struct os_drv_ver func_os_drv_ver[E2_FUNC_MAX]; /* Offset 0x16c */
/* Flag to the driver that PF's drv_info_host_addr buffer was read */
u32 mfw_drv_indication;
/* We use indication for each PF (0..3) */
#define MFW_DRV_IND_READ_DONE_OFFSET(_pf_) (1 << (_pf_))
}; };
......
...@@ -3482,10 +3482,15 @@ static void bnx2x_handle_eee_event(struct bnx2x *bp) ...@@ -3482,10 +3482,15 @@ static void bnx2x_handle_eee_event(struct bnx2x *bp)
bnx2x_fw_command(bp, DRV_MSG_CODE_EEE_RESULTS_ACK, 0); bnx2x_fw_command(bp, DRV_MSG_CODE_EEE_RESULTS_ACK, 0);
} }
#define BNX2X_UPDATE_DRV_INFO_IND_LENGTH (20)
#define BNX2X_UPDATE_DRV_INFO_IND_COUNT (25)
static void bnx2x_handle_drv_info_req(struct bnx2x *bp) static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
{ {
enum drv_info_opcode op_code; enum drv_info_opcode op_code;
u32 drv_info_ctl = SHMEM2_RD(bp, drv_info_control); u32 drv_info_ctl = SHMEM2_RD(bp, drv_info_control);
bool release = false;
int wait;
/* if drv_info version supported by MFW doesn't match - send NACK */ /* if drv_info version supported by MFW doesn't match - send NACK */
if ((drv_info_ctl & DRV_INFO_CONTROL_VER_MASK) != DRV_INFO_CUR_VER) { if ((drv_info_ctl & DRV_INFO_CONTROL_VER_MASK) != DRV_INFO_CUR_VER) {
...@@ -3496,6 +3501,9 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp) ...@@ -3496,6 +3501,9 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
op_code = (drv_info_ctl & DRV_INFO_CONTROL_OP_CODE_MASK) >> op_code = (drv_info_ctl & DRV_INFO_CONTROL_OP_CODE_MASK) >>
DRV_INFO_CONTROL_OP_CODE_SHIFT; DRV_INFO_CONTROL_OP_CODE_SHIFT;
/* Must prevent other flows from accessing drv_info_to_mcp */
mutex_lock(&bp->drv_info_mutex);
memset(&bp->slowpath->drv_info_to_mcp, 0, memset(&bp->slowpath->drv_info_to_mcp, 0,
sizeof(union drv_info_to_mcp)); sizeof(union drv_info_to_mcp));
...@@ -3512,7 +3520,7 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp) ...@@ -3512,7 +3520,7 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
default: default:
/* if op code isn't supported - send NACK */ /* if op code isn't supported - send NACK */
bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_NACK, 0); bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_NACK, 0);
return; goto out;
} }
/* if we got drv_info attn from MFW then these fields are defined in /* if we got drv_info attn from MFW then these fields are defined in
...@@ -3524,6 +3532,106 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp) ...@@ -3524,6 +3532,106 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
U64_HI(bnx2x_sp_mapping(bp, drv_info_to_mcp))); U64_HI(bnx2x_sp_mapping(bp, drv_info_to_mcp)));
bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_ACK, 0); bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_ACK, 0);
/* Since possible management wants both this and get_driver_version
* need to wait until management notifies us it finished utilizing
* the buffer.
*/
if (!SHMEM2_HAS(bp, mfw_drv_indication)) {
DP(BNX2X_MSG_MCP, "Management does not support indication\n");
} else if (!bp->drv_info_mng_owner) {
u32 bit = MFW_DRV_IND_READ_DONE_OFFSET((BP_ABS_FUNC(bp) >> 1));
for (wait = 0; wait < BNX2X_UPDATE_DRV_INFO_IND_COUNT; wait++) {
u32 indication = SHMEM2_RD(bp, mfw_drv_indication);
/* Management is done; need to clear indication */
if (indication & bit) {
SHMEM2_WR(bp, mfw_drv_indication,
indication & ~bit);
release = true;
break;
}
msleep(BNX2X_UPDATE_DRV_INFO_IND_LENGTH);
}
}
if (!release) {
DP(BNX2X_MSG_MCP, "Management did not release indication\n");
bp->drv_info_mng_owner = true;
}
out:
mutex_unlock(&bp->drv_info_mutex);
}
static u32 bnx2x_update_mng_version_utility(u8 *version, bool bnx2x_format)
{
u8 vals[4];
int i = 0;
if (bnx2x_format) {
i = sscanf(version, "1.%c%hhd.%hhd.%hhd",
&vals[0], &vals[1], &vals[2], &vals[3]);
if (i > 0)
vals[0] -= '0';
} else {
i = sscanf(version, "%hhd.%hhd.%hhd.%hhd",
&vals[0], &vals[1], &vals[2], &vals[3]);
}
while (i < 4)
vals[i++] = 0;
return (vals[0] << 24) | (vals[1] << 16) | (vals[2] << 8) | vals[3];
}
void bnx2x_update_mng_version(struct bnx2x *bp)
{
u32 iscsiver = DRV_VER_NOT_LOADED;
u32 fcoever = DRV_VER_NOT_LOADED;
u32 ethver = DRV_VER_NOT_LOADED;
int idx = BP_FW_MB_IDX(bp);
u8 *version;
if (!SHMEM2_HAS(bp, func_os_drv_ver))
return;
mutex_lock(&bp->drv_info_mutex);
/* Must not proceed when `bnx2x_handle_drv_info_req' is feasible */
if (bp->drv_info_mng_owner)
goto out;
if (bp->state != BNX2X_STATE_OPEN)
goto out;
/* Parse ethernet driver version */
ethver = bnx2x_update_mng_version_utility(DRV_MODULE_VERSION, true);
if (!CNIC_LOADED(bp))
goto out;
/* Try getting storage driver version via cnic */
memset(&bp->slowpath->drv_info_to_mcp, 0,
sizeof(union drv_info_to_mcp));
bnx2x_drv_info_iscsi_stat(bp);
version = bp->slowpath->drv_info_to_mcp.iscsi_stat.version;
iscsiver = bnx2x_update_mng_version_utility(version, false);
memset(&bp->slowpath->drv_info_to_mcp, 0,
sizeof(union drv_info_to_mcp));
bnx2x_drv_info_fcoe_stat(bp);
version = bp->slowpath->drv_info_to_mcp.fcoe_stat.version;
fcoever = bnx2x_update_mng_version_utility(version, false);
out:
SHMEM2_WR(bp, func_os_drv_ver[idx].versions[DRV_PERS_ETHERNET], ethver);
SHMEM2_WR(bp, func_os_drv_ver[idx].versions[DRV_PERS_ISCSI], iscsiver);
SHMEM2_WR(bp, func_os_drv_ver[idx].versions[DRV_PERS_FCOE], fcoever);
mutex_unlock(&bp->drv_info_mutex);
DP(BNX2X_MSG_MCP, "Setting driver version: ETH [%08x] iSCSI [%08x] FCoE [%08x]\n",
ethver, iscsiver, fcoever);
} }
static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event) static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
...@@ -9807,6 +9915,10 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work) ...@@ -9807,6 +9915,10 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
bnx2x_dcbx_resume_hw_tx(bp); bnx2x_dcbx_resume_hw_tx(bp);
} }
if (test_and_clear_bit(BNX2X_SP_RTNL_GET_DRV_VERSION,
&bp->sp_rtnl_state))
bnx2x_update_mng_version(bp);
/* work which needs rtnl lock not-taken (as it takes the lock itself and /* work which needs rtnl lock not-taken (as it takes the lock itself and
* can be called from other contexts as well) * can be called from other contexts as well)
*/ */
...@@ -11757,6 +11869,8 @@ static int bnx2x_init_bp(struct bnx2x *bp) ...@@ -11757,6 +11869,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
mutex_init(&bp->port.phy_mutex); mutex_init(&bp->port.phy_mutex);
mutex_init(&bp->fw_mb_mutex); mutex_init(&bp->fw_mb_mutex);
mutex_init(&bp->drv_info_mutex);
bp->drv_info_mng_owner = false;
spin_lock_init(&bp->stats_lock); spin_lock_init(&bp->stats_lock);
sema_init(&bp->stats_sema, 1); sema_init(&bp->stats_sema, 1);
...@@ -13794,6 +13908,7 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl) ...@@ -13794,6 +13908,7 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
REG_WR(bp, scratch_offset + i, REG_WR(bp, scratch_offset + i,
*(host_addr + i/4)); *(host_addr + i/4));
} }
bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
break; break;
} }
...@@ -13811,6 +13926,7 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl) ...@@ -13811,6 +13926,7 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
cap &= ~DRV_FLAGS_CAPABILITIES_LOADED_FCOE; cap &= ~DRV_FLAGS_CAPABILITIES_LOADED_FCOE;
SHMEM2_WR(bp, drv_capabilities_flag[idx], cap); SHMEM2_WR(bp, drv_capabilities_flag[idx], cap);
} }
bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
break; break;
} }
...@@ -13916,6 +14032,9 @@ static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops, ...@@ -13916,6 +14032,9 @@ static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
rcu_assign_pointer(bp->cnic_ops, ops); rcu_assign_pointer(bp->cnic_ops, ops);
/* Schedule driver to read CNIC driver versions */
bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment