diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie')
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/internal.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/trans.c | 125 |
2 files changed, 128 insertions, 4 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 6c22b23a2845..78f72c34438a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -260,6 +260,9 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) | |||
260 | * @wd_timeout: queue watchdog timeout (jiffies) | 260 | * @wd_timeout: queue watchdog timeout (jiffies) |
261 | * @reg_lock: protect hw register access | 261 | * @reg_lock: protect hw register access |
262 | * @cmd_in_flight: true when we have a host command in flight | 262 | * @cmd_in_flight: true when we have a host command in flight |
263 | * @fw_mon_phys: physical address of the buffer for the firmware monitor | ||
264 | * @fw_mon_page: points to the first page of the buffer for the firmware monitor | ||
265 | * @fw_mon_size: size of the buffer for the firmware monitor | ||
263 | */ | 266 | */ |
264 | struct iwl_trans_pcie { | 267 | struct iwl_trans_pcie { |
265 | struct iwl_rxq rxq; | 268 | struct iwl_rxq rxq; |
@@ -312,6 +315,10 @@ struct iwl_trans_pcie { | |||
312 | /*protect hw register */ | 315 | /*protect hw register */ |
313 | spinlock_t reg_lock; | 316 | spinlock_t reg_lock; |
314 | bool cmd_in_flight; | 317 | bool cmd_in_flight; |
318 | |||
319 | dma_addr_t fw_mon_phys; | ||
320 | struct page *fw_mon_page; | ||
321 | u32 fw_mon_size; | ||
315 | }; | 322 | }; |
316 | 323 | ||
317 | #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ | 324 | #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 788085bc65d7..3ffac4888c12 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -76,6 +76,68 @@ | |||
76 | #include "iwl-fw-error-dump.h" | 76 | #include "iwl-fw-error-dump.h" |
77 | #include "internal.h" | 77 | #include "internal.h" |
78 | 78 | ||
79 | static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) | ||
80 | { | ||
81 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
82 | |||
83 | if (!trans_pcie->fw_mon_page) | ||
84 | return; | ||
85 | |||
86 | dma_unmap_page(trans->dev, trans_pcie->fw_mon_phys, | ||
87 | trans_pcie->fw_mon_size, DMA_FROM_DEVICE); | ||
88 | __free_pages(trans_pcie->fw_mon_page, | ||
89 | get_order(trans_pcie->fw_mon_size)); | ||
90 | trans_pcie->fw_mon_page = NULL; | ||
91 | trans_pcie->fw_mon_phys = 0; | ||
92 | trans_pcie->fw_mon_size = 0; | ||
93 | } | ||
94 | |||
95 | static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans) | ||
96 | { | ||
97 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
98 | struct page *page; | ||
99 | dma_addr_t phys; | ||
100 | u32 size; | ||
101 | u8 power; | ||
102 | |||
103 | if (trans_pcie->fw_mon_page) { | ||
104 | dma_sync_single_for_device(trans->dev, trans_pcie->fw_mon_phys, | ||
105 | trans_pcie->fw_mon_size, | ||
106 | DMA_FROM_DEVICE); | ||
107 | return; | ||
108 | } | ||
109 | |||
110 | phys = 0; | ||
111 | for (power = 26; power >= 11; power--) { | ||
112 | int order; | ||
113 | |||
114 | size = BIT(power); | ||
115 | order = get_order(size); | ||
116 | page = alloc_pages(__GFP_COMP | __GFP_NOWARN | __GFP_ZERO, | ||
117 | order); | ||
118 | if (!page) | ||
119 | continue; | ||
120 | |||
121 | phys = dma_map_page(trans->dev, page, 0, PAGE_SIZE << order, | ||
122 | DMA_FROM_DEVICE); | ||
123 | if (dma_mapping_error(trans->dev, phys)) { | ||
124 | __free_pages(page, order); | ||
125 | continue; | ||
126 | } | ||
127 | IWL_INFO(trans, | ||
128 | "Allocated 0x%08x bytes (order %d) for firmware monitor.\n", | ||
129 | size, order); | ||
130 | break; | ||
131 | } | ||
132 | |||
133 | if (!page) | ||
134 | return; | ||
135 | |||
136 | trans_pcie->fw_mon_page = page; | ||
137 | trans_pcie->fw_mon_phys = phys; | ||
138 | trans_pcie->fw_mon_size = size; | ||
139 | } | ||
140 | |||
79 | static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) | 141 | static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) |
80 | { | 142 | { |
81 | iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, | 143 | iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, |
@@ -675,6 +737,7 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, | |||
675 | static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | 737 | static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, |
676 | const struct fw_img *image) | 738 | const struct fw_img *image) |
677 | { | 739 | { |
740 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
678 | int ret = 0; | 741 | int ret = 0; |
679 | int first_ucode_section; | 742 | int first_ucode_section; |
680 | 743 | ||
@@ -733,6 +796,20 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | |||
733 | return ret; | 796 | return ret; |
734 | } | 797 | } |
735 | 798 | ||
799 | /* supported for 7000 only for the moment */ | ||
800 | if (iwlwifi_mod_params.fw_monitor && | ||
801 | trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | ||
802 | iwl_pcie_alloc_fw_monitor(trans); | ||
803 | |||
804 | if (trans_pcie->fw_mon_size) { | ||
805 | iwl_write_prph(trans, MON_BUFF_BASE_ADDR, | ||
806 | trans_pcie->fw_mon_phys >> 4); | ||
807 | iwl_write_prph(trans, MON_BUFF_END_ADDR, | ||
808 | (trans_pcie->fw_mon_phys + | ||
809 | trans_pcie->fw_mon_size) >> 4); | ||
810 | } | ||
811 | } | ||
812 | |||
736 | /* release CPU reset */ | 813 | /* release CPU reset */ |
737 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | 814 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) |
738 | iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); | 815 | iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); |
@@ -1126,6 +1203,8 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) | |||
1126 | if (trans_pcie->napi.poll) | 1203 | if (trans_pcie->napi.poll) |
1127 | netif_napi_del(&trans_pcie->napi); | 1204 | netif_napi_del(&trans_pcie->napi); |
1128 | 1205 | ||
1206 | iwl_pcie_free_fw_monitor(trans); | ||
1207 | |||
1129 | kfree(trans); | 1208 | kfree(trans); |
1130 | } | 1209 | } |
1131 | 1210 | ||
@@ -1698,10 +1777,15 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, | |||
1698 | u32 len; | 1777 | u32 len; |
1699 | int i, ptr; | 1778 | int i, ptr; |
1700 | 1779 | ||
1780 | len = sizeof(*data) + | ||
1781 | cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); | ||
1782 | |||
1783 | if (trans_pcie->fw_mon_page) | ||
1784 | len += sizeof(*data) + sizeof(struct iwl_fw_error_fw_mon) + | ||
1785 | trans_pcie->fw_mon_size; | ||
1786 | |||
1701 | if (!buf) | 1787 | if (!buf) |
1702 | return sizeof(*data) + | 1788 | return len; |
1703 | cmdq->q.n_window * (sizeof(*txcmd) + | ||
1704 | TFD_MAX_PAYLOAD_SIZE); | ||
1705 | 1789 | ||
1706 | len = 0; | 1790 | len = 0; |
1707 | data = buf; | 1791 | data = buf; |
@@ -1729,7 +1813,40 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, | |||
1729 | spin_unlock_bh(&cmdq->lock); | 1813 | spin_unlock_bh(&cmdq->lock); |
1730 | 1814 | ||
1731 | data->len = cpu_to_le32(len); | 1815 | data->len = cpu_to_le32(len); |
1732 | return sizeof(*data) + len; | 1816 | len += sizeof(*data); |
1817 | |||
1818 | if (trans_pcie->fw_mon_page) { | ||
1819 | struct iwl_fw_error_fw_mon *fw_mon_data; | ||
1820 | |||
1821 | data = iwl_fw_error_next_data(data); | ||
1822 | data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); | ||
1823 | data->len = cpu_to_le32(trans_pcie->fw_mon_size + | ||
1824 | sizeof(*fw_mon_data)); | ||
1825 | fw_mon_data = (void *)data->data; | ||
1826 | fw_mon_data->fw_mon_wr_ptr = | ||
1827 | cpu_to_le32(iwl_read_prph(trans, MON_BUFF_WRPTR)); | ||
1828 | fw_mon_data->fw_mon_cycle_cnt = | ||
1829 | cpu_to_le32(iwl_read_prph(trans, MON_BUFF_CYCLE_CNT)); | ||
1830 | fw_mon_data->fw_mon_base_ptr = | ||
1831 | cpu_to_le32(iwl_read_prph(trans, MON_BUFF_BASE_ADDR)); | ||
1832 | |||
1833 | /* | ||
1834 | * The firmware is now asserted, it won't write anything to | ||
1835 | * the buffer. CPU can take ownership to fetch the data. | ||
1836 | * The buffer will be handed back to the device before the | ||
1837 | * firmware will be restarted. | ||
1838 | */ | ||
1839 | dma_sync_single_for_cpu(trans->dev, trans_pcie->fw_mon_phys, | ||
1840 | trans_pcie->fw_mon_size, | ||
1841 | DMA_FROM_DEVICE); | ||
1842 | memcpy(fw_mon_data->data, page_address(trans_pcie->fw_mon_page), | ||
1843 | trans_pcie->fw_mon_size); | ||
1844 | |||
1845 | len += sizeof(*data) + sizeof(*fw_mon_data) + | ||
1846 | trans_pcie->fw_mon_size; | ||
1847 | } | ||
1848 | |||
1849 | return len; | ||
1733 | } | 1850 | } |
1734 | #else | 1851 | #else |
1735 | static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, | 1852 | static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, |