Linux 4.4.145
[linux/fpc-iii.git] / drivers / net / wireless / ath / wil6210 / ioctl.c
blobf7f9486219516f3d8d713d0377fa574bb5eb1ec9
1 /*
2 * Copyright (c) 2014 Qualcomm Atheros, Inc.
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.
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.
17 #include <linux/uaccess.h>
19 #include "wil6210.h"
20 #include <uapi/linux/wil6210_uapi.h>
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)
27 static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr,
28 uint32_t size, enum wil_memio_op op)
30 void __iomem *a;
31 u32 off;
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;
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;
55 return a;
58 static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data)
60 struct wil_memio io;
61 void __iomem *a;
62 bool need_copy = false;
64 if (copy_from_user(&io, data, sizeof(io)))
65 return -EFAULT;
67 wil_dbg_ioctl(wil, "IO: addr = 0x%08x val = 0x%08x op = 0x%08x\n",
68 io.addr, io.val, io.op);
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;
76 /* operation */
77 switch (io.op & wil_mmio_op_mask) {
78 case wil_mmio_read:
79 io.val = readl(a);
80 need_copy = true;
81 break;
82 case wil_mmio_write:
83 writel(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;
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;
99 return 0;
102 static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data)
104 struct wil_memio_block io;
105 void *block;
106 void __iomem *a;
107 int rc = 0;
109 if (copy_from_user(&io, data, sizeof(io)))
110 return -EFAULT;
112 wil_dbg_ioctl(wil, "IO: addr = 0x%08x size = 0x%08x op = 0x%08x\n",
113 io.addr, io.size, io.op);
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;
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;
128 block = kmalloc(io.size, GFP_USER);
129 if (!block)
130 return -ENOMEM;
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;
141 break;
142 case wil_mmio_write:
143 if (copy_from_user(block, io.block, io.size)) {
144 rc = -EFAULT;
145 goto out_free;
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;
157 out_free:
158 kfree(block);
159 return rc;
162 int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd)
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;