]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/blobdiff - drivers/net/wireless/intel/iwlwifi/pcie/trans.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[mirror_ubuntu-disco-kernel.git] / drivers / net / wireless / intel / iwlwifi / pcie / trans.c
index 9ad3f4fe589417ed752e397554575fdc4553fb0e..b7a51603465b20752616639cd3f663a6844dcdd8 100644 (file)
 #define IWL_FW_MEM_EXTENDED_START      0x40000
 #define IWL_FW_MEM_EXTENDED_END                0x57FFF
 
+static void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
+{
+#define PCI_DUMP_SIZE  64
+#define PREFIX_LEN     32
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct pci_dev *pdev = trans_pcie->pci_dev;
+       u32 i, pos, alloc_size, *ptr, *buf;
+       char *prefix;
+
+       if (trans_pcie->pcie_dbg_dumped_once)
+               return;
+
+       /* Should be a multiple of 4 */
+       BUILD_BUG_ON(PCI_DUMP_SIZE > 4096 || PCI_DUMP_SIZE & 0x3);
+       /* Alloc a max size buffer */
+       if (PCI_ERR_ROOT_ERR_SRC +  4 > PCI_DUMP_SIZE)
+               alloc_size = PCI_ERR_ROOT_ERR_SRC +  4 + PREFIX_LEN;
+       else
+               alloc_size = PCI_DUMP_SIZE + PREFIX_LEN;
+       buf = kmalloc(alloc_size, GFP_ATOMIC);
+       if (!buf)
+               return;
+       prefix = (char *)buf + alloc_size - PREFIX_LEN;
+
+       IWL_ERR(trans, "iwlwifi transaction failed, dumping registers\n");
+
+       /* Print wifi device registers */
+       sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
+       IWL_ERR(trans, "iwlwifi device config registers:\n");
+       for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
+               if (pci_read_config_dword(pdev, i, ptr))
+                       goto err_read;
+       print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
+
+       IWL_ERR(trans, "iwlwifi device memory mapped registers:\n");
+       for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
+               *ptr = iwl_read32(trans, i);
+       print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
+
+       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
+       if (pos) {
+               IWL_ERR(trans, "iwlwifi device AER capability structure:\n");
+               for (i = 0, ptr = buf; i < PCI_ERR_ROOT_COMMAND; i += 4, ptr++)
+                       if (pci_read_config_dword(pdev, pos + i, ptr))
+                               goto err_read;
+               print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
+                              32, 4, buf, i, 0);
+       }
+
+       /* Print parent device registers next */
+       if (!pdev->bus->self)
+               goto out;
+
+       pdev = pdev->bus->self;
+       sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
+
+       IWL_ERR(trans, "iwlwifi parent port (%s) config registers:\n",
+               pci_name(pdev));
+       for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
+               if (pci_read_config_dword(pdev, i, ptr))
+                       goto err_read;
+       print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
+
+       /* Print root port AER registers */
+       pos = 0;
+       pdev = pcie_find_root_port(pdev);
+       if (pdev)
+               pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
+       if (pos) {
+               IWL_ERR(trans, "iwlwifi root port (%s) AER cap structure:\n",
+                       pci_name(pdev));
+               sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
+               for (i = 0, ptr = buf; i <= PCI_ERR_ROOT_ERR_SRC; i += 4, ptr++)
+                       if (pci_read_config_dword(pdev, pos + i, ptr))
+                               goto err_read;
+               print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32,
+                              4, buf, i, 0);
+       }
+
+err_read:
+       print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
+       IWL_ERR(trans, "Read failed at 0x%X\n", i);
+out:
+       trans_pcie->pcie_dbg_dumped_once = 1;
+       kfree(buf);
+}
+
 static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -649,6 +736,7 @@ static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans,
                                 trans_pcie->ucode_write_complete, 5 * HZ);
        if (!ret) {
                IWL_ERR(trans, "Failed to load firmware chunk!\n");
+               iwl_trans_pcie_dump_regs(trans);
                return -ETIMEDOUT;
        }
 
@@ -1868,6 +1956,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans,
                           (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
                            CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
        if (unlikely(ret < 0)) {
+               iwl_trans_pcie_dump_regs(trans);
                iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
                WARN_ONCE(1,
                          "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
@@ -2932,6 +3021,7 @@ static void iwl_trans_pcie_resume(struct iwl_trans *trans)
        .ref = iwl_trans_pcie_ref,                                      \
        .unref = iwl_trans_pcie_unref,                                  \
        .dump_data = iwl_trans_pcie_dump_data,                          \
+       .dump_regs = iwl_trans_pcie_dump_regs,                          \
        .d3_suspend = iwl_trans_pcie_d3_suspend,                        \
        .d3_resume = iwl_trans_pcie_d3_resume