/*
* Copyright (c) 2012-2015 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/moduleparam.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include "wil6210.h"
#include "txrx.h"
#include "wmi.h"
#include "boot_loader.h"
#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
bool debug_fw; /* = false; */
module_param(debug_fw, bool, S_IRUGO);
MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
/* if not set via modparam, will be set to default value of 1/8 of
* rx ring size during init flow
*/
unsigned short rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_INIT;
module_param(rx_ring_overflow_thrsh, ushort, S_IRUGO);
MODULE_PARM_DESC(rx_ring_overflow_thrsh,
" RX ring overflow threshold in descriptors.");
/* We allow allocation of more than 1 page buffers to support large packets.
* It is suboptimal behavior performance wise in case MTU above page size.
*/
unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD;
static int mtu_max_set(const char *val, const struct kernel_param *kp)
{
int ret;
/* sets mtu_max directly. no need to restore it in case of
* illegal value since we assume this will fail insmod
*/
ret = param_set_uint(val, kp);
if (ret)
return ret;
if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU)
ret = -EINVAL;
return ret;
}
static const struct kernel_param_ops mtu_max_ops = {
.set = mtu_max_set,
.get = param_get_uint,
};
module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, S_IRUGO);
MODULE_PARM_DESC(mtu_max, " Max MTU value.");
static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT;
static int ring_order_set(const char *val, const struct kernel_param *kp)
{
int ret;
uint x;
ret = kstrtouint(val, 0, &x);
if (ret)
return ret;
if ((x < WIL_RING_SIZE_ORDER_MIN) || (x > WIL_RING_SIZE_ORDER_MAX))
return -EINVAL;
*((uint *)kp->arg) = x;
return 0;
}
static const struct kernel_param_ops ring_order_ops = {
.set = ring_order_set,
.get = param_get_uint,
};
module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO);
MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO);
MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order");
module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, S_IRUGO);
MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order");
#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
/*
* Due to a hardware issue,
* one has to read/write to/from NIC in 32-bit chunks;
* regular memcpy_fromio and siblings will
* not work on 64-bit platform - it uses 64-bit transactions
*
* Force 32-bit transactions to enable NIC on 64-bit platforms
*
* To avoid byte swap on big endian host, __raw_{read|write}l
* should be used - {read|write}l would swap bytes to provide
* little endian on PCI value in host endianness.
*/
void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
size_t count)
{
u32 *d = dst;
const volatile u32 __iomem *s = src;
/* size_t is unsigned, if (count%4 != 0) it will wrap */
for (count += 4; count > 4; count -= 4)
*d++ = __raw_readl(s++);
}
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
size_t count)
{
volatile u32 __iomem *d = dst;
const u32 *s = src;
for (count += 4; count > 4; count -= 4)
__raw_writel(*s++, d++);
}
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
u16