Skip to content

Commit 18f2f61

Browse files
Anirban Chakrabortydavem330
authored andcommitted
qlcnic: FW dump support
Added code to take FW dump. o Driver queries FW at the init time and gets the dump template o It takes FW dump as per the dump template o Level of FW dump (and its size) is configured via dump flag Signed-off-by: Sritej Velaga <[email protected]> Signed-off-by: Anirban Chakraborty <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1dbf53a commit 18f2f61

File tree

6 files changed

+774
-9
lines changed

6 files changed

+774
-9
lines changed

drivers/net/qlcnic/qlcnic.h

Lines changed: 175 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,29 @@ struct qlcnic_nic_intr_coalesce {
411411
u32 timer_out;
412412
};
413413

414+
struct qlcnic_dump_template_hdr {
415+
__le32 type;
416+
__le32 offset;
417+
__le32 size;
418+
__le32 cap_mask;
419+
__le32 num_entries;
420+
__le32 version;
421+
__le32 timestamp;
422+
__le32 checksum;
423+
__le32 drv_cap_mask;
424+
__le32 sys_info[3];
425+
__le32 saved_state[16];
426+
__le32 cap_sizes[8];
427+
__le32 rsvd[0];
428+
};
429+
430+
struct qlcnic_fw_dump {
431+
u8 clr; /* flag to indicate if dump is cleared */
432+
u32 size; /* total size of the dump */
433+
void *data; /* dump data area */
434+
struct qlcnic_dump_template_hdr *tmpl_hdr;
435+
};
436+
414437
/*
415438
* One hardware_context{} per adapter
416439
* contains interrupt info as well shared hardware info.
@@ -431,6 +454,7 @@ struct qlcnic_hardware_context {
431454
u16 board_type;
432455

433456
struct qlcnic_nic_intr_coalesce coal;
457+
struct qlcnic_fw_dump fw_dump;
434458
};
435459

436460
struct qlcnic_adapter_stats {
@@ -574,6 +598,8 @@ struct qlcnic_recv_context {
574598
#define QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG 0x00000029
575599
#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATS 0x0000002a
576600
#define QLCNIC_CDRP_CMD_CONFIG_PORT 0x0000002E
601+
#define QLCNIC_CDRP_CMD_TEMP_SIZE 0x0000002f
602+
#define QLCNIC_CDRP_CMD_GET_TEMP_HDR 0x00000030
577603

578604
#define QLCNIC_RCODE_SUCCESS 0
579605
#define QLCNIC_RCODE_NOT_SUPPORTED 9
@@ -1157,6 +1183,152 @@ struct qlcnic_esw_statistics {
11571183
struct __qlcnic_esw_statistics tx;
11581184
};
11591185

1186+
struct qlcnic_common_entry_hdr {
1187+
__le32 type;
1188+
__le32 offset;
1189+
__le32 cap_size;
1190+
u8 mask;
1191+
u8 rsvd[2];
1192+
u8 flags;
1193+
} __packed;
1194+
1195+
struct __crb {
1196+
__le32 addr;
1197+
u8 stride;
1198+
u8 rsvd1[3];
1199+
__le32 data_size;
1200+
__le32 no_ops;
1201+
__le32 rsvd2[4];
1202+
} __packed;
1203+
1204+
struct __ctrl {
1205+
__le32 addr;
1206+
u8 stride;
1207+
u8 index_a;
1208+
__le16 timeout;
1209+
__le32 data_size;
1210+
__le32 no_ops;
1211+
u8 opcode;
1212+
u8 index_v;
1213+
u8 shl_val;
1214+
u8 shr_val;
1215+
__le32 val1;
1216+
__le32 val2;
1217+
__le32 val3;
1218+
} __packed;
1219+
1220+
struct __cache {
1221+
__le32 addr;
1222+
u8 stride;
1223+
u8 rsvd;
1224+
__le16 init_tag_val;
1225+
__le32 size;
1226+
__le32 no_ops;
1227+
__le32 ctrl_addr;
1228+
__le32 ctrl_val;
1229+
__le32 read_addr;
1230+
u8 read_addr_stride;
1231+
u8 read_addr_num;
1232+
u8 rsvd1[2];
1233+
} __packed;
1234+
1235+
struct __ocm {
1236+
u8 rsvd[8];
1237+
__le32 size;
1238+
__le32 no_ops;
1239+
u8 rsvd1[8];
1240+
__le32 read_addr;
1241+
__le32 read_addr_stride;
1242+
} __packed;
1243+
1244+
struct __mem {
1245+
u8 rsvd[24];
1246+
__le32 addr;
1247+
__le32 size;
1248+
} __packed;
1249+
1250+
struct __mux {
1251+
__le32 addr;
1252+
u8 rsvd[4];
1253+
__le32 size;
1254+
__le32 no_ops;
1255+
__le32 val;
1256+
__le32 val_stride;
1257+
__le32 read_addr;
1258+
u8 rsvd2[4];
1259+
} __packed;
1260+
1261+
struct __queue {
1262+
__le32 sel_addr;
1263+
__le16 stride;
1264+
u8 rsvd[2];
1265+
__le32 size;
1266+
__le32 no_ops;
1267+
u8 rsvd2[8];
1268+
__le32 read_addr;
1269+
u8 read_addr_stride;
1270+
u8 read_addr_cnt;
1271+
u8 rsvd3[2];
1272+
} __packed;
1273+
1274+
struct qlcnic_dump_entry {
1275+
struct qlcnic_common_entry_hdr hdr;
1276+
union {
1277+
struct __crb crb;
1278+
struct __cache cache;
1279+
struct __ocm ocm;
1280+
struct __mem mem;
1281+
struct __mux mux;
1282+
struct __queue que;
1283+
struct __ctrl ctrl;
1284+
} region;
1285+
} __packed;
1286+
1287+
enum op_codes {
1288+
QLCNIC_DUMP_NOP = 0,
1289+
QLCNIC_DUMP_READ_CRB = 1,
1290+
QLCNIC_DUMP_READ_MUX = 2,
1291+
QLCNIC_DUMP_QUEUE = 3,
1292+
QLCNIC_DUMP_BRD_CONFIG = 4,
1293+
QLCNIC_DUMP_READ_OCM = 6,
1294+
QLCNIC_DUMP_PEG_REG = 7,
1295+
QLCNIC_DUMP_L1_DTAG = 8,
1296+
QLCNIC_DUMP_L1_ITAG = 9,
1297+
QLCNIC_DUMP_L1_DATA = 11,
1298+
QLCNIC_DUMP_L1_INST = 12,
1299+
QLCNIC_DUMP_L2_DTAG = 21,
1300+
QLCNIC_DUMP_L2_ITAG = 22,
1301+
QLCNIC_DUMP_L2_DATA = 23,
1302+
QLCNIC_DUMP_L2_INST = 24,
1303+
QLCNIC_DUMP_READ_ROM = 71,
1304+
QLCNIC_DUMP_READ_MEM = 72,
1305+
QLCNIC_DUMP_READ_CTRL = 98,
1306+
QLCNIC_DUMP_TLHDR = 99,
1307+
QLCNIC_DUMP_RDEND = 255
1308+
};
1309+
1310+
#define QLCNIC_DUMP_WCRB BIT_0
1311+
#define QLCNIC_DUMP_RWCRB BIT_1
1312+
#define QLCNIC_DUMP_ANDCRB BIT_2
1313+
#define QLCNIC_DUMP_ORCRB BIT_3
1314+
#define QLCNIC_DUMP_POLLCRB BIT_4
1315+
#define QLCNIC_DUMP_RD_SAVE BIT_5
1316+
#define QLCNIC_DUMP_WRT_SAVED BIT_6
1317+
#define QLCNIC_DUMP_MOD_SAVE_ST BIT_7
1318+
#define QLCNIC_DUMP_SKIP BIT_7
1319+
1320+
#define QLCNIC_DUMP_MASK_MIN 3
1321+
#define QLCNIC_DUMP_MASK_DEF 0x0f
1322+
#define QLCNIC_DUMP_MASK_MAX 0xff
1323+
#define QLCNIC_FORCE_FW_DUMP_KEY 0xdeadfeed
1324+
1325+
struct qlcnic_dump_operations {
1326+
enum op_codes opcode;
1327+
u32 (*handler)(struct qlcnic_adapter *,
1328+
struct qlcnic_dump_entry *, u32 *);
1329+
};
1330+
1331+
int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
11601332
int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config);
11611333

11621334
u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off);
@@ -1203,6 +1375,7 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
12031375
int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
12041376
void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter);
12051377
void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter);
1378+
int qlcnic_dump_fw(struct qlcnic_adapter *);
12061379

12071380
/* Functions from qlcnic_init.c */
12081381
int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
@@ -1213,7 +1386,7 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter);
12131386
int qlcnic_setup_idc_param(struct qlcnic_adapter *adapter);
12141387
int qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter);
12151388

1216-
int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp);
1389+
int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp);
12171390
int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
12181391
u8 *bytes, size_t size);
12191392
int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter);
@@ -1265,6 +1438,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
12651438
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
12661439
int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val);
12671440
int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data);
1441+
void qlcnic_dev_request_reset(struct qlcnic_adapter *);
12681442

12691443
/* Management functions */
12701444
int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);

drivers/net/qlcnic/qlcnic_ctx.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,97 @@ qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
6464
return rcode;
6565
}
6666

67+
static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u16 temp_size)
68+
{
69+
uint64_t sum = 0;
70+
int count = temp_size / sizeof(uint32_t);
71+
while (count-- > 0)
72+
sum += *temp_buffer++;
73+
while (sum >> 32)
74+
sum = (sum & 0xFFFFFFFF) + (sum >> 32);
75+
return ~sum;
76+
}
77+
78+
int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
79+
{
80+
int err, i;
81+
u16 temp_size;
82+
void *tmp_addr;
83+
u32 version, csum, *template, *tmp_buf;
84+
struct qlcnic_hardware_context *ahw;
85+
struct qlcnic_dump_template_hdr *tmpl_hdr, *tmp_tmpl;
86+
dma_addr_t tmp_addr_t = 0;
87+
88+
ahw = adapter->ahw;
89+
err = qlcnic_issue_cmd(adapter,
90+
adapter->ahw->pci_func,
91+
adapter->fw_hal_version,
92+
0,
93+
0,
94+
0,
95+
QLCNIC_CDRP_CMD_TEMP_SIZE);
96+
if (err != QLCNIC_RCODE_SUCCESS) {
97+
err = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
98+
dev_err(&adapter->pdev->dev,
99+
"Failed to get template size %d\n", err);
100+
err = -EIO;
101+
return err;
102+
}
103+
version = QLCRD32(adapter, QLCNIC_ARG3_CRB_OFFSET);
104+
temp_size = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
105+
if (!temp_size)
106+
return -EIO;
107+
108+
tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
109+
&tmp_addr_t, GFP_KERNEL);
110+
if (!tmp_addr) {
111+
dev_err(&adapter->pdev->dev,
112+
"Can't get memory for FW dump template\n");
113+
return -ENOMEM;
114+
}
115+
err = qlcnic_issue_cmd(adapter,
116+
adapter->ahw->pci_func,
117+
adapter->fw_hal_version,
118+
LSD(tmp_addr_t),
119+
MSD(tmp_addr_t),
120+
temp_size,
121+
QLCNIC_CDRP_CMD_GET_TEMP_HDR);
122+
123+
if (err != QLCNIC_RCODE_SUCCESS) {
124+
dev_err(&adapter->pdev->dev,
125+
"Failed to get mini dump template header %d\n", err);
126+
err = -EIO;
127+
goto error;
128+
}
129+
tmp_tmpl = (struct qlcnic_dump_template_hdr *) tmp_addr;
130+
csum = qlcnic_temp_checksum((uint32_t *) tmp_addr, temp_size);
131+
if (csum) {
132+
dev_err(&adapter->pdev->dev,
133+
"Template header checksum validation failed\n");
134+
err = -EIO;
135+
goto error;
136+
}
137+
ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
138+
if (!ahw->fw_dump.tmpl_hdr) {
139+
err = -EIO;
140+
goto error;
141+
}
142+
tmp_buf = (u32 *) tmp_addr;
143+
template = (u32 *) ahw->fw_dump.tmpl_hdr;
144+
for (i = 0; i < temp_size/sizeof(u32); i++)
145+
*template++ = __le32_to_cpu(*tmp_buf++);
146+
147+
tmpl_hdr = ahw->fw_dump.tmpl_hdr;
148+
if (tmpl_hdr->cap_mask > QLCNIC_DUMP_MASK_DEF &&
149+
tmpl_hdr->cap_mask <= QLCNIC_DUMP_MASK_MAX)
150+
tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask;
151+
else
152+
tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
153+
error:
154+
dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
155+
return err;
156+
}
157+
67158
int
68159
qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
69160
{

drivers/net/qlcnic/qlcnic_hdr.h

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -492,10 +492,10 @@ enum {
492492

493493
#define TEST_AGT_CTRL (0x00)
494494

495-
#define TA_CTL_START 1
496-
#define TA_CTL_ENABLE 2
497-
#define TA_CTL_WRITE 4
498-
#define TA_CTL_BUSY 8
495+
#define TA_CTL_START BIT_0
496+
#define TA_CTL_ENABLE BIT_1
497+
#define TA_CTL_WRITE BIT_2
498+
#define TA_CTL_BUSY BIT_3
499499

500500
/*
501501
* Register offsets for MN
@@ -765,6 +765,38 @@ struct qlcnic_legacy_intr_set {
765765
#define QLCNIC_MAX_PCI_FUNC 8
766766
#define QLCNIC_MAX_VLAN_FILTERS 64
767767

768+
/* FW dump defines */
769+
#define MIU_TEST_CTR 0x41000090
770+
#define MIU_TEST_ADDR_LO 0x41000094
771+
#define MIU_TEST_ADDR_HI 0x41000098
772+
#define FLASH_ROM_WINDOW 0x42110030
773+
#define FLASH_ROM_DATA 0x42150000
774+
775+
static const u32 MIU_TEST_READ_DATA[] = {
776+
0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, };
777+
778+
#define QLCNIC_FW_DUMP_REG1 0x00130060
779+
#define QLCNIC_FW_DUMP_REG2 0x001e0000
780+
#define QLCNIC_FLASH_SEM2_LK 0x0013C010
781+
#define QLCNIC_FLASH_SEM2_ULK 0x0013C014
782+
#define QLCNIC_FLASH_LOCK_ID 0x001B2100
783+
784+
#define QLCNIC_RD_DUMP_REG(addr, bar0, data) do { \
785+
writel((addr & 0xFFFF0000), (void *) (bar0 + \
786+
QLCNIC_FW_DUMP_REG1)); \
787+
readl((void *) (bar0 + QLCNIC_FW_DUMP_REG1)); \
788+
*data = readl((void *) (bar0 + QLCNIC_FW_DUMP_REG2 + \
789+
LSW(addr))); \
790+
} while (0)
791+
792+
#define QLCNIC_WR_DUMP_REG(addr, bar0, data) do { \
793+
writel((addr & 0xFFFF0000), (void *) (bar0 + \
794+
QLCNIC_FW_DUMP_REG1)); \
795+
readl((void *) (bar0 + QLCNIC_FW_DUMP_REG1)); \
796+
writel(data, (void *) (bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr)));\
797+
readl((void *) (bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr))); \
798+
} while (0)
799+
768800
/* PCI function operational mode */
769801
enum {
770802
QLCNIC_MGMT_FUNC = 0,

0 commit comments

Comments
 (0)