Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c3e072e1 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "wil6210: atomic I/O for the card memory"

parents 9285ff4f 51370aa7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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>
+1 −0
Original line number Diff line number Diff line
@@ -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
+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;
	}
}
+12 −0
Original line number Diff line number Diff line
@@ -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,
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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