liquidio: fix kernel panic when NIC firmware is older than 1.7.2

Pre-1.7.2 NIC firmware does not support (and does not respond to) the "get
speed" command which is sent by the 1.7.2 driver (for CN23XX-225 cards
only) during modprobe.  Due to a bug in older firmware (with respect to
unknown commands), this unsupported command causes a cascade of errors that
ends in a kernel panic.

Fix it by making the sending of the "get speed" command conditional on the
firmware version.

Signed-off-by: Rick Farrington <ricardo.farrington@cavium.com>
Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Rick Farrington 2018-07-06 11:27:07 -07:00 committed by David S. Miller
parent 9ebcb397aa
commit 4fed38cf26
2 changed files with 33 additions and 2 deletions

View File

@ -3299,7 +3299,9 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
{
struct lio *lio = NULL;
struct net_device *netdev;
u8 mac[6], i, j, *fw_ver;
u8 mac[6], i, j, *fw_ver, *micro_ver;
unsigned long micro;
u32 cur_ver;
struct octeon_soft_command *sc;
struct liquidio_if_cfg_context *ctx;
struct liquidio_if_cfg_resp *resp;
@ -3429,6 +3431,14 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
fw_ver);
}
/* extract micro version field; point past '<maj>.<min>.' */
micro_ver = fw_ver + strlen(LIQUIDIO_BASE_VERSION) + 1;
if (kstrtoul(micro_ver, 10, &micro) != 0)
micro = 0;
octeon_dev->fw_info.ver.maj = LIQUIDIO_BASE_MAJOR_VERSION;
octeon_dev->fw_info.ver.min = LIQUIDIO_BASE_MINOR_VERSION;
octeon_dev->fw_info.ver.rev = micro;
octeon_swap_8B_data((u64 *)(&resp->cfg_info),
(sizeof(struct liquidio_if_cfg_info)) >> 3);
@ -3671,7 +3681,19 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
OCTEON_CN2350_25GB_SUBSYS_ID ||
octeon_dev->subsystem_id ==
OCTEON_CN2360_25GB_SUBSYS_ID) {
liquidio_get_speed(lio);
cur_ver = OCT_FW_VER(octeon_dev->fw_info.ver.maj,
octeon_dev->fw_info.ver.min,
octeon_dev->fw_info.ver.rev);
/* speed control unsupported in f/w older than 1.7.2 */
if (cur_ver < OCT_FW_VER(1, 7, 2)) {
dev_info(&octeon_dev->pci_dev->dev,
"speed setting not supported by f/w.");
octeon_dev->speed_setting = 25;
octeon_dev->no_speed_setting = 1;
} else {
liquidio_get_speed(lio);
}
if (octeon_dev->speed_setting == 0) {
octeon_dev->speed_setting = 25;

View File

@ -288,8 +288,17 @@ struct oct_fw_info {
*/
u32 app_mode;
char liquidio_firmware_version[32];
/* Fields extracted from legacy string 'liquidio_firmware_version' */
struct {
u8 maj;
u8 min;
u8 rev;
} ver;
};
#define OCT_FW_VER(maj, min, rev) \
(((u32)(maj) << 16) | ((u32)(min) << 8) | ((u32)(rev)))
/* wrappers around work structs */
struct cavium_wk {
struct delayed_work work;