Skip to content

Commit b3c6873

Browse files
Anirban Chakrabortydavem330
authored andcommitted
qlcnic: Take FW dump via ethtool
Driver checks if the previous dump has been cleared before taking the dump. It doesn't take the dump if it is not cleared. Changes from v2: Added lock to protect dump data structures from being mangled while dumping or setting them via ethtool. Signed-off-by: Anirban Chakraborty <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 18f2f61 commit b3c6873

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

drivers/net/qlcnic/qlcnic_ethtool.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,84 @@ static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
965965
adapter->msg_enable = msglvl;
966966
}
967967

968+
static int
969+
qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
970+
{
971+
struct qlcnic_adapter *adapter = netdev_priv(netdev);
972+
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
973+
974+
dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
975+
dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
976+
dump->version = adapter->fw_version;
977+
return 0;
978+
}
979+
980+
static int
981+
qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
982+
void *buffer)
983+
{
984+
int i, copy_sz;
985+
u32 *hdr_ptr, *data;
986+
struct qlcnic_adapter *adapter = netdev_priv(netdev);
987+
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
988+
989+
if (qlcnic_api_lock(adapter))
990+
return -EIO;
991+
if (!fw_dump->clr) {
992+
netdev_info(netdev, "Dump not available\n");
993+
qlcnic_api_unlock(adapter);
994+
return -EINVAL;
995+
}
996+
/* Copy template header first */
997+
copy_sz = fw_dump->tmpl_hdr->size;
998+
hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
999+
data = (u32 *) buffer;
1000+
for (i = 0; i < copy_sz/sizeof(u32); i++)
1001+
*data++ = cpu_to_le32(*hdr_ptr++);
1002+
1003+
/* Copy captured dump data */
1004+
memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
1005+
dump->len = copy_sz + fw_dump->size;
1006+
dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
1007+
1008+
/* Free dump area once data has been captured */
1009+
vfree(fw_dump->data);
1010+
fw_dump->data = NULL;
1011+
fw_dump->clr = 0;
1012+
qlcnic_api_unlock(adapter);
1013+
1014+
return 0;
1015+
}
1016+
1017+
static int
1018+
qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1019+
{
1020+
int ret = 0;
1021+
struct qlcnic_adapter *adapter = netdev_priv(netdev);
1022+
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1023+
1024+
if (val->flag == QLCNIC_FORCE_FW_DUMP_KEY) {
1025+
netdev_info(netdev, "Forcing a FW dump\n");
1026+
qlcnic_dev_request_reset(adapter);
1027+
} else {
1028+
if (val->flag > QLCNIC_DUMP_MASK_MAX ||
1029+
val->flag < QLCNIC_DUMP_MASK_MIN) {
1030+
netdev_info(netdev,
1031+
"Invalid dump level: 0x%x\n", val->flag);
1032+
ret = -EINVAL;
1033+
goto out;
1034+
}
1035+
if (qlcnic_api_lock(adapter))
1036+
return -EIO;
1037+
fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
1038+
qlcnic_api_unlock(adapter);
1039+
netdev_info(netdev, "Driver mask changed to: 0x%x\n",
1040+
fw_dump->tmpl_hdr->drv_cap_mask);
1041+
}
1042+
out:
1043+
return ret;
1044+
}
1045+
9681046
const struct ethtool_ops qlcnic_ethtool_ops = {
9691047
.get_settings = qlcnic_get_settings,
9701048
.set_settings = qlcnic_set_settings,
@@ -991,4 +1069,7 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
9911069
.set_phys_id = qlcnic_set_led,
9921070
.set_msglevel = qlcnic_set_msglevel,
9931071
.get_msglevel = qlcnic_get_msglevel,
1072+
.get_dump_flag = qlcnic_get_dump_flag,
1073+
.get_dump_data = qlcnic_get_dump_data,
1074+
.set_dump = qlcnic_set_dump,
9941075
};

0 commit comments

Comments
 (0)