|
@@ -211,6 +211,107 @@ enum qlcnic_minidump_opcode {
|
|
|
QLCNIC_DUMP_RDEND = 255
|
|
|
};
|
|
|
|
|
|
+inline u32 qlcnic_82xx_get_saved_state(void *t_hdr, u32 index)
|
|
|
+{
|
|
|
+ struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
|
|
|
+
|
|
|
+ return hdr->saved_state[index];
|
|
|
+}
|
|
|
+
|
|
|
+inline void qlcnic_82xx_set_saved_state(void *t_hdr, u32 index,
|
|
|
+ u32 value)
|
|
|
+{
|
|
|
+ struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
|
|
|
+
|
|
|
+ hdr->saved_state[index] = value;
|
|
|
+}
|
|
|
+
|
|
|
+void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
|
|
|
+{
|
|
|
+ struct qlcnic_82xx_dump_template_hdr *hdr;
|
|
|
+
|
|
|
+ hdr = fw_dump->tmpl_hdr;
|
|
|
+ fw_dump->tmpl_hdr_size = hdr->size;
|
|
|
+ fw_dump->version = hdr->version;
|
|
|
+ fw_dump->num_entries = hdr->num_entries;
|
|
|
+ fw_dump->offset = hdr->offset;
|
|
|
+
|
|
|
+ hdr->drv_cap_mask = hdr->cap_mask;
|
|
|
+ fw_dump->cap_mask = hdr->cap_mask;
|
|
|
+}
|
|
|
+
|
|
|
+inline u32 qlcnic_82xx_get_cap_size(void *t_hdr, int index)
|
|
|
+{
|
|
|
+ struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
|
|
|
+
|
|
|
+ return hdr->cap_sizes[index];
|
|
|
+}
|
|
|
+
|
|
|
+void qlcnic_82xx_set_sys_info(void *t_hdr, int idx, u32 value)
|
|
|
+{
|
|
|
+ struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
|
|
|
+
|
|
|
+ hdr->sys_info[idx] = value;
|
|
|
+}
|
|
|
+
|
|
|
+void qlcnic_82xx_store_cap_mask(void *tmpl_hdr, u32 mask)
|
|
|
+{
|
|
|
+ struct qlcnic_82xx_dump_template_hdr *hdr = tmpl_hdr;
|
|
|
+
|
|
|
+ hdr->drv_cap_mask = mask;
|
|
|
+}
|
|
|
+
|
|
|
+inline u32 qlcnic_83xx_get_saved_state(void *t_hdr, u32 index)
|
|
|
+{
|
|
|
+ struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
|
|
|
+
|
|
|
+ return hdr->saved_state[index];
|
|
|
+}
|
|
|
+
|
|
|
+inline void qlcnic_83xx_set_saved_state(void *t_hdr, u32 index,
|
|
|
+ u32 value)
|
|
|
+{
|
|
|
+ struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
|
|
|
+
|
|
|
+ hdr->saved_state[index] = value;
|
|
|
+}
|
|
|
+
|
|
|
+void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
|
|
|
+{
|
|
|
+ struct qlcnic_83xx_dump_template_hdr *hdr;
|
|
|
+
|
|
|
+ hdr = fw_dump->tmpl_hdr;
|
|
|
+ fw_dump->tmpl_hdr_size = hdr->size;
|
|
|
+ fw_dump->version = hdr->version;
|
|
|
+ fw_dump->num_entries = hdr->num_entries;
|
|
|
+ fw_dump->offset = hdr->offset;
|
|
|
+
|
|
|
+ hdr->drv_cap_mask = hdr->cap_mask;
|
|
|
+ fw_dump->cap_mask = hdr->cap_mask;
|
|
|
+}
|
|
|
+
|
|
|
+inline u32 qlcnic_83xx_get_cap_size(void *t_hdr, int index)
|
|
|
+{
|
|
|
+ struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
|
|
|
+
|
|
|
+ return hdr->cap_sizes[index];
|
|
|
+}
|
|
|
+
|
|
|
+void qlcnic_83xx_set_sys_info(void *t_hdr, int idx, u32 value)
|
|
|
+{
|
|
|
+ struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
|
|
|
+
|
|
|
+ hdr->sys_info[idx] = value;
|
|
|
+}
|
|
|
+
|
|
|
+void qlcnic_83xx_store_cap_mask(void *tmpl_hdr, u32 mask)
|
|
|
+{
|
|
|
+ struct qlcnic_83xx_dump_template_hdr *hdr;
|
|
|
+
|
|
|
+ hdr = tmpl_hdr;
|
|
|
+ hdr->drv_cap_mask = mask;
|
|
|
+}
|
|
|
+
|
|
|
struct qlcnic_dump_operations {
|
|
|
enum qlcnic_minidump_opcode opcode;
|
|
|
u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *,
|
|
@@ -238,11 +339,11 @@ static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
|
|
|
static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
|
|
|
struct qlcnic_dump_entry *entry, __le32 *buffer)
|
|
|
{
|
|
|
+ void *hdr = adapter->ahw->fw_dump.tmpl_hdr;
|
|
|
+ struct __ctrl *ctr = &entry->region.ctrl;
|
|
|
int i, k, timeout = 0;
|
|
|
- u32 addr, data;
|
|
|
+ u32 addr, data, temp;
|
|
|
u8 no_ops;
|
|
|
- struct __ctrl *ctr = &entry->region.ctrl;
|
|
|
- struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
|
|
|
|
|
|
addr = ctr->addr;
|
|
|
no_ops = ctr->no_ops;
|
|
@@ -285,29 +386,42 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
|
|
|
}
|
|
|
break;
|
|
|
case QLCNIC_DUMP_RD_SAVE:
|
|
|
- if (ctr->index_a)
|
|
|
- addr = t_hdr->saved_state[ctr->index_a];
|
|
|
+ temp = ctr->index_a;
|
|
|
+ if (temp)
|
|
|
+ addr = qlcnic_get_saved_state(adapter,
|
|
|
+ hdr,
|
|
|
+ temp);
|
|
|
data = qlcnic_ind_rd(adapter, addr);
|
|
|
- t_hdr->saved_state[ctr->index_v] = data;
|
|
|
+ qlcnic_set_saved_state(adapter, hdr,
|
|
|
+ ctr->index_v, data);
|
|
|
break;
|
|
|
case QLCNIC_DUMP_WRT_SAVED:
|
|
|
- if (ctr->index_v)
|
|
|
- data = t_hdr->saved_state[ctr->index_v];
|
|
|
+ temp = ctr->index_v;
|
|
|
+ if (temp)
|
|
|
+ data = qlcnic_get_saved_state(adapter,
|
|
|
+ hdr,
|
|
|
+ temp);
|
|
|
else
|
|
|
data = ctr->val1;
|
|
|
- if (ctr->index_a)
|
|
|
- addr = t_hdr->saved_state[ctr->index_a];
|
|
|
+
|
|
|
+ temp = ctr->index_a;
|
|
|
+ if (temp)
|
|
|
+ addr = qlcnic_get_saved_state(adapter,
|
|
|
+ hdr,
|
|
|
+ temp);
|
|
|
qlcnic_ind_wr(adapter, addr, data);
|
|
|
break;
|
|
|
case QLCNIC_DUMP_MOD_SAVE_ST:
|
|
|
- data = t_hdr->saved_state[ctr->index_v];
|
|
|
+ data = qlcnic_get_saved_state(adapter, hdr,
|
|
|
+ ctr->index_v);
|
|
|
data <<= ctr->shl_val;
|
|
|
data >>= ctr->shr_val;
|
|
|
if (ctr->val2)
|
|
|
data &= ctr->val2;
|
|
|
data |= ctr->val3;
|
|
|
data += ctr->val1;
|
|
|
- t_hdr->saved_state[ctr->index_v] = data;
|
|
|
+ qlcnic_set_saved_state(adapter, hdr,
|
|
|
+ ctr->index_v, data);
|
|
|
break;
|
|
|
default:
|
|
|
dev_info(&adapter->pdev->dev,
|
|
@@ -544,7 +658,7 @@ out:
|
|
|
static int qlcnic_start_pex_dma(struct qlcnic_adapter *adapter,
|
|
|
struct __mem *mem)
|
|
|
{
|
|
|
- struct qlcnic_dump_template_hdr *tmpl_hdr;
|
|
|
+ struct qlcnic_83xx_dump_template_hdr *tmpl_hdr;
|
|
|
struct device *dev = &adapter->pdev->dev;
|
|
|
u32 dma_no, dma_base_addr, temp_addr;
|
|
|
int i, ret, dma_sts;
|
|
@@ -596,7 +710,7 @@ static u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter,
|
|
|
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
|
|
|
u32 temp, dma_base_addr, size = 0, read_size = 0;
|
|
|
struct qlcnic_pex_dma_descriptor *dma_descr;
|
|
|
- struct qlcnic_dump_template_hdr *tmpl_hdr;
|
|
|
+ struct qlcnic_83xx_dump_template_hdr *tmpl_hdr;
|
|
|
struct device *dev = &adapter->pdev->dev;
|
|
|
dma_addr_t dma_phys_addr;
|
|
|
void *dma_buffer;
|
|
@@ -938,8 +1052,8 @@ static int
|
|
|
qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
|
|
|
struct qlcnic_cmd_args *cmd)
|
|
|
{
|
|
|
- struct qlcnic_dump_template_hdr tmp_hdr;
|
|
|
- u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32);
|
|
|
+ struct qlcnic_83xx_dump_template_hdr tmp_hdr;
|
|
|
+ u32 size = sizeof(tmp_hdr) / sizeof(u32);
|
|
|
int ret = 0;
|
|
|
|
|
|
if (qlcnic_82xx_check(adapter))
|
|
@@ -1027,17 +1141,19 @@ free_mem:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+#define QLCNIC_TEMPLATE_VERSION (0x20001)
|
|
|
+
|
|
|
int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
|
|
|
{
|
|
|
- int err;
|
|
|
- u32 temp_size = 0;
|
|
|
- u32 version, csum, *tmp_buf;
|
|
|
struct qlcnic_hardware_context *ahw;
|
|
|
- struct qlcnic_dump_template_hdr *tmpl_hdr;
|
|
|
+ struct qlcnic_fw_dump *fw_dump;
|
|
|
+ u32 version, csum, *tmp_buf;
|
|
|
u8 use_flash_temp = 0;
|
|
|
+ u32 temp_size = 0;
|
|
|
+ int err;
|
|
|
|
|
|
ahw = adapter->ahw;
|
|
|
-
|
|
|
+ fw_dump = &ahw->fw_dump;
|
|
|
err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size,
|
|
|
&use_flash_temp);
|
|
|
if (err) {
|
|
@@ -1046,11 +1162,11 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
|
|
|
return -EIO;
|
|
|
}
|
|
|
|
|
|
- ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
|
|
|
- if (!ahw->fw_dump.tmpl_hdr)
|
|
|
+ fw_dump->tmpl_hdr = vzalloc(temp_size);
|
|
|
+ if (!fw_dump->tmpl_hdr)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr;
|
|
|
+ tmp_buf = (u32 *)fw_dump->tmpl_hdr;
|
|
|
if (use_flash_temp)
|
|
|
goto flash_temp;
|
|
|
|
|
@@ -1065,8 +1181,8 @@ flash_temp:
|
|
|
dev_err(&adapter->pdev->dev,
|
|
|
"Failed to get minidump template header %d\n",
|
|
|
err);
|
|
|
- vfree(ahw->fw_dump.tmpl_hdr);
|
|
|
- ahw->fw_dump.tmpl_hdr = NULL;
|
|
|
+ vfree(fw_dump->tmpl_hdr);
|
|
|
+ fw_dump->tmpl_hdr = NULL;
|
|
|
return -EIO;
|
|
|
}
|
|
|
}
|
|
@@ -1076,21 +1192,22 @@ flash_temp:
|
|
|
if (csum) {
|
|
|
dev_err(&adapter->pdev->dev,
|
|
|
"Template header checksum validation failed\n");
|
|
|
- vfree(ahw->fw_dump.tmpl_hdr);
|
|
|
- ahw->fw_dump.tmpl_hdr = NULL;
|
|
|
+ vfree(fw_dump->tmpl_hdr);
|
|
|
+ fw_dump->tmpl_hdr = NULL;
|
|
|
return -EIO;
|
|
|
}
|
|
|
|
|
|
- tmpl_hdr = ahw->fw_dump.tmpl_hdr;
|
|
|
- tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask;
|
|
|
+ qlcnic_cache_tmpl_hdr_values(adapter, fw_dump);
|
|
|
+
|
|
|
dev_info(&adapter->pdev->dev,
|
|
|
"Default minidump capture mask 0x%x\n",
|
|
|
- tmpl_hdr->cap_mask);
|
|
|
+ fw_dump->cap_mask);
|
|
|
|
|
|
- if ((tmpl_hdr->version & 0xfffff) >= 0x20001)
|
|
|
- ahw->fw_dump.use_pex_dma = true;
|
|
|
+ if (qlcnic_83xx_check(adapter) &&
|
|
|
+ (fw_dump->version & 0xfffff) >= QLCNIC_TEMPLATE_VERSION)
|
|
|
+ fw_dump->use_pex_dma = true;
|
|
|
else
|
|
|
- ahw->fw_dump.use_pex_dma = false;
|
|
|
+ fw_dump->use_pex_dma = false;
|
|
|
|
|
|
qlcnic_enable_fw_dump_state(adapter);
|
|
|
|
|
@@ -1099,21 +1216,22 @@ flash_temp:
|
|
|
|
|
|
int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
|
|
|
{
|
|
|
- __le32 *buffer;
|
|
|
- u32 ocm_window;
|
|
|
- char mesg[64];
|
|
|
- char *msg[] = {mesg, NULL};
|
|
|
- int i, k, ops_cnt, ops_index, dump_size = 0;
|
|
|
- u32 entry_offset, dump, no_entries, buf_offset = 0;
|
|
|
- struct qlcnic_dump_entry *entry;
|
|
|
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
|
|
|
- struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
|
|
|
static const struct qlcnic_dump_operations *fw_dump_ops;
|
|
|
+ struct qlcnic_83xx_dump_template_hdr *hdr_83xx;
|
|
|
+ u32 entry_offset, dump, no_entries, buf_offset = 0;
|
|
|
+ int i, k, ops_cnt, ops_index, dump_size = 0;
|
|
|
struct device *dev = &adapter->pdev->dev;
|
|
|
struct qlcnic_hardware_context *ahw;
|
|
|
- void *temp_buffer;
|
|
|
+ struct qlcnic_dump_entry *entry;
|
|
|
+ void *temp_buffer, *tmpl_hdr;
|
|
|
+ u32 ocm_window;
|
|
|
+ __le32 *buffer;
|
|
|
+ char mesg[64];
|
|
|
+ char *msg[] = {mesg, NULL};
|
|
|
|
|
|
ahw = adapter->ahw;
|
|
|
+ tmpl_hdr = fw_dump->tmpl_hdr;
|
|
|
|
|
|
/* Return if we don't have firmware dump template header */
|
|
|
if (!tmpl_hdr)
|
|
@@ -1133,8 +1251,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
|
|
|
netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n");
|
|
|
/* Calculate the size for dump data area only */
|
|
|
for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
|
|
|
- if (i & tmpl_hdr->drv_cap_mask)
|
|
|
- dump_size += tmpl_hdr->cap_sizes[k];
|
|
|
+ if (i & fw_dump->cap_mask)
|
|
|
+ dump_size += qlcnic_get_cap_size(adapter, tmpl_hdr, k);
|
|
|
+
|
|
|
if (!dump_size)
|
|
|
return -EIO;
|
|
|
|
|
@@ -1144,10 +1263,10 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
|
|
|
|
|
|
buffer = fw_dump->data;
|
|
|
fw_dump->size = dump_size;
|
|
|
- no_entries = tmpl_hdr->num_entries;
|
|
|
- entry_offset = tmpl_hdr->offset;
|
|
|
- tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
|
|
|
- tmpl_hdr->sys_info[1] = adapter->fw_version;
|
|
|
+ no_entries = fw_dump->num_entries;
|
|
|
+ entry_offset = fw_dump->offset;
|
|
|
+ qlcnic_set_sys_info(adapter, tmpl_hdr, 0, QLCNIC_DRIVER_VERSION);
|
|
|
+ qlcnic_set_sys_info(adapter, tmpl_hdr, 1, adapter->fw_version);
|
|
|
|
|
|
if (fw_dump->use_pex_dma) {
|
|
|
temp_buffer = dma_alloc_coherent(dev, QLC_PEX_DMA_READ_SIZE,
|
|
@@ -1163,16 +1282,17 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
|
|
|
ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
|
|
|
fw_dump_ops = qlcnic_fw_dump_ops;
|
|
|
} else {
|
|
|
+ hdr_83xx = tmpl_hdr;
|
|
|
ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
|
|
|
fw_dump_ops = qlcnic_83xx_fw_dump_ops;
|
|
|
- ocm_window = tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func];
|
|
|
- tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
|
|
|
- tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
|
|
|
+ ocm_window = hdr_83xx->ocm_wnd_reg[ahw->pci_func];
|
|
|
+ hdr_83xx->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
|
|
|
+ hdr_83xx->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < no_entries; i++) {
|
|
|
- entry = (void *)tmpl_hdr + entry_offset;
|
|
|
- if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
|
|
|
+ entry = tmpl_hdr + entry_offset;
|
|
|
+ if (!(entry->hdr.mask & fw_dump->cap_mask)) {
|
|
|
entry->hdr.flags |= QLCNIC_DUMP_SKIP;
|
|
|
entry_offset += entry->hdr.offset;
|
|
|
continue;
|
|
@@ -1209,8 +1329,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
|
|
|
|
|
|
fw_dump->clr = 1;
|
|
|
snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name);
|
|
|
- dev_info(dev, "%s: Dump data %d bytes captured, template header size %d bytes\n",
|
|
|
- adapter->netdev->name, fw_dump->size, tmpl_hdr->size);
|
|
|
+ netdev_info(adapter->netdev,
|
|
|
+ "Dump data %d bytes captured, template header size %d bytes\n",
|
|
|
+ fw_dump->size, fw_dump->tmpl_hdr_size);
|
|
|
/* Send a udev event to notify availability of FW dump */
|
|
|
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, msg);
|
|
|
|