ioctl.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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. #include <linux/uaccess.h>
  17. #include "wil6210.h"
  18. #include <uapi/linux/wil6210_uapi.h>
  19. #define wil_hex_dump_ioctl(prefix_str, buf, len) \
  20. print_hex_dump_debug("DBG[IOC ]" prefix_str, \
  21. DUMP_PREFIX_OFFSET, 16, 1, buf, len, true)
  22. #define wil_dbg_ioctl(wil, fmt, arg...) wil_dbg(wil, "DBG[IOC ]" fmt, ##arg)
  23. static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr,
  24. uint32_t size, enum wil_memio_op op)
  25. {
  26. void __iomem *a;
  27. u32 off;
  28. switch (op & wil_mmio_addr_mask) {
  29. case wil_mmio_addr_linker:
  30. a = wmi_buffer(wil, cpu_to_le32(addr));
  31. break;
  32. case wil_mmio_addr_ahb:
  33. a = wmi_addr(wil, addr);
  34. break;
  35. case wil_mmio_addr_bar:
  36. a = wmi_addr(wil, addr + WIL6210_FW_HOST_OFF);
  37. break;
  38. default:
  39. wil_err(wil, "Unsupported address mode, op = 0x%08x\n", op);
  40. return NULL;
  41. }
  42. off = a - wil->csr;
  43. if (size >= WIL6210_MEM_SIZE - off) {
  44. wil_err(wil, "Requested block does not fit into memory: "
  45. "off = 0x%08x size = 0x%08x\n", off, size);
  46. return NULL;
  47. }
  48. return a;
  49. }
  50. static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data)
  51. {
  52. struct wil_memio io;
  53. void __iomem *a;
  54. bool need_copy = false;
  55. if (copy_from_user(&io, data, sizeof(io)))
  56. return -EFAULT;
  57. wil_dbg_ioctl(wil, "IO: addr = 0x%08x val = 0x%08x op = 0x%08x\n",
  58. io.addr, io.val, io.op);
  59. a = wil_ioc_addr(wil, io.addr, sizeof(u32), io.op);
  60. if (!a) {
  61. wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr,
  62. io.op);
  63. return -EINVAL;
  64. }
  65. /* operation */
  66. switch (io.op & wil_mmio_op_mask) {
  67. case wil_mmio_read:
  68. io.val = readl(a);
  69. need_copy = true;
  70. break;
  71. case wil_mmio_write:
  72. writel(io.val, a);
  73. wmb(); /* make sure write propagated to HW */
  74. break;
  75. default:
  76. wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
  77. return -EINVAL;
  78. }
  79. if (need_copy) {
  80. wil_dbg_ioctl(wil, "IO done: addr = 0x%08x"
  81. " val = 0x%08x op = 0x%08x\n",
  82. io.addr, io.val, io.op);
  83. if (copy_to_user(data, &io, sizeof(io)))
  84. return -EFAULT;
  85. }
  86. return 0;
  87. }
  88. static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data)
  89. {
  90. struct wil_memio_block io;
  91. void *block;
  92. void __iomem *a;
  93. int rc = 0;
  94. if (copy_from_user(&io, data, sizeof(io)))
  95. return -EFAULT;
  96. wil_dbg_ioctl(wil, "IO: addr = 0x%08x size = 0x%08x op = 0x%08x\n",
  97. io.addr, io.size, io.op);
  98. /* size */
  99. if (io.size % 4) {
  100. wil_err(wil, "size is not multiple of 4: 0x%08x\n", io.size);
  101. return -EINVAL;
  102. }
  103. a = wil_ioc_addr(wil, io.addr, io.size, io.op);
  104. if (!a) {
  105. wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr,
  106. io.op);
  107. return -EINVAL;
  108. }
  109. block = kmalloc(io.size, GFP_USER);
  110. if (!block)
  111. return -ENOMEM;
  112. /* operation */
  113. switch (io.op & wil_mmio_op_mask) {
  114. case wil_mmio_read:
  115. wil_memcpy_fromio_32(block, a, io.size);
  116. wil_hex_dump_ioctl("Read ", block, io.size);
  117. if (copy_to_user(io.block, block, io.size)) {
  118. rc = -EFAULT;
  119. goto out_free;
  120. }
  121. break;
  122. case wil_mmio_write:
  123. if (copy_from_user(block, io.block, io.size)) {
  124. rc = -EFAULT;
  125. goto out_free;
  126. }
  127. wil_memcpy_toio_32(a, block, io.size);
  128. wmb(); /* make sure write propagated to HW */
  129. wil_hex_dump_ioctl("Write ", block, io.size);
  130. break;
  131. default:
  132. wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
  133. rc = -EINVAL;
  134. break;
  135. }
  136. out_free:
  137. kfree(block);
  138. return rc;
  139. }
  140. int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd)
  141. {
  142. switch (cmd) {
  143. case WIL_IOCTL_MEMIO:
  144. return wil_ioc_memio_dword(wil, data);
  145. case WIL_IOCTL_MEMIO_BLOCK:
  146. return wil_ioc_memio_block(wil, data);
  147. default:
  148. wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd);
  149. return -ENOIOCTLCMD;
  150. }
  151. }