Loading MAINTAINERS +1 −0 Original line number Diff line number Diff line Loading @@ -1406,6 +1406,7 @@ L: wil6210@qca.qualcomm.com S: Supported W: http://wireless.kernel.org/en/users/Drivers/wil6210 F: drivers/net/wireless/ath/wil6210/ F: include/uapi/linux/wil6210_uapi.h CARL9170 LINUX COMMUNITY WIRELESS DRIVER M: Christian Lamparter <chunkeey@googlemail.com> Loading drivers/net/wireless/ath/wil6210/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ wil6210-y += interrupt.o wil6210-y += txrx.o wil6210-y += debug.o wil6210-y += rx_reorder.o wil6210-y += ioctl.o wil6210-y += fw.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o wil6210-y += wil_platform.o Loading drivers/net/wireless/ath/wil6210/ioctl.c 0 → 100644 +173 −0 Original line number Diff line number Diff line /* * Copyright (c) 2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/uaccess.h> #include "wil6210.h" #include <uapi/linux/wil6210_uapi.h> #define wil_hex_dump_ioctl(prefix_str, buf, len) \ print_hex_dump_debug("DBG[IOC ]" prefix_str, \ DUMP_PREFIX_OFFSET, 16, 1, buf, len, true) #define wil_dbg_ioctl(wil, fmt, arg...) wil_dbg(wil, "DBG[IOC ]" fmt, ##arg) static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr, uint32_t size, enum wil_memio_op op) { void __iomem *a; u32 off; switch (op & wil_mmio_addr_mask) { case wil_mmio_addr_linker: a = wmi_buffer(wil, cpu_to_le32(addr)); break; case wil_mmio_addr_ahb: a = wmi_addr(wil, addr); break; case wil_mmio_addr_bar: a = wmi_addr(wil, addr + WIL6210_FW_HOST_OFF); break; default: wil_err(wil, "Unsupported address mode, op = 0x%08x\n", op); return NULL; } off = a - wil->csr; if (size >= WIL6210_MEM_SIZE - off) { wil_err(wil, "Requested block does not fit into memory: " "off = 0x%08x size = 0x%08x\n", off, size); return NULL; } return a; } static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data) { struct wil_memio io; void __iomem *a; bool need_copy = false; if (copy_from_user(&io, data, sizeof(io))) return -EFAULT; wil_dbg_ioctl(wil, "IO: addr = 0x%08x val = 0x%08x op = 0x%08x\n", io.addr, io.val, io.op); a = wil_ioc_addr(wil, io.addr, sizeof(u32), io.op); if (!a) { wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr, io.op); return -EINVAL; } /* operation */ switch (io.op & wil_mmio_op_mask) { case wil_mmio_read: io.val = ioread32(a); need_copy = true; break; case wil_mmio_write: iowrite32(io.val, a); wmb(); /* make sure write propagated to HW */ break; default: wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op); return -EINVAL; } if (need_copy) { wil_dbg_ioctl(wil, "IO done: addr = 0x%08x" " val = 0x%08x op = 0x%08x\n", io.addr, io.val, io.op); if (copy_to_user(data, &io, sizeof(io))) return -EFAULT; } return 0; } static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data) { struct wil_memio_block io; void *block; void __iomem *a; int rc = 0; if (copy_from_user(&io, data, sizeof(io))) return -EFAULT; wil_dbg_ioctl(wil, "IO: addr = 0x%08x size = 0x%08x op = 0x%08x\n", io.addr, io.size, io.op); /* size */ if (io.size % 4) { wil_err(wil, "size is not multiple of 4: 0x%08x\n", io.size); return -EINVAL; } a = wil_ioc_addr(wil, io.addr, io.size, io.op); if (!a) { wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr, io.op); return -EINVAL; } block = kmalloc(io.size, GFP_USER); if (!block) return -ENOMEM; /* operation */ switch (io.op & wil_mmio_op_mask) { case wil_mmio_read: wil_memcpy_fromio_32(block, a, io.size); wil_hex_dump_ioctl("Read ", block, io.size); if (copy_to_user(io.block, block, io.size)) { rc = -EFAULT; goto out_free; } break; case wil_mmio_write: if (copy_from_user(block, io.block, io.size)) { rc = -EFAULT; goto out_free; } wil_memcpy_toio_32(a, block, io.size); wmb(); /* make sure write propagated to HW */ wil_hex_dump_ioctl("Write ", block, io.size); break; default: wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op); rc = -EINVAL; break; } out_free: kfree(block); return rc; } int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd) { switch (cmd) { case WIL_IOCTL_MEMIO: return wil_ioc_memio_dword(wil, data); case WIL_IOCTL_MEMIO_BLOCK: return wil_ioc_memio_block(wil, data); default: wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd); return -ENOIOCTLCMD; } } drivers/net/wireless/ath/wil6210/netdev.c +12 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,17 @@ static int wil_change_mtu(struct net_device *ndev, int new_mtu) return 0; } static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) { struct wil6210_priv *wil = ndev_to_wil(ndev); int ret = wil_ioctl(wil, ifr->ifr_data, cmd); wil_dbg_misc(wil, "ioctl(0x%04x) -> %d\n", cmd, ret); return ret; } static const struct net_device_ops wil_netdev_ops = { .ndo_open = wil_open, .ndo_stop = wil_stop, Loading @@ -59,6 +70,7 @@ static const struct net_device_ops wil_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = wil_change_mtu, .ndo_do_ioctl = wil_do_ioctl, }; static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) Loading drivers/net/wireless/ath/wil6210/wil6210.h +2 −0 Original line number Diff line number Diff line Loading @@ -597,5 +597,7 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil); int wil_iftype_nl2wmi(enum nl80211_iftype type); int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd); int wil_request_firmware(struct wil6210_priv *wil, const char *name); #endif /* __WIL6210_H__ */ Loading
MAINTAINERS +1 −0 Original line number Diff line number Diff line Loading @@ -1406,6 +1406,7 @@ L: wil6210@qca.qualcomm.com S: Supported W: http://wireless.kernel.org/en/users/Drivers/wil6210 F: drivers/net/wireless/ath/wil6210/ F: include/uapi/linux/wil6210_uapi.h CARL9170 LINUX COMMUNITY WIRELESS DRIVER M: Christian Lamparter <chunkeey@googlemail.com> Loading
drivers/net/wireless/ath/wil6210/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ wil6210-y += interrupt.o wil6210-y += txrx.o wil6210-y += debug.o wil6210-y += rx_reorder.o wil6210-y += ioctl.o wil6210-y += fw.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o wil6210-y += wil_platform.o Loading
drivers/net/wireless/ath/wil6210/ioctl.c 0 → 100644 +173 −0 Original line number Diff line number Diff line /* * Copyright (c) 2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/uaccess.h> #include "wil6210.h" #include <uapi/linux/wil6210_uapi.h> #define wil_hex_dump_ioctl(prefix_str, buf, len) \ print_hex_dump_debug("DBG[IOC ]" prefix_str, \ DUMP_PREFIX_OFFSET, 16, 1, buf, len, true) #define wil_dbg_ioctl(wil, fmt, arg...) wil_dbg(wil, "DBG[IOC ]" fmt, ##arg) static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr, uint32_t size, enum wil_memio_op op) { void __iomem *a; u32 off; switch (op & wil_mmio_addr_mask) { case wil_mmio_addr_linker: a = wmi_buffer(wil, cpu_to_le32(addr)); break; case wil_mmio_addr_ahb: a = wmi_addr(wil, addr); break; case wil_mmio_addr_bar: a = wmi_addr(wil, addr + WIL6210_FW_HOST_OFF); break; default: wil_err(wil, "Unsupported address mode, op = 0x%08x\n", op); return NULL; } off = a - wil->csr; if (size >= WIL6210_MEM_SIZE - off) { wil_err(wil, "Requested block does not fit into memory: " "off = 0x%08x size = 0x%08x\n", off, size); return NULL; } return a; } static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data) { struct wil_memio io; void __iomem *a; bool need_copy = false; if (copy_from_user(&io, data, sizeof(io))) return -EFAULT; wil_dbg_ioctl(wil, "IO: addr = 0x%08x val = 0x%08x op = 0x%08x\n", io.addr, io.val, io.op); a = wil_ioc_addr(wil, io.addr, sizeof(u32), io.op); if (!a) { wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr, io.op); return -EINVAL; } /* operation */ switch (io.op & wil_mmio_op_mask) { case wil_mmio_read: io.val = ioread32(a); need_copy = true; break; case wil_mmio_write: iowrite32(io.val, a); wmb(); /* make sure write propagated to HW */ break; default: wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op); return -EINVAL; } if (need_copy) { wil_dbg_ioctl(wil, "IO done: addr = 0x%08x" " val = 0x%08x op = 0x%08x\n", io.addr, io.val, io.op); if (copy_to_user(data, &io, sizeof(io))) return -EFAULT; } return 0; } static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data) { struct wil_memio_block io; void *block; void __iomem *a; int rc = 0; if (copy_from_user(&io, data, sizeof(io))) return -EFAULT; wil_dbg_ioctl(wil, "IO: addr = 0x%08x size = 0x%08x op = 0x%08x\n", io.addr, io.size, io.op); /* size */ if (io.size % 4) { wil_err(wil, "size is not multiple of 4: 0x%08x\n", io.size); return -EINVAL; } a = wil_ioc_addr(wil, io.addr, io.size, io.op); if (!a) { wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr, io.op); return -EINVAL; } block = kmalloc(io.size, GFP_USER); if (!block) return -ENOMEM; /* operation */ switch (io.op & wil_mmio_op_mask) { case wil_mmio_read: wil_memcpy_fromio_32(block, a, io.size); wil_hex_dump_ioctl("Read ", block, io.size); if (copy_to_user(io.block, block, io.size)) { rc = -EFAULT; goto out_free; } break; case wil_mmio_write: if (copy_from_user(block, io.block, io.size)) { rc = -EFAULT; goto out_free; } wil_memcpy_toio_32(a, block, io.size); wmb(); /* make sure write propagated to HW */ wil_hex_dump_ioctl("Write ", block, io.size); break; default: wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op); rc = -EINVAL; break; } out_free: kfree(block); return rc; } int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd) { switch (cmd) { case WIL_IOCTL_MEMIO: return wil_ioc_memio_dword(wil, data); case WIL_IOCTL_MEMIO_BLOCK: return wil_ioc_memio_block(wil, data); default: wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd); return -ENOIOCTLCMD; } }
drivers/net/wireless/ath/wil6210/netdev.c +12 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,17 @@ static int wil_change_mtu(struct net_device *ndev, int new_mtu) return 0; } static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) { struct wil6210_priv *wil = ndev_to_wil(ndev); int ret = wil_ioctl(wil, ifr->ifr_data, cmd); wil_dbg_misc(wil, "ioctl(0x%04x) -> %d\n", cmd, ret); return ret; } static const struct net_device_ops wil_netdev_ops = { .ndo_open = wil_open, .ndo_stop = wil_stop, Loading @@ -59,6 +70,7 @@ static const struct net_device_ops wil_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = wil_change_mtu, .ndo_do_ioctl = wil_do_ioctl, }; static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) Loading
drivers/net/wireless/ath/wil6210/wil6210.h +2 −0 Original line number Diff line number Diff line Loading @@ -597,5 +597,7 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil); int wil_iftype_nl2wmi(enum nl80211_iftype type); int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd); int wil_request_firmware(struct wil6210_priv *wil, const char *name); #endif /* __WIL6210_H__ */