Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / net / wireless / ath / wil6210 / ioctl.c
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
27 static 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
58 static 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
102 static 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
157 out_free:
158         kfree(block);
159         return rc;
160 }
161
162 int 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 }