aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorBartosz Markowski <bartosz.markowski@tieto.com>2013-09-26 11:47:11 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2013-09-27 07:58:14 -0400
commitb3effe61a1a3b8f20fa4b4d30c4390a6b81a6fc2 (patch)
tree24a06e9a7498870290d51dff79f8b9d6a5df60ad /drivers/net
parent08ba7b6b6f4bd6a912d0b6825f4e2d4e7fb4ddac (diff)
ath10k: implement host memory chunks
10.X firmware can request a memory pool from host to offload it's own resources. This is a feature designed especially for AP mode where the target has to deal with large number of peers. So we allocate and map a consistent DMA memory which FW can use to store e.g. peer rate contol maps. Signed-off-by: Bartosz Markowski <bartosz.markowski@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h12
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c126
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h3
3 files changed, 133 insertions, 8 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index acfee7c51b9e..e2a2658cf841 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -102,12 +102,24 @@ struct ath10k_bmi {
102 bool done_sent; 102 bool done_sent;
103}; 103};
104 104
105#define ATH10K_MAX_MEM_REQS 16
106
107struct ath10k_mem_chunk {
108 void *vaddr;
109 dma_addr_t paddr;
110 u32 len;
111 u32 req_id;
112};
113
105struct ath10k_wmi { 114struct ath10k_wmi {
106 enum ath10k_htc_ep_id eid; 115 enum ath10k_htc_ep_id eid;
107 struct completion service_ready; 116 struct completion service_ready;
108 struct completion unified_ready; 117 struct completion unified_ready;
109 wait_queue_head_t tx_credits_wq; 118 wait_queue_head_t tx_credits_wq;
110 struct wmi_cmd_map *cmd; 119 struct wmi_cmd_map *cmd;
120
121 u32 num_mem_chunks;
122 struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS];
111}; 123};
112 124
113struct ath10k_peer_stat { 125struct ath10k_peer_stat {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index ed79d325b610..97ba23e78abf 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1230,6 +1230,37 @@ static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar,
1230 ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n"); 1230 ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
1231} 1231}
1232 1232
1233static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
1234 u32 num_units, u32 unit_len)
1235{
1236 dma_addr_t paddr;
1237 u32 pool_size;
1238 int idx = ar->wmi.num_mem_chunks;
1239
1240 pool_size = num_units * round_up(unit_len, 4);
1241
1242 if (!pool_size)
1243 return -EINVAL;
1244
1245 ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev,
1246 pool_size,
1247 &paddr,
1248 GFP_ATOMIC);
1249 if (!ar->wmi.mem_chunks[idx].vaddr) {
1250 ath10k_warn("failed to allocate memory chunk\n");
1251 return -ENOMEM;
1252 }
1253
1254 memset(ar->wmi.mem_chunks[idx].vaddr, 0, pool_size);
1255
1256 ar->wmi.mem_chunks[idx].paddr = paddr;
1257 ar->wmi.mem_chunks[idx].len = pool_size;
1258 ar->wmi.mem_chunks[idx].req_id = req_id;
1259 ar->wmi.num_mem_chunks++;
1260
1261 return 0;
1262}
1263
1233static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, 1264static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
1234 struct sk_buff *skb) 1265 struct sk_buff *skb)
1235{ 1266{
@@ -1304,6 +1335,8 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
1304static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, 1335static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
1305 struct sk_buff *skb) 1336 struct sk_buff *skb)
1306{ 1337{
1338 u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
1339 int ret;
1307 struct wmi_service_ready_event_10x *ev = (void *)skb->data; 1340 struct wmi_service_ready_event_10x *ev = (void *)skb->data;
1308 1341
1309 if (skb->len < sizeof(*ev)) { 1342 if (skb->len < sizeof(*ev)) {
@@ -1342,13 +1375,50 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
1342 ar->fw_version_minor); 1375 ar->fw_version_minor);
1343 } 1376 }
1344 1377
1345 /* FIXME: it probably should be better to support this. 1378 num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs);
1346 TODO: Next patch introduce memory chunks. It's a must for 10.x FW */ 1379
1347 if (__le32_to_cpu(ev->num_mem_reqs) > 0) { 1380 if (num_mem_reqs > ATH10K_MAX_MEM_REQS) {
1348 ath10k_warn("target requested %d memory chunks; ignoring\n", 1381 ath10k_warn("requested memory chunks number (%d) exceeds the limit\n",
1349 __le32_to_cpu(ev->num_mem_reqs)); 1382 num_mem_reqs);
1383 return;
1350 } 1384 }
1351 1385
1386 if (!num_mem_reqs)
1387 goto exit;
1388
1389 ath10k_dbg(ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
1390 num_mem_reqs);
1391
1392 for (i = 0; i < num_mem_reqs; ++i) {
1393 req_id = __le32_to_cpu(ev->mem_reqs[i].req_id);
1394 num_units = __le32_to_cpu(ev->mem_reqs[i].num_units);
1395 unit_size = __le32_to_cpu(ev->mem_reqs[i].unit_size);
1396 num_unit_info = __le32_to_cpu(ev->mem_reqs[i].num_unit_info);
1397
1398 if (num_unit_info & NUM_UNITS_IS_NUM_PEERS)
1399 /* number of units to allocate is number of
1400 * peers, 1 extra for self peer on target */
1401 /* this needs to be tied, host and target
1402 * can get out of sync */
1403 num_units = TARGET_NUM_PEERS + 1;
1404 else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS)
1405 num_units = TARGET_NUM_VDEVS + 1;
1406
1407 ath10k_dbg(ATH10K_DBG_WMI,
1408 "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n",
1409 req_id,
1410 __le32_to_cpu(ev->mem_reqs[i].num_units),
1411 num_unit_info,
1412 unit_size,
1413 num_units);
1414
1415 ret = ath10k_wmi_alloc_host_mem(ar, req_id, num_units,
1416 unit_size);
1417 if (ret)
1418 return;
1419 }
1420
1421exit:
1352 ath10k_dbg(ATH10K_DBG_WMI, 1422 ath10k_dbg(ATH10K_DBG_WMI,
1353 "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n", 1423 "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
1354 __le32_to_cpu(ev->sw_version), 1424 __le32_to_cpu(ev->sw_version),
@@ -1645,6 +1715,17 @@ int ath10k_wmi_attach(struct ath10k *ar)
1645 1715
1646void ath10k_wmi_detach(struct ath10k *ar) 1716void ath10k_wmi_detach(struct ath10k *ar)
1647{ 1717{
1718 int i;
1719
1720 /* free the host memory chunks requested by firmware */
1721 for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
1722 dma_free_coherent(ar->dev,
1723 ar->wmi.mem_chunks[i].len,
1724 ar->wmi.mem_chunks[i].vaddr,
1725 ar->wmi.mem_chunks[i].paddr);
1726 }
1727
1728 ar->wmi.num_mem_chunks = 0;
1648} 1729}
1649 1730
1650int ath10k_wmi_connect_htc_service(struct ath10k *ar) 1731int ath10k_wmi_connect_htc_service(struct ath10k *ar)
@@ -1781,7 +1862,8 @@ int ath10k_wmi_cmd_init(struct ath10k *ar)
1781 struct wmi_init_cmd *cmd; 1862 struct wmi_init_cmd *cmd;
1782 struct sk_buff *buf; 1863 struct sk_buff *buf;
1783 struct wmi_resource_config config = {}; 1864 struct wmi_resource_config config = {};
1784 u32 val; 1865 u32 len, val;
1866 int i;
1785 1867
1786 config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); 1868 config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);
1787 config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS); 1869 config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS);
@@ -1834,12 +1916,40 @@ int ath10k_wmi_cmd_init(struct ath10k *ar)
1834 config.num_msdu_desc = __cpu_to_le32(TARGET_NUM_MSDU_DESC); 1916 config.num_msdu_desc = __cpu_to_le32(TARGET_NUM_MSDU_DESC);
1835 config.max_frag_entries = __cpu_to_le32(TARGET_MAX_FRAG_ENTRIES); 1917 config.max_frag_entries = __cpu_to_le32(TARGET_MAX_FRAG_ENTRIES);
1836 1918
1837 buf = ath10k_wmi_alloc_skb(sizeof(*cmd)); 1919 len = sizeof(*cmd) +
1920 (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
1921
1922 buf = ath10k_wmi_alloc_skb(len);
1838 if (!buf) 1923 if (!buf)
1839 return -ENOMEM; 1924 return -ENOMEM;
1840 1925
1841 cmd = (struct wmi_init_cmd *)buf->data; 1926 cmd = (struct wmi_init_cmd *)buf->data;
1842 cmd->num_host_mem_chunks = 0; 1927
1928 if (ar->wmi.num_mem_chunks == 0) {
1929 cmd->num_host_mem_chunks = 0;
1930 goto out;
1931 }
1932
1933 ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
1934 __cpu_to_le32(ar->wmi.num_mem_chunks));
1935
1936 cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
1937
1938 for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
1939 cmd->host_mem_chunks[i].ptr =
1940 __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
1941 cmd->host_mem_chunks[i].size =
1942 __cpu_to_le32(ar->wmi.mem_chunks[i].len);
1943 cmd->host_mem_chunks[i].req_id =
1944 __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
1945
1946 ath10k_dbg(ATH10K_DBG_WMI,
1947 "wmi chunk %d len %d requested, addr 0x%x\n",
1948 i,
1949 cmd->host_mem_chunks[i].size,
1950 cmd->host_mem_chunks[i].ptr);
1951 }
1952out:
1843 memcpy(&cmd->resource_config, &config, sizeof(config)); 1953 memcpy(&cmd->resource_config, &config, sizeof(config));
1844 1954
1845 ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n"); 1955 ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n");
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index a0cfdfd87faf..56339d2e338a 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -1377,6 +1377,9 @@ struct wmi_resource_config {
1377 __le32 max_frag_entries; 1377 __le32 max_frag_entries;
1378} __packed; 1378} __packed;
1379 1379
1380#define NUM_UNITS_IS_NUM_VDEVS 0x1
1381#define NUM_UNITS_IS_NUM_PEERS 0x2
1382
1380/* strucutre describing host memory chunk. */ 1383/* strucutre describing host memory chunk. */
1381struct host_memory_chunk { 1384struct host_memory_chunk {
1382 /* id of the request that is passed up in service ready */ 1385 /* id of the request that is passed up in service ready */