aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/pcie
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-06-01 01:05:52 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-06-24 14:55:27 -0400
commitc2d202017da18ebd6567862bd9a50392970f048f (patch)
tree538cd364c5bf39d0a1b230dbbfdb935e2280f147 /drivers/net/wireless/iwlwifi/pcie
parent1fa1605648d15d42f350807279b6c6e8d33b6382 (diff)
iwlwifi: pcie: add firmware monitor capabilities
This allows to use the firmware monitor. This capability uses a lot of contiguous memory (up to 64MB), so make its usage module parameter dependent. The driver will try to allocate as much contiguous memory as possible downgrading its requirements until the allocation succeeds. Dump this data into the fw-error dump file when an error happens. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h7
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c125
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 */
264struct iwl_trans_pcie { 267struct 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
79static 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
95static 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
79static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) 141static 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,
675static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, 737static 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
1735static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, 1852static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,