aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>2014-10-01 08:05:25 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-10-02 14:23:14 -0400
commitdba4b74d2da8798626e2b702ad3f452671e335f7 (patch)
tree0b69811380cfc1aa121c5fd481c77829b830436d
parentc33407a8c50430f1634a8809f9528b6888360e56 (diff)
wil6210: atomic I/O for the card memory
Introduce netdev IOCTLs, to be used by the debug tools. Allows to read/write single dword value or memory block, aligned to dword Different address modes supported: - BAR offset - Firmware "linker" address - target's AHB bus Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile1
-rw-r--r--drivers/net/wireless/ath/wil6210/ioctl.c173
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c12
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h2
-rw-r--r--include/uapi/linux/wil6210_uapi.h87
6 files changed, 276 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 482888d80431..66de6b2923d4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1611,6 +1611,7 @@ L: wil6210@qca.qualcomm.com
1611S: Supported 1611S: Supported
1612W: http://wireless.kernel.org/en/users/Drivers/wil6210 1612W: http://wireless.kernel.org/en/users/Drivers/wil6210
1613F: drivers/net/wireless/ath/wil6210/ 1613F: drivers/net/wireless/ath/wil6210/
1614F: include/uapi/linux/wil6210_uapi.h
1614 1615
1615CARL9170 LINUX COMMUNITY WIRELESS DRIVER 1616CARL9170 LINUX COMMUNITY WIRELESS DRIVER
1616M: Christian Lamparter <chunkeey@googlemail.com> 1617M: Christian Lamparter <chunkeey@googlemail.com>
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index 05f29a6b1ba8..8ad4b5f97e04 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -10,6 +10,7 @@ wil6210-y += interrupt.o
10wil6210-y += txrx.o 10wil6210-y += txrx.o
11wil6210-y += debug.o 11wil6210-y += debug.o
12wil6210-y += rx_reorder.o 12wil6210-y += rx_reorder.o
13wil6210-y += ioctl.o
13wil6210-y += fw.o 14wil6210-y += fw.o
14wil6210-$(CONFIG_WIL6210_TRACING) += trace.o 15wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
15wil6210-y += wil_platform.o 16wil6210-y += wil_platform.o
diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c
new file mode 100644
index 000000000000..e9c0673819c6
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/ioctl.c
@@ -0,0 +1,173 @@
1/*
2 * Copyright (c) 2014 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/uaccess.h>
18
19#include "wil6210.h"
20#include <uapi/linux/wil6210_uapi.h>
21
22#define wil_hex_dump_ioctl(prefix_str, buf, len) \
23 print_hex_dump_debug("DBG[IOC ]" prefix_str, \
24 DUMP_PREFIX_OFFSET, 16, 1, buf, len, true)
25#define wil_dbg_ioctl(wil, fmt, arg...) wil_dbg(wil, "DBG[IOC ]" fmt, ##arg)
26
27static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr,
28 uint32_t size, enum wil_memio_op op)
29{
30 void __iomem *a;
31 u32 off;
32
33 switch (op & wil_mmio_addr_mask) {
34 case wil_mmio_addr_linker:
35 a = wmi_buffer(wil, cpu_to_le32(addr));
36 break;
37 case wil_mmio_addr_ahb:
38 a = wmi_addr(wil, addr);
39 break;
40 case wil_mmio_addr_bar:
41 a = wmi_addr(wil, addr + WIL6210_FW_HOST_OFF);
42 break;
43 default:
44 wil_err(wil, "Unsupported address mode, op = 0x%08x\n", op);
45 return NULL;
46 }
47
48 off = a - wil->csr;
49 if (size >= WIL6210_MEM_SIZE - off) {
50 wil_err(wil, "Requested block does not fit into memory: "
51 "off = 0x%08x size = 0x%08x\n", off, size);
52 return NULL;
53 }
54
55 return a;
56}
57
58static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data)
59{
60 struct wil_memio io;
61 void __iomem *a;
62 bool need_copy = false;
63
64 if (copy_from_user(&io, data, sizeof(io)))
65 return -EFAULT;
66
67 wil_dbg_ioctl(wil, "IO: addr = 0x%08x val = 0x%08x op = 0x%08x\n",
68 io.addr, io.val, io.op);
69
70 a = wil_ioc_addr(wil, io.addr, sizeof(u32), io.op);
71 if (!a) {
72 wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr,
73 io.op);
74 return -EINVAL;
75 }
76 /* operation */
77 switch (io.op & wil_mmio_op_mask) {
78 case wil_mmio_read:
79 io.val = ioread32(a);
80 need_copy = true;
81 break;
82 case wil_mmio_write:
83 iowrite32(io.val, a);
84 wmb(); /* make sure write propagated to HW */
85 break;
86 default:
87 wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
88 return -EINVAL;
89 }
90
91 if (need_copy) {
92 wil_dbg_ioctl(wil, "IO done: addr = 0x%08x"
93 " val = 0x%08x op = 0x%08x\n",
94 io.addr, io.val, io.op);
95 if (copy_to_user(data, &io, sizeof(io)))
96 return -EFAULT;
97 }
98
99 return 0;
100}
101
102static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data)
103{
104 struct wil_memio_block io;
105 void *block;
106 void __iomem *a;
107 int rc = 0;
108
109 if (copy_from_user(&io, data, sizeof(io)))
110 return -EFAULT;
111
112 wil_dbg_ioctl(wil, "IO: addr = 0x%08x size = 0x%08x op = 0x%08x\n",
113 io.addr, io.size, io.op);
114
115 /* size */
116 if (io.size % 4) {
117 wil_err(wil, "size is not multiple of 4: 0x%08x\n", io.size);
118 return -EINVAL;
119 }
120
121 a = wil_ioc_addr(wil, io.addr, io.size, io.op);
122 if (!a) {
123 wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr,
124 io.op);
125 return -EINVAL;
126 }
127
128 block = kmalloc(io.size, GFP_USER);
129 if (!block)
130 return -ENOMEM;
131
132 /* operation */
133 switch (io.op & wil_mmio_op_mask) {
134 case wil_mmio_read:
135 wil_memcpy_fromio_32(block, a, io.size);
136 wil_hex_dump_ioctl("Read ", block, io.size);
137 if (copy_to_user(io.block, block, io.size)) {
138 rc = -EFAULT;
139 goto out_free;
140 }
141 break;
142 case wil_mmio_write:
143 if (copy_from_user(block, io.block, io.size)) {
144 rc = -EFAULT;
145 goto out_free;
146 }
147 wil_memcpy_toio_32(a, block, io.size);
148 wmb(); /* make sure write propagated to HW */
149 wil_hex_dump_ioctl("Write ", block, io.size);
150 break;
151 default:
152 wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
153 rc = -EINVAL;
154 break;
155 }
156
157out_free:
158 kfree(block);
159 return rc;
160}
161
162int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd)
163{
164 switch (cmd) {
165 case WIL_IOCTL_MEMIO:
166 return wil_ioc_memio_dword(wil, data);
167 case WIL_IOCTL_MEMIO_BLOCK:
168 return wil_ioc_memio_block(wil, data);
169 default:
170 wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd);
171 return -ENOIOCTLCMD;
172 }
173}
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index c3f0ddfaa5da..239965106c05 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -52,6 +52,17 @@ static int wil_change_mtu(struct net_device *ndev, int new_mtu)
52 return 0; 52 return 0;
53} 53}
54 54
55static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
56{
57 struct wil6210_priv *wil = ndev_to_wil(ndev);
58
59 int ret = wil_ioctl(wil, ifr->ifr_data, cmd);
60
61 wil_dbg_misc(wil, "ioctl(0x%04x) -> %d\n", cmd, ret);
62
63 return ret;
64}
65
55static const struct net_device_ops wil_netdev_ops = { 66static const struct net_device_ops wil_netdev_ops = {
56 .ndo_open = wil_open, 67 .ndo_open = wil_open,
57 .ndo_stop = wil_stop, 68 .ndo_stop = wil_stop,
@@ -59,6 +70,7 @@ static const struct net_device_ops wil_netdev_ops = {
59 .ndo_set_mac_address = eth_mac_addr, 70 .ndo_set_mac_address = eth_mac_addr,
60 .ndo_validate_addr = eth_validate_addr, 71 .ndo_validate_addr = eth_validate_addr,
61 .ndo_change_mtu = wil_change_mtu, 72 .ndo_change_mtu = wil_change_mtu,
73 .ndo_do_ioctl = wil_do_ioctl,
62}; 74};
63 75
64static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) 76static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 2991609885f7..61cceca155a2 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -595,5 +595,7 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
595 595
596int wil_iftype_nl2wmi(enum nl80211_iftype type); 596int wil_iftype_nl2wmi(enum nl80211_iftype type);
597 597
598int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);
598int wil_request_firmware(struct wil6210_priv *wil, const char *name); 599int wil_request_firmware(struct wil6210_priv *wil, const char *name);
600
599#endif /* __WIL6210_H__ */ 601#endif /* __WIL6210_H__ */
diff --git a/include/uapi/linux/wil6210_uapi.h b/include/uapi/linux/wil6210_uapi.h
new file mode 100644
index 000000000000..6a3cddd156c4
--- /dev/null
+++ b/include/uapi/linux/wil6210_uapi.h
@@ -0,0 +1,87 @@
1/*
2 * Copyright (c) 2014 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef __WIL6210_UAPI_H__
18#define __WIL6210_UAPI_H__
19
20#if !defined(__KERNEL__)
21#define __user
22#endif
23
24#include <linux/sockios.h>
25
26/* Numbers SIOCDEVPRIVATE and SIOCDEVPRIVATE + 1
27 * are used by Android devices to implement PNO (preferred network offload).
28 * Albeit it is temporary solution, use different numbers to avoid conflicts
29 */
30
31/**
32 * Perform 32-bit I/O operation to the card memory
33 *
34 * User code should arrange data in memory like this:
35 *
36 * struct wil_memio io;
37 * struct ifreq ifr = {
38 * .ifr_data = &io,
39 * };
40 */
41#define WIL_IOCTL_MEMIO (SIOCDEVPRIVATE + 2)
42
43/**
44 * Perform block I/O operation to the card memory
45 *
46 * User code should arrange data in memory like this:
47 *
48 * void *buf;
49 * struct wil_memio_block io = {
50 * .block = buf,
51 * };
52 * struct ifreq ifr = {
53 * .ifr_data = &io,
54 * };
55 */
56#define WIL_IOCTL_MEMIO_BLOCK (SIOCDEVPRIVATE + 3)
57
58/**
59 * operation to perform
60 *
61 * @wil_mmio_op_mask - bits defining operation,
62 * @wil_mmio_addr_mask - bits defining addressing mode
63 */
64enum wil_memio_op {
65 wil_mmio_read = 0,
66 wil_mmio_write = 1,
67 wil_mmio_op_mask = 0xff,
68 wil_mmio_addr_linker = 0 << 8,
69 wil_mmio_addr_ahb = 1 << 8,
70 wil_mmio_addr_bar = 2 << 8,
71 wil_mmio_addr_mask = 0xff00,
72};
73
74struct wil_memio {
75 uint32_t op; /* enum wil_memio_op */
76 uint32_t addr; /* should be 32-bit aligned */
77 uint32_t val;
78};
79
80struct wil_memio_block {
81 uint32_t op; /* enum wil_memio_op */
82 uint32_t addr; /* should be 32-bit aligned */
83 uint32_t size; /* should be multiple of 4 */
84 void __user *block; /* block address */
85};
86
87#endif /* __WIL6210_UAPI_H__ */