1
0
Fork 0

Merge tag 'master-2014-11-04' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next

John W. Linville says:

====================
pull request: wireless-next 2014-11-07

Please pull this batch of updates intended for the 3.19 stream!

For the mac80211 bits, Johannes says:

"This relatively large batch of changes is comprised of the following:
 * large mac80211-hwsim changes from Ben, Jukka and a bit myself
 * OCB/WAVE/11p support from Rostislav on behalf of the Czech Technical
   University in Prague and Volkswagen Group Research
 * minstrel VHT work from Karl
 * more CSA work from Luca
 * WMM admission control support in mac80211 (myself)
 * various smaller fixes, spelling corrections, and minor API additions"

For the Bluetooth bits, Johan says:

"Here's the first bluetooth-next pull request for 3.19. The vast majority
of patches are for ieee802154 from Alexander Aring with various fixes
and cleanups. There are also several LE/SMP fixes as well as improved
support for handling LE devices that have lost their pairing information
(the patches from Alfonso). Jukka provides a couple of stability fixes
for 6lowpan and Szymon conformance fixes for RFCOMM. For the HCI drivers
we have one new USB ID for an Acer controller as well as a reset
handling fix for H5."

For the Atheros bits, Kalle says:

"Major changes are:

o ethtool support (Ben)

o print dev string prefix with debug hex buffers dump (Michal)

o debugfs file to read calibration data from the firmware verification
  purposes (me)

o fix fw_stats debugfs file, now results are more reliable (Michal)

o firmware crash counters via debugfs (Ben&me)

o various tracing points to debug firmware (Rajkumar)

o make it possible to provide firmware calibration data via a file (me)

And we have quite a lot of smaller fixes and clean up."

For the iwlwifi bits, Emmanuel says:

"The big new thing here is netdetect which allows the
firmware to wake up the platform when a specific network
is detected. Along with that I have fixes for d3 operation.
The usual amount of rate scaling stuff - we now support STBC.
The other commit that stands out is Johannes's work on
devcoredump. He basically starts to use the standard
infrastructure he built."

Along with that are the usual sort of updates and such for ath9k,
brcmfmac, wil6210, and a handful of other bits here and there...

Please let me know if there are problems!
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
hifive-unleashed-5.1
David S. Miller 2014-11-10 14:34:59 -05:00
commit b92172661e
251 changed files with 10035 additions and 6021 deletions

View File

@ -2306,6 +2306,14 @@ F: security/capability.c
F: security/commoncap.c
F: kernel/capability.c
CC2520 IEEE-802.15.4 RADIO DRIVER
M: Varka Bhadram <varkabhadram@gmail.com>
L: linux-wpan@vger.kernel.org
S: Maintained
F: drivers/net/ieee802154/cc2520.c
F: include/linux/spi/cc2520.h
F: Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
CELL BROADBAND ENGINE ARCHITECTURE
M: Arnd Bergmann <arnd@arndb.de>
L: linuxppc-dev@lists.ozlabs.org
@ -4693,6 +4701,13 @@ S: Maintained
F: net/ieee802154/
F: net/mac802154/
F: drivers/net/ieee802154/
F: include/linux/nl802154.h
F: include/linux/ieee802154.h
F: include/net/nl802154.h
F: include/net/mac802154.h
F: include/net/af_ieee802154.h
F: include/net/cfg802154.h
F: include/net/ieee802154_netdev.h
F: Documentation/networking/ieee802154.txt
IGUANAWORKS USB IR TRANSCEIVER

View File

@ -24,6 +24,7 @@ struct bcma_bus;
/* main.c */
bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
int timeout);
void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
int bcma_bus_register(struct bcma_bus *bus);
void bcma_bus_unregister(struct bcma_bus *bus);
int __init bcma_bus_early_register(struct bcma_bus *bus,

View File

@ -169,10 +169,8 @@ static void bcma_of_fill_device(struct platform_device *parent,
}
#endif /* CONFIG_OF */
static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
{
int err;
core->dev.release = bcma_release_core_dev;
core->dev.bus = &bcma_bus_type;
dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
@ -196,6 +194,11 @@ static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
case BCMA_HOSTTYPE_SDIO:
break;
}
}
static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
{
int err;
err = device_register(&core->dev);
if (err) {

View File

@ -505,6 +505,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
bus->nr_cores++;
other_core = bcma_find_core_reverse(bus, core->id.id);
core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
bcma_prepare_core(bus, core);
bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
core->core_index, bcma_device_name(&core->id),

View File

@ -79,6 +79,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x0489, 0xe057) },
{ USB_DEVICE(0x0489, 0xe056) },
{ USB_DEVICE(0x0489, 0xe05f) },
{ USB_DEVICE(0x0489, 0xe078) },
{ USB_DEVICE(0x04c5, 0x1330) },
{ USB_DEVICE(0x04CA, 0x3004) },
{ USB_DEVICE(0x04CA, 0x3005) },
@ -130,6 +131,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },

View File

@ -156,6 +156,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },

View File

@ -168,6 +168,36 @@ wakeup:
hci_uart_tx_wakeup(hu);
}
static void h5_peer_reset(struct hci_uart *hu)
{
struct h5 *h5 = hu->priv;
struct sk_buff *skb;
const unsigned char hard_err[] = { 0x10, 0x01, 0x00 };
BT_ERR("Peer device has reset");
h5->state = H5_UNINITIALIZED;
del_timer(&h5->timer);
skb_queue_purge(&h5->rel);
skb_queue_purge(&h5->unrel);
skb_queue_purge(&h5->unack);
h5->tx_seq = 0;
h5->tx_ack = 0;
skb = bt_skb_alloc(3, GFP_ATOMIC);
if (!skb)
return;
bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
memcpy(skb_put(skb, 3), hard_err, 3);
/* Send Hardware Error to upper stack */
hci_recv_frame(hu->hdev, skb);
}
static int h5_open(struct hci_uart *hu)
{
struct h5 *h5;
@ -283,8 +313,12 @@ static void h5_handle_internal_rx(struct hci_uart *hu)
conf_req[2] = h5_cfg_field(h5);
if (memcmp(data, sync_req, 2) == 0) {
if (h5->state == H5_ACTIVE)
h5_peer_reset(hu);
h5_link_control(hu, sync_rsp, 2);
} else if (memcmp(data, sync_rsp, 2) == 0) {
if (h5->state == H5_ACTIVE)
h5_peer_reset(hu);
h5->state = H5_INITIALIZED;
h5_link_control(hu, conf_req, 3);
} else if (memcmp(data, conf_req, 2) == 0) {

View File

@ -10,16 +10,6 @@ menuconfig IEEE802154_DRIVERS
If you say N, all options in this submenu will be skipped and
disabled.
config IEEE802154_FAKEHARD
tristate "Fake LR-WPAN driver with several interconnected devices"
depends on IEEE802154_DRIVERS
---help---
Say Y here to enable the fake driver that serves as an example
of HardMAC device driver.
This driver can also be built as a module. To do so say M here.
The module will be called 'fakehard'.
config IEEE802154_FAKELB
depends on IEEE802154_DRIVERS && MAC802154
tristate "IEEE 802.15.4 loopback driver"

View File

@ -1,4 +1,3 @@
obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o

View File

@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by:
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
* Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
@ -33,10 +29,10 @@
#include <linux/regmap.h>
#include <linux/skbuff.h>
#include <linux/of_gpio.h>
#include <linux/ieee802154.h>
#include <net/ieee802154.h>
#include <net/mac802154.h>
#include <net/wpan-phy.h>
#include <net/cfg802154.h>
struct at86rf230_local;
/* at86rf2xx chip depend data.
@ -58,7 +54,7 @@ struct at86rf2xx_chip_data {
u16 t_tx_timeout;
int rssi_base_val;
int (*set_channel)(struct at86rf230_local *, int, int);
int (*set_channel)(struct at86rf230_local *, u8, u8);
int (*get_desense_steps)(struct at86rf230_local *, s32);
};
@ -74,12 +70,14 @@ struct at86rf230_state_change {
void (*complete)(void *context);
u8 from_state;
u8 to_state;
bool irq_enable;
};
struct at86rf230_local {
struct spi_device *spi;
struct ieee802154_dev *dev;
struct ieee802154_hw *hw;
struct at86rf2xx_chip_data *data;
struct regmap *regmap;
@ -89,10 +87,10 @@ struct at86rf230_local {
struct at86rf230_state_change irq;
bool tx_aret;
s8 max_frame_retries;
bool is_tx;
/* spinlock for is_tx protection */
spinlock_t lock;
struct completion tx_complete;
struct sk_buff *tx_skb;
struct at86rf230_state_change tx;
};
@ -291,10 +289,11 @@ struct at86rf230_local {
#define AT86RF2XX_NUMREGS 0x3F
static int
static void
at86rf230_async_state_change(struct at86rf230_local *lp,
struct at86rf230_state_change *ctx,
const u8 state, void (*complete)(void *context));
const u8 state, void (*complete)(void *context),
const bool irq_enable);
static inline int
__at86rf230_write(struct at86rf230_local *lp,
@ -451,7 +450,8 @@ at86rf230_async_error_recover(void *context)
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL);
at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL, false);
ieee802154_wake_queue(lp->hw);
}
static void
@ -461,21 +461,31 @@ at86rf230_async_error(struct at86rf230_local *lp,
dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
at86rf230_async_error_recover);
at86rf230_async_error_recover, false);
}
/* Generic function to get some register value in async mode */
static int
static void
at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg,
struct at86rf230_state_change *ctx,
void (*complete)(void *context))
void (*complete)(void *context),
const bool irq_enable)
{
int rc;
u8 *tx_buf = ctx->buf;
tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG;
ctx->trx.len = 2;
ctx->msg.complete = complete;
return spi_async(lp->spi, &ctx->msg);
ctx->irq_enable = irq_enable;
rc = spi_async(lp->spi, &ctx->msg);
if (rc) {
if (irq_enable)
enable_irq(lp->spi->irq);
at86rf230_async_error(lp, ctx, rc);
}
}
static void
@ -512,7 +522,8 @@ at86rf230_async_state_assert(void *context)
if (ctx->to_state == STATE_TX_ON) {
at86rf230_async_state_change(lp, ctx,
STATE_FORCE_TX_ON,
ctx->complete);
ctx->complete,
ctx->irq_enable);
return;
}
}
@ -535,7 +546,6 @@ at86rf230_async_state_delay(void *context)
struct at86rf230_local *lp = ctx->lp;
struct at86rf2xx_chip_data *c = lp->data;
bool force = false;
int rc;
/* The force state changes are will show as normal states in the
* state status subregister. We change the to_state to the
@ -604,10 +614,9 @@ at86rf230_async_state_delay(void *context)
udelay(1);
change:
rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
at86rf230_async_state_assert);
if (rc)
dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
at86rf230_async_state_assert,
ctx->irq_enable);
}
static void
@ -622,10 +631,9 @@ at86rf230_async_state_change_start(void *context)
/* Check for "possible" STATE_TRANSITION_IN_PROGRESS */
if (trx_state == STATE_TRANSITION_IN_PROGRESS) {
udelay(1);
rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
at86rf230_async_state_change_start);
if (rc)
dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
at86rf230_async_state_change_start,
ctx->irq_enable);
return;
}
@ -647,20 +655,27 @@ at86rf230_async_state_change_start(void *context)
ctx->trx.len = 2;
ctx->msg.complete = at86rf230_async_state_delay;
rc = spi_async(lp->spi, &ctx->msg);
if (rc)
dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
if (rc) {
if (ctx->irq_enable)
enable_irq(lp->spi->irq);
at86rf230_async_error(lp, &lp->state, rc);
}
}
static int
static void
at86rf230_async_state_change(struct at86rf230_local *lp,
struct at86rf230_state_change *ctx,
const u8 state, void (*complete)(void *context))
const u8 state, void (*complete)(void *context),
const bool irq_enable)
{
/* Initialization for the state change context */
ctx->to_state = state;
ctx->complete = complete;
return at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
at86rf230_async_state_change_start);
ctx->irq_enable = irq_enable;
at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
at86rf230_async_state_change_start,
irq_enable);
}
static void
@ -681,17 +696,16 @@ at86rf230_sync_state_change(struct at86rf230_local *lp, unsigned int state)
{
int rc;
rc = at86rf230_async_state_change(lp, &lp->state, state,
at86rf230_sync_state_change_complete);
if (rc) {
at86rf230_async_error(lp, &lp->state, rc);
return rc;
}
at86rf230_async_state_change(lp, &lp->state, state,
at86rf230_sync_state_change_complete,
false);
rc = wait_for_completion_timeout(&lp->state_complete,
msecs_to_jiffies(100));
if (!rc)
if (!rc) {
at86rf230_async_error(lp, &lp->state, -ETIMEDOUT);
return -ETIMEDOUT;
}
return 0;
}
@ -701,8 +715,23 @@ at86rf230_tx_complete(void *context)
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
struct sk_buff *skb = lp->tx_skb;
complete(&lp->tx_complete);
enable_irq(lp->spi->irq);
if (lp->max_frame_retries <= 0) {
/* Interfame spacing time, which is phy depend.
* TODO
* Move this handling in MAC 802.15.4 layer.
* This is currently a workaround to avoid fragmenation issues.
*/
if (skb->len > 18)
udelay(lp->data->t_lifs);
else
udelay(lp->data->t_sifs);
}
ieee802154_xmit_complete(lp->hw, skb);
}
static void
@ -710,12 +739,9 @@ at86rf230_tx_on(void *context)
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
int rc;
rc = at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON,
at86rf230_tx_complete);
if (rc)
at86rf230_async_error(lp, ctx, rc);
at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON,
at86rf230_tx_complete, true);
}
static void
@ -723,12 +749,9 @@ at86rf230_tx_trac_error(void *context)
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
int rc;
rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
at86rf230_tx_on);
if (rc)
at86rf230_async_error(lp, ctx, rc);
at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
at86rf230_tx_on, true);
}
static void
@ -738,17 +761,14 @@ at86rf230_tx_trac_check(void *context)
struct at86rf230_local *lp = ctx->lp;
const u8 *buf = ctx->buf;
const u8 trac = (buf[1] & 0xe0) >> 5;
int rc;
/* If trac status is different than zero we need to do a state change
* to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver
* state to TX_ON.
*/
if (trac) {
rc = at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
at86rf230_tx_trac_error);
if (rc)
at86rf230_async_error(lp, ctx, rc);
at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
at86rf230_tx_trac_error, true);
return;
}
@ -761,51 +781,29 @@ at86rf230_tx_trac_status(void *context)
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
int rc;
rc = at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
at86rf230_tx_trac_check);
if (rc)
at86rf230_async_error(lp, ctx, rc);
at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
at86rf230_tx_trac_check, true);
}
static void
at86rf230_rx(struct at86rf230_local *lp,
const u8 *data, u8 len)
const u8 *data, const u8 len, const u8 lqi)
{
u8 lqi;
struct sk_buff *skb;
u8 rx_local_buf[AT86RF2XX_MAX_BUF];
if (len < 2)
return;
/* read full frame buffer and invalid lqi value to lowest
* indicator if frame was is in a corrupted state.
*/
if (len > IEEE802154_MTU) {
lqi = 0;
len = IEEE802154_MTU;
dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
} else {
lqi = data[len];
}
memcpy(rx_local_buf, data, len);
enable_irq(lp->spi->irq);
skb = alloc_skb(IEEE802154_MTU, GFP_ATOMIC);
skb = dev_alloc_skb(IEEE802154_MTU);
if (!skb) {
dev_vdbg(&lp->spi->dev, "failed to allocate sk_buff\n");
return;
}
memcpy(skb_put(skb, len), rx_local_buf, len);
/* We do not put CRC into the frame */
skb_trim(skb, len - 2);
ieee802154_rx_irqsafe(lp->dev, skb, lqi);
ieee802154_rx_irqsafe(lp->hw, skb, lqi);
}
static void
@ -814,20 +812,31 @@ at86rf230_rx_read_frame_complete(void *context)
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
const u8 *buf = lp->irq.buf;
const u8 len = buf[1];
u8 len = buf[1];
at86rf230_rx(lp, buf + 2, len);
if (!ieee802154_is_valid_psdu_len(len)) {
dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
len = IEEE802154_MTU;
}
at86rf230_rx(lp, buf + 2, len, buf[2 + len]);
}
static int
static void
at86rf230_rx_read_frame(struct at86rf230_local *lp)
{
int rc;
u8 *buf = lp->irq.buf;
buf[0] = CMD_FB;
lp->irq.trx.len = AT86RF2XX_MAX_BUF;
lp->irq.msg.complete = at86rf230_rx_read_frame_complete;
return spi_async(lp->spi, &lp->irq.msg);
rc = spi_async(lp->spi, &lp->irq.msg);
if (rc) {
enable_irq(lp->spi->irq);
at86rf230_async_error(lp, &lp->irq, rc);
}
}
static void
@ -835,7 +844,6 @@ at86rf230_rx_trac_check(void *context)
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
int rc;
/* Possible check on trac status here. This could be useful to make
* some stats why receive is failed. Not used at the moment, but it's
@ -843,34 +851,31 @@ at86rf230_rx_trac_check(void *context)
* The programming guide say do it so.
*/
rc = at86rf230_rx_read_frame(lp);
if (rc) {
enable_irq(lp->spi->irq);
at86rf230_async_error(lp, ctx, rc);
}
at86rf230_rx_read_frame(lp);
}
static int
static void
at86rf230_irq_trx_end(struct at86rf230_local *lp)
{
spin_lock(&lp->lock);
if (lp->is_tx) {
lp->is_tx = 0;
spin_unlock(&lp->lock);
enable_irq(lp->spi->irq);
if (lp->tx_aret)
return at86rf230_async_state_change(lp, &lp->irq,
STATE_FORCE_TX_ON,
at86rf230_tx_trac_status);
at86rf230_async_state_change(lp, &lp->irq,
STATE_FORCE_TX_ON,
at86rf230_tx_trac_status,
true);
else
return at86rf230_async_state_change(lp, &lp->irq,
STATE_RX_AACK_ON,
at86rf230_tx_complete);
at86rf230_async_state_change(lp, &lp->irq,
STATE_RX_AACK_ON,
at86rf230_tx_complete,
true);
} else {
spin_unlock(&lp->lock);
return at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq,
at86rf230_rx_trac_check);
at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq,
at86rf230_rx_trac_check, true);
}
}
@ -881,12 +886,9 @@ at86rf230_irq_status(void *context)
struct at86rf230_local *lp = ctx->lp;
const u8 *buf = lp->irq.buf;
const u8 irq = buf[1];
int rc;
if (irq & IRQ_TRX_END) {
rc = at86rf230_irq_trx_end(lp);
if (rc)
at86rf230_async_error(lp, ctx, rc);
at86rf230_irq_trx_end(lp);
} else {
enable_irq(lp->spi->irq);
dev_err(&lp->spi->dev, "not supported irq %02x received\n",
@ -901,13 +903,14 @@ static irqreturn_t at86rf230_isr(int irq, void *data)
u8 *buf = ctx->buf;
int rc;
disable_irq_nosync(lp->spi->irq);
disable_irq_nosync(irq);
buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG;
ctx->trx.len = 2;
ctx->msg.complete = at86rf230_irq_status;
rc = spi_async(lp->spi, &ctx->msg);
if (rc) {
enable_irq(irq);
at86rf230_async_error(lp, ctx, rc);
return IRQ_NONE;
}
@ -960,22 +963,18 @@ at86rf230_xmit_tx_on(void *context)
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
int rc;
rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
at86rf230_write_frame);
if (rc)
at86rf230_async_error(lp, ctx, rc);
at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
at86rf230_write_frame, false);
}
static int
at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
{
struct at86rf230_local *lp = dev->priv;
struct at86rf230_local *lp = hw->priv;
struct at86rf230_state_change *ctx = &lp->tx;
void (*tx_complete)(void *context) = at86rf230_write_frame;
int rc;
lp->tx_skb = skb;
@ -986,61 +985,39 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
if (lp->tx_aret)
tx_complete = at86rf230_xmit_tx_on;
rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
tx_complete);
if (rc) {
at86rf230_async_error(lp, ctx, rc);
return rc;
}
rc = wait_for_completion_interruptible_timeout(&lp->tx_complete,
msecs_to_jiffies(lp->data->t_tx_timeout));
if (!rc) {
at86rf230_async_error(lp, ctx, rc);
return -ETIMEDOUT;
}
/* Interfame spacing time, which is phy depend.
* TODO
* Move this handling in MAC 802.15.4 layer.
* This is currently a workaround to avoid fragmenation issues.
*/
if (skb->len > 18)
usleep_range(lp->data->t_lifs, lp->data->t_lifs + 10);
else
usleep_range(lp->data->t_sifs, lp->data->t_sifs + 10);
at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false);
return 0;
}
static int
at86rf230_ed(struct ieee802154_dev *dev, u8 *level)
at86rf230_ed(struct ieee802154_hw *hw, u8 *level)
{
might_sleep();
BUG_ON(!level);
*level = 0xbe;
return 0;
}
static int
at86rf230_start(struct ieee802154_dev *dev)
at86rf230_start(struct ieee802154_hw *hw)
{
return at86rf230_sync_state_change(dev->priv, STATE_RX_AACK_ON);
return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON);
}
static void
at86rf230_stop(struct ieee802154_dev *dev)
at86rf230_stop(struct ieee802154_hw *hw)
{
at86rf230_sync_state_change(dev->priv, STATE_FORCE_TRX_OFF);
at86rf230_sync_state_change(hw->priv, STATE_FORCE_TRX_OFF);
}
static int
at86rf23x_set_channel(struct at86rf230_local *lp, int page, int channel)
at86rf23x_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
{
return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
}
static int
at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel)
at86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
{
int rc;
@ -1065,15 +1042,13 @@ at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel)
}
static int
at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
at86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
struct at86rf230_local *lp = dev->priv;
struct at86rf230_local *lp = hw->priv;
int rc;
might_sleep();
if (page < 0 || page > 31 ||
!(lp->dev->phy->channels_supported[page] & BIT(channel))) {
!(lp->hw->phy->channels_supported[page] & BIT(channel))) {
WARN_ON(1);
return -EINVAL;
}
@ -1085,20 +1060,20 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
/* Wait for PLL */
usleep_range(lp->data->t_channel_switch,
lp->data->t_channel_switch + 10);
dev->phy->current_channel = channel;
dev->phy->current_page = page;
hw->phy->current_channel = channel;
hw->phy->current_page = page;
return 0;
}
static int
at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw,
struct ieee802154_hw_addr_filt *filt,
unsigned long changed)
{
struct at86rf230_local *lp = dev->priv;
struct at86rf230_local *lp = hw->priv;
if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
u16 addr = le16_to_cpu(filt->short_addr);
dev_vdbg(&lp->spi->dev,
@ -1107,7 +1082,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
__at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
}
if (changed & IEEE802515_AFILT_PANID_CHANGED) {
if (changed & IEEE802154_AFILT_PANID_CHANGED) {
u16 pan = le16_to_cpu(filt->pan_id);
dev_vdbg(&lp->spi->dev,
@ -1116,7 +1091,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
__at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
}
if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
u8 i, addr[8];
memcpy(addr, &filt->ieee_addr, 8);
@ -1126,7 +1101,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
__at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
}
if (changed & IEEE802515_AFILT_PANC_CHANGED) {
if (changed & IEEE802154_AFILT_PANC_CHANGED) {
dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for panc change\n");
if (filt->pan_coord)
@ -1139,9 +1114,9 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
}
static int
at86rf230_set_txpower(struct ieee802154_dev *dev, int db)
at86rf230_set_txpower(struct ieee802154_hw *hw, int db)
{
struct at86rf230_local *lp = dev->priv;
struct at86rf230_local *lp = hw->priv;
/* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five
* bits decrease power in 1dB steps. 0x60 represents extra PA gain of
@ -1158,17 +1133,17 @@ at86rf230_set_txpower(struct ieee802154_dev *dev, int db)
}
static int
at86rf230_set_lbt(struct ieee802154_dev *dev, bool on)
at86rf230_set_lbt(struct ieee802154_hw *hw, bool on)
{
struct at86rf230_local *lp = dev->priv;
struct at86rf230_local *lp = hw->priv;
return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on);
}
static int
at86rf230_set_cca_mode(struct ieee802154_dev *dev, u8 mode)
at86rf230_set_cca_mode(struct ieee802154_hw *hw, u8 mode)
{
struct at86rf230_local *lp = dev->priv;
struct at86rf230_local *lp = hw->priv;
return at86rf230_write_subreg(lp, SR_CCA_MODE, mode);
}
@ -1186,9 +1161,9 @@ at86rf23x_get_desens_steps(struct at86rf230_local *lp, s32 level)
}
static int
at86rf230_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 level)
{
struct at86rf230_local *lp = dev->priv;
struct at86rf230_local *lp = hw->priv;
if (level < lp->data->rssi_base_val || level > 30)
return -EINVAL;
@ -1198,10 +1173,10 @@ at86rf230_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
}
static int
at86rf230_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be,
at86rf230_set_csma_params(struct ieee802154_hw *hw, u8 min_be, u8 max_be,
u8 retries)
{
struct at86rf230_local *lp = dev->priv;
struct at86rf230_local *lp = hw->priv;
int rc;
if (min_be > max_be || max_be > 8 || retries > 5)
@ -1219,15 +1194,16 @@ at86rf230_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be,
}
static int
at86rf230_set_frame_retries(struct ieee802154_dev *dev, s8 retries)
at86rf230_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
{
struct at86rf230_local *lp = dev->priv;
struct at86rf230_local *lp = hw->priv;
int rc = 0;
if (retries < -1 || retries > 15)
return -EINVAL;
lp->tx_aret = retries >= 0;
lp->max_frame_retries = retries;
if (retries >= 0)
rc = at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries);
@ -1235,9 +1211,36 @@ at86rf230_set_frame_retries(struct ieee802154_dev *dev, s8 retries)
return rc;
}
static struct ieee802154_ops at86rf230_ops = {
static int
at86rf230_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
{
struct at86rf230_local *lp = hw->priv;
int rc;
if (on) {
rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 1);
if (rc < 0)
return rc;
rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 1);
if (rc < 0)
return rc;
} else {
rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 0);
if (rc < 0)
return rc;
rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 0);
if (rc < 0)
return rc;
}
return 0;
}
static const struct ieee802154_ops at86rf230_ops = {
.owner = THIS_MODULE,
.xmit = at86rf230_xmit,
.xmit_async = at86rf230_xmit,
.ed = at86rf230_ed,
.set_channel = at86rf230_channel,
.start = at86rf230_start,
@ -1249,6 +1252,7 @@ static struct ieee802154_ops at86rf230_ops = {
.set_cca_ed_level = at86rf230_set_cca_ed_level,
.set_csma_params = at86rf230_set_csma_params,
.set_frame_retries = at86rf230_set_frame_retries,
.set_promiscuous_mode = at86rf230_set_promiscuous_mode,
};
static struct at86rf2xx_chip_data at86rf233_data = {
@ -1260,7 +1264,7 @@ static struct at86rf2xx_chip_data at86rf233_data = {
.t_frame = 4096,
.t_p_ack = 545,
.t_sifs = 192,
.t_lifs = 480,
.t_lifs = 640,
.t_tx_timeout = 2000,
.rssi_base_val = -91,
.set_channel = at86rf23x_set_channel,
@ -1276,7 +1280,7 @@ static struct at86rf2xx_chip_data at86rf231_data = {
.t_frame = 4096,
.t_p_ack = 545,
.t_sifs = 192,
.t_lifs = 480,
.t_lifs = 640,
.t_tx_timeout = 2000,
.rssi_base_val = -91,
.set_channel = at86rf23x_set_channel,
@ -1292,7 +1296,7 @@ static struct at86rf2xx_chip_data at86rf212_data = {
.t_frame = 4096,
.t_p_ack = 545,
.t_sifs = 192,
.t_lifs = 480,
.t_lifs = 640,
.t_tx_timeout = 2000,
.rssi_base_val = -100,
.set_channel = at86rf212_set_channel,
@ -1409,9 +1413,10 @@ at86rf230_detect_device(struct at86rf230_local *lp)
return -EINVAL;
}
lp->dev->extra_tx_headroom = 0;
lp->dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
IEEE802154_HW_TXPOWER | IEEE802154_HW_CSMA;
lp->hw->extra_tx_headroom = 0;
lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK |
IEEE802154_HW_TXPOWER | IEEE802154_HW_ARET |
IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS;
switch (part) {
case 2:
@ -1421,15 +1426,15 @@ at86rf230_detect_device(struct at86rf230_local *lp)
case 3:
chip = "at86rf231";
lp->data = &at86rf231_data;
lp->dev->phy->channels_supported[0] = 0x7FFF800;
lp->hw->phy->channels_supported[0] = 0x7FFF800;
break;
case 7:
chip = "at86rf212";
if (version == 1) {
lp->data = &at86rf212_data;
lp->dev->flags |= IEEE802154_HW_LBT;
lp->dev->phy->channels_supported[0] = 0x00007FF;
lp->dev->phy->channels_supported[2] = 0x00007FF;
lp->hw->flags |= IEEE802154_HW_LBT;
lp->hw->phy->channels_supported[0] = 0x00007FF;
lp->hw->phy->channels_supported[2] = 0x00007FF;
} else {
rc = -ENOTSUPP;
}
@ -1437,7 +1442,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
case 11:
chip = "at86rf233";
lp->data = &at86rf233_data;
lp->dev->phy->channels_supported[0] = 0x7FFF800;
lp->hw->phy->channels_supported[0] = 0x7FFF800;
break;
default:
chip = "unkown";
@ -1478,7 +1483,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp)
static int at86rf230_probe(struct spi_device *spi)
{
struct at86rf230_platform_data *pdata;
struct ieee802154_dev *dev;
struct ieee802154_hw *hw;
struct at86rf230_local *lp;
unsigned int status;
int rc, irq_type;
@ -1517,14 +1522,14 @@ static int at86rf230_probe(struct spi_device *spi)
usleep_range(120, 240);
}
dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops);
if (!dev)
hw = ieee802154_alloc_hw(sizeof(*lp), &at86rf230_ops);
if (!hw)
return -ENOMEM;
lp = dev->priv;
lp->dev = dev;
lp = hw->priv;
lp->hw = hw;
lp->spi = spi;
dev->parent = &spi->dev;
hw->parent = &spi->dev;
lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config);
if (IS_ERR(lp->regmap)) {
@ -1541,7 +1546,6 @@ static int at86rf230_probe(struct spi_device *spi)
goto free_dev;
spin_lock_init(&lp->lock);
init_completion(&lp->tx_complete);
init_completion(&lp->state_complete);
spi_set_drvdata(spi, lp);
@ -1564,14 +1568,14 @@ static int at86rf230_probe(struct spi_device *spi)
if (rc)
goto free_dev;
rc = ieee802154_register_device(lp->dev);
rc = ieee802154_register_hw(lp->hw);
if (rc)
goto free_dev;
return rc;
free_dev:
ieee802154_free_device(lp->dev);
ieee802154_free_hw(lp->hw);
return rc;
}
@ -1582,8 +1586,8 @@ static int at86rf230_remove(struct spi_device *spi)
/* mask all at86rf230 irq's */
at86rf230_write_subreg(lp, SR_IRQ_MASK, 0);
ieee802154_unregister_device(lp->dev);
ieee802154_free_device(lp->dev);
ieee802154_unregister_hw(lp->hw);
ieee802154_free_hw(lp->hw);
dev_dbg(&spi->dev, "unregistered at86rf230\n");
return 0;

View File

@ -21,10 +21,10 @@
#include <linux/skbuff.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of_gpio.h>
#include <linux/ieee802154.h>
#include <net/mac802154.h>
#include <net/wpan-phy.h>
#include <net/ieee802154.h>
#include <net/cfg802154.h>
#define SPI_COMMAND_BUFFER 3
#define HIGH 1
@ -193,7 +193,7 @@
/* Driver private information */
struct cc2520_private {
struct spi_device *spi; /* SPI device structure */
struct ieee802154_dev *dev; /* IEEE-802.15.4 device */
struct ieee802154_hw *hw; /* IEEE-802.15.4 device */
u8 *buf; /* SPI TX/Rx data buffer */
struct mutex buffer_mutex; /* SPI buffer mutex */
bool is_tx; /* Flag for sync b/w Tx and Rx */
@ -453,20 +453,20 @@ cc2520_read_rxfifo(struct cc2520_private *priv, u8 *data, u8 len, u8 *lqi)
return status;
}
static int cc2520_start(struct ieee802154_dev *dev)
static int cc2520_start(struct ieee802154_hw *hw)
{
return cc2520_cmd_strobe(dev->priv, CC2520_CMD_SRXON);
return cc2520_cmd_strobe(hw->priv, CC2520_CMD_SRXON);
}
static void cc2520_stop(struct ieee802154_dev *dev)
static void cc2520_stop(struct ieee802154_hw *hw)
{
cc2520_cmd_strobe(dev->priv, CC2520_CMD_SRFOFF);
cc2520_cmd_strobe(hw->priv, CC2520_CMD_SRFOFF);
}
static int
cc2520_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
cc2520_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
{
struct cc2520_private *priv = dev->priv;
struct cc2520_private *priv = hw->priv;
unsigned long flags;
int rc;
u8 status = 0;
@ -524,7 +524,7 @@ static int cc2520_rx(struct cc2520_private *priv)
if (len < 2 || len > IEEE802154_MTU)
return -EINVAL;
skb = alloc_skb(len, GFP_KERNEL);
skb = dev_alloc_skb(len);
if (!skb)
return -ENOMEM;
@ -536,7 +536,7 @@ static int cc2520_rx(struct cc2520_private *priv)
skb_trim(skb, skb->len - 2);
ieee802154_rx_irqsafe(priv->dev, skb, lqi);
ieee802154_rx_irqsafe(priv->hw, skb, lqi);
dev_vdbg(&priv->spi->dev, "RXFIFO: %x %x\n", len, lqi);
@ -544,9 +544,9 @@ static int cc2520_rx(struct cc2520_private *priv)
}
static int
cc2520_ed(struct ieee802154_dev *dev, u8 *level)
cc2520_ed(struct ieee802154_hw *hw, u8 *level)
{
struct cc2520_private *priv = dev->priv;
struct cc2520_private *priv = hw->priv;
u8 status = 0xff;
u8 rssi;
int ret;
@ -569,12 +569,11 @@ cc2520_ed(struct ieee802154_dev *dev, u8 *level)
}
static int
cc2520_set_channel(struct ieee802154_dev *dev, int page, int channel)
cc2520_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
struct cc2520_private *priv = dev->priv;
struct cc2520_private *priv = hw->priv;
int ret;
might_sleep();
dev_dbg(&priv->spi->dev, "trying to set channel\n");
BUG_ON(page != 0);
@ -588,12 +587,12 @@ cc2520_set_channel(struct ieee802154_dev *dev, int page, int channel)
}
static int
cc2520_filter(struct ieee802154_dev *dev,
cc2520_filter(struct ieee802154_hw *hw,
struct ieee802154_hw_addr_filt *filt, unsigned long changed)
{
struct cc2520_private *priv = dev->priv;
struct cc2520_private *priv = hw->priv;
if (changed & IEEE802515_AFILT_PANID_CHANGED) {
if (changed & IEEE802154_AFILT_PANID_CHANGED) {
u16 panid = le16_to_cpu(filt->pan_id);
dev_vdbg(&priv->spi->dev,
@ -602,7 +601,7 @@ cc2520_filter(struct ieee802154_dev *dev,
sizeof(panid), (u8 *)&panid);
}
if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
dev_vdbg(&priv->spi->dev,
"cc2520_filter called for IEEE addr\n");
cc2520_write_ram(priv, CC2520RAM_IEEEADDR,
@ -610,7 +609,7 @@ cc2520_filter(struct ieee802154_dev *dev,
(u8 *)&filt->ieee_addr);
}
if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
u16 addr = le16_to_cpu(filt->short_addr);
dev_vdbg(&priv->spi->dev,
@ -619,7 +618,7 @@ cc2520_filter(struct ieee802154_dev *dev,
sizeof(addr), (u8 *)&addr);
}
if (changed & IEEE802515_AFILT_PANC_CHANGED) {
if (changed & IEEE802154_AFILT_PANC_CHANGED) {
dev_vdbg(&priv->spi->dev,
"cc2520_filter called for panc change\n");
if (filt->pan_coord)
@ -631,11 +630,11 @@ cc2520_filter(struct ieee802154_dev *dev,
return 0;
}
static struct ieee802154_ops cc2520_ops = {
static const struct ieee802154_ops cc2520_ops = {
.owner = THIS_MODULE,
.start = cc2520_start,
.stop = cc2520_stop,
.xmit = cc2520_tx,
.xmit_sync = cc2520_tx,
.ed = cc2520_ed,
.set_channel = cc2520_set_channel,
.set_hw_addr_filt = cc2520_filter,
@ -645,27 +644,28 @@ static int cc2520_register(struct cc2520_private *priv)
{
int ret = -ENOMEM;
priv->dev = ieee802154_alloc_device(sizeof(*priv), &cc2520_ops);
if (!priv->dev)
priv->hw = ieee802154_alloc_hw(sizeof(*priv), &cc2520_ops);
if (!priv->hw)
goto err_ret;
priv->dev->priv = priv;
priv->dev->parent = &priv->spi->dev;
priv->dev->extra_tx_headroom = 0;
priv->hw->priv = priv;
priv->hw->parent = &priv->spi->dev;
priv->hw->extra_tx_headroom = 0;
/* We do support only 2.4 Ghz */
priv->dev->phy->channels_supported[0] = 0x7FFF800;
priv->dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK;
priv->hw->phy->channels_supported[0] = 0x7FFF800;
priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
IEEE802154_HW_AFILT;
dev_vdbg(&priv->spi->dev, "registered cc2520\n");
ret = ieee802154_register_device(priv->dev);
ret = ieee802154_register_hw(priv->hw);
if (ret)
goto err_free_device;
return 0;
err_free_device:
ieee802154_free_device(priv->dev);
ieee802154_free_hw(priv->hw);
err_ret:
return ret;
}
@ -1002,8 +1002,8 @@ static int cc2520_remove(struct spi_device *spi)
mutex_destroy(&priv->buffer_mutex);
flush_work(&priv->fifop_irqwork);
ieee802154_unregister_device(priv->dev);
ieee802154_free_device(priv->dev);
ieee802154_unregister_hw(priv->hw);
ieee802154_free_hw(priv->hw);
return 0;
}

View File

@ -1,427 +0,0 @@
/*
* Sample driver for HardMAC IEEE 802.15.4 devices
*
* Copyright (C) 2009 Siemens AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by:
* Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <net/af_ieee802154.h>
#include <net/ieee802154_netdev.h>
#include <net/ieee802154.h>
#include <net/nl802154.h>
#include <net/wpan-phy.h>
struct fakehard_priv {
struct wpan_phy *phy;
};
static struct wpan_phy *fake_to_phy(const struct net_device *dev)
{
struct fakehard_priv *priv = netdev_priv(dev);
return priv->phy;
}
/**
* fake_get_phy - Return a phy corresponding to this device.
* @dev: The network device for which to return the wan-phy object
*
* This function returns a wpan-phy object corresponding to the passed
* network device. Reference counter for wpan-phy object is incremented,
* so when the wpan-phy isn't necessary, you should drop the reference
* via @wpan_phy_put() call.
*/
static struct wpan_phy *fake_get_phy(const struct net_device *dev)
{
struct wpan_phy *phy = fake_to_phy(dev);
return to_phy(get_device(&phy->dev));
}
/**
* fake_get_pan_id - Retrieve the PAN ID of the device.
* @dev: The network device to retrieve the PAN of.
*
* Return the ID of the PAN from the PIB.
*/
static __le16 fake_get_pan_id(const struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
return cpu_to_le16(0xeba1);
}
/**
* fake_get_short_addr - Retrieve the short address of the device.
* @dev: The network device to retrieve the short address of.
*
* Returns the IEEE 802.15.4 short-form address cached for this
* device. If the device has not yet had a short address assigned
* then this should return 0xFFFF to indicate a lack of association.
*/
static __le16 fake_get_short_addr(const struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
return cpu_to_le16(0x1);
}
/**
* fake_get_dsn - Retrieve the DSN of the device.
* @dev: The network device to retrieve the DSN for.
*
* Returns the IEEE 802.15.4 DSN for the network device.
* The DSN is the sequence number which will be added to each
* packet or MAC command frame by the MAC during transmission.
*
* DSN means 'Data Sequence Number'.
*
* Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
* document.
*/
static u8 fake_get_dsn(const struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
return 0x00; /* DSN are implemented in HW, so return just 0 */
}
/**
* fake_assoc_req - Make an association request to the HW.
* @dev: The network device which we are associating to a network.
* @addr: The coordinator with which we wish to associate.
* @channel: The channel on which to associate.
* @cap: The capability information field to use in the association.
*
* Start an association with a coordinator. The coordinator's address
* and PAN ID can be found in @addr.
*
* Note: This is in section 7.3.1 and 7.5.3.1 of the IEEE
* 802.15.4-2006 document.
*/
static int fake_assoc_req(struct net_device *dev,
struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap)
{
struct wpan_phy *phy = fake_to_phy(dev);
mutex_lock(&phy->pib_lock);
phy->current_channel = channel;
phy->current_page = page;
mutex_unlock(&phy->pib_lock);
/* We simply emulate it here */
return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev),
IEEE802154_SUCCESS);
}
/**
* fake_assoc_resp - Send an association response to a device.
* @dev: The network device on which to send the response.
* @addr: The address of the device to respond to.
* @short_addr: The assigned short address for the device (if any).
* @status: The result of the association request.
*
* Queue the association response of the coordinator to another
* device's attempt to associate with the network which we
* coordinate. This is then added to the indirect-send queue to be
* transmitted to the end device when it polls for data.
*
* Note: This is in section 7.3.2 and 7.5.3.1 of the IEEE
* 802.15.4-2006 document.
*/
static int fake_assoc_resp(struct net_device *dev,
struct ieee802154_addr *addr, __le16 short_addr, u8 status)
{
return 0;
}
/**
* fake_disassoc_req - Disassociate a device from a network.
* @dev: The network device on which we're disassociating a device.
* @addr: The device to disassociate from the network.
* @reason: The reason to give to the device for being disassociated.
*
* This sends a disassociation notification to the device being
* disassociated from the network.
*
* Note: This is in section 7.5.3.2 of the IEEE 802.15.4-2006
* document, with the reason described in 7.3.3.2.
*/
static int fake_disassoc_req(struct net_device *dev,
struct ieee802154_addr *addr, u8 reason)
{
return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS);
}
/**
* fake_start_req - Start an IEEE 802.15.4 PAN.
* @dev: The network device on which to start the PAN.
* @addr: The coordinator address to use when starting the PAN.
* @channel: The channel on which to start the PAN.
* @bcn_ord: Beacon order.
* @sf_ord: Superframe order.
* @pan_coord: Whether or not we are the PAN coordinator or just
* requesting a realignment perhaps?
* @blx: Battery Life Extension feature bitfield.
* @coord_realign: Something to realign something else.
*
* If pan_coord is non-zero then this starts a network with the
* provided parameters, otherwise it attempts a coordinator
* realignment of the stated network instead.
*
* Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
* document, with 7.3.8 describing coordinator realignment.
*/
static int fake_start_req(struct net_device *dev,
struct ieee802154_addr *addr, u8 channel, u8 page,
u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
u8 coord_realign)
{
struct wpan_phy *phy = fake_to_phy(dev);
mutex_lock(&phy->pib_lock);
phy->current_channel = channel;
phy->current_page = page;
mutex_unlock(&phy->pib_lock);
/* We don't emulate beacons here at all, so START should fail */
ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER);
return 0;
}
/**
* fake_scan_req - Start a channel scan.
* @dev: The network device on which to perform a channel scan.
* @type: The type of scan to perform.
* @channels: The channel bitmask to scan.
* @duration: How long to spend on each channel.
*
* This starts either a passive (energy) scan or an active (PAN) scan
* on the channels indicated in the @channels bitmask. The duration of
* the scan is measured in terms of superframe duration. Specifically,
* the scan will spend aBaseSuperFrameDuration * ((2^n) + 1) on each
* channel.
*
* Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document.
*/
static int fake_scan_req(struct net_device *dev, u8 type, u32 channels,
u8 page, u8 duration)
{
u8 edl[27] = {};
return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type,
channels, page,
type == IEEE802154_MAC_SCAN_ED ? edl : NULL);
}
static struct ieee802154_mlme_ops fake_mlme = {
.assoc_req = fake_assoc_req,
.assoc_resp = fake_assoc_resp,
.disassoc_req = fake_disassoc_req,
.start_req = fake_start_req,
.scan_req = fake_scan_req,
.get_phy = fake_get_phy,
.get_pan_id = fake_get_pan_id,
.get_short_addr = fake_get_short_addr,
.get_dsn = fake_get_dsn,
};
static int ieee802154_fake_open(struct net_device *dev)
{
netif_start_queue(dev);
return 0;
}
static int ieee802154_fake_close(struct net_device *dev)
{
netif_stop_queue(dev);
return 0;
}
static netdev_tx_t ieee802154_fake_xmit(struct sk_buff *skb,
struct net_device *dev)
{
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
/* FIXME: do hardware work here ... */
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
int cmd)
{
struct sockaddr_ieee802154 *sa =
(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
u16 pan_id, short_addr;
switch (cmd) {
case SIOCGIFADDR:
/* FIXME: fixed here, get from device IRL */
pan_id = le16_to_cpu(fake_get_pan_id(dev));
short_addr = le16_to_cpu(fake_get_short_addr(dev));
if (pan_id == IEEE802154_PANID_BROADCAST ||
short_addr == IEEE802154_ADDR_BROADCAST)
return -EADDRNOTAVAIL;
sa->family = AF_IEEE802154;
sa->addr.addr_type = IEEE802154_ADDR_SHORT;
sa->addr.pan_id = pan_id;
sa->addr.short_addr = short_addr;
return 0;
}
return -ENOIOCTLCMD;
}
static int ieee802154_fake_mac_addr(struct net_device *dev, void *p)
{
return -EBUSY; /* HW address is built into the device */
}
static const struct net_device_ops fake_ops = {
.ndo_open = ieee802154_fake_open,
.ndo_stop = ieee802154_fake_close,
.ndo_start_xmit = ieee802154_fake_xmit,
.ndo_do_ioctl = ieee802154_fake_ioctl,
.ndo_set_mac_address = ieee802154_fake_mac_addr,
};
static void ieee802154_fake_destruct(struct net_device *dev)
{
struct wpan_phy *phy = fake_to_phy(dev);
wpan_phy_unregister(phy);
free_netdev(dev);
wpan_phy_free(phy);
}
static void ieee802154_fake_setup(struct net_device *dev)
{
dev->addr_len = IEEE802154_ADDR_LEN;
memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
dev->features = NETIF_F_HW_CSUM;
dev->needed_tailroom = 2; /* FCS */
dev->mtu = 127;
dev->tx_queue_len = 10;
dev->type = ARPHRD_IEEE802154;
dev->flags = IFF_NOARP | IFF_BROADCAST;
dev->watchdog_timeo = 0;
dev->destructor = ieee802154_fake_destruct;
}
static int ieee802154fake_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct fakehard_priv *priv;
struct wpan_phy *phy = wpan_phy_alloc(0);
int err;
if (!phy)
return -ENOMEM;
dev = alloc_netdev(sizeof(struct fakehard_priv), "hardwpan%d",
NET_NAME_UNKNOWN, ieee802154_fake_setup);
if (!dev) {
wpan_phy_free(phy);
return -ENOMEM;
}
memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
dev->addr_len);
/*
* For now we'd like to emulate 2.4 GHz-only device,
* both O-QPSK and CSS
*/
/* 2.4 GHz O-QPSK 802.15.4-2003 */
phy->channels_supported[0] |= 0x7FFF800;
/* 2.4 GHz CSS 802.15.4a-2007 */
phy->channels_supported[3] |= 0x3fff;
phy->transmit_power = 0xbf;
dev->netdev_ops = &fake_ops;
dev->ml_priv = &fake_mlme;
priv = netdev_priv(dev);
priv->phy = phy;
wpan_phy_set_dev(phy, &pdev->dev);
SET_NETDEV_DEV(dev, &phy->dev);
platform_set_drvdata(pdev, dev);
err = wpan_phy_register(phy);
if (err)
goto out;
err = register_netdev(dev);
if (err < 0)
goto out;
dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n");
return 0;
out:
unregister_netdev(dev);
return err;
}
static int ieee802154fake_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
unregister_netdev(dev);
return 0;
}
static struct platform_device *ieee802154fake_dev;
static struct platform_driver ieee802154fake_driver = {
.probe = ieee802154fake_probe,
.remove = ieee802154fake_remove,
.driver = {
.name = "ieee802154hardmac",
.owner = THIS_MODULE,
},
};
static __init int fake_init(void)
{
ieee802154fake_dev = platform_device_register_simple(
"ieee802154hardmac", -1, NULL, 0);
return platform_driver_register(&ieee802154fake_driver);
}
static __exit void fake_exit(void)
{
platform_driver_unregister(&ieee802154fake_driver);
platform_device_unregister(ieee802154fake_dev);
}
module_init(fake_init);
module_exit(fake_exit);
MODULE_LICENSE("GPL");

View File

@ -12,10 +12,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
@ -29,12 +25,12 @@
#include <linux/device.h>
#include <linux/spinlock.h>
#include <net/mac802154.h>
#include <net/wpan-phy.h>
#include <net/cfg802154.h>
static int numlbs = 1;
struct fakelb_dev_priv {
struct ieee802154_dev *dev;
struct ieee802154_hw *hw;
struct list_head list;
struct fakelb_priv *fake;
@ -49,9 +45,8 @@ struct fakelb_priv {
};
static int
fakelb_hw_ed(struct ieee802154_dev *dev, u8 *level)
fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level)
{
might_sleep();
BUG_ON(!level);
*level = 0xbe;
@ -59,13 +54,12 @@ fakelb_hw_ed(struct ieee802154_dev *dev, u8 *level)
}
static int
fakelb_hw_channel(struct ieee802154_dev *dev, int page, int channel)
fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
pr_debug("set channel to %d\n", channel);
might_sleep();
dev->phy->current_page = page;
dev->phy->current_channel = channel;
hw->phy->current_page = page;
hw->phy->current_channel = channel;
return 0;
}
@ -78,19 +72,17 @@ fakelb_hw_deliver(struct fakelb_dev_priv *priv, struct sk_buff *skb)
spin_lock(&priv->lock);
if (priv->working) {
newskb = pskb_copy(skb, GFP_ATOMIC);
ieee802154_rx_irqsafe(priv->dev, newskb, 0xcc);
ieee802154_rx_irqsafe(priv->hw, newskb, 0xcc);
}
spin_unlock(&priv->lock);
}
static int
fakelb_hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
{
struct fakelb_dev_priv *priv = dev->priv;
struct fakelb_dev_priv *priv = hw->priv;
struct fakelb_priv *fake = priv->fake;
might_sleep();
read_lock_bh(&fake->lock);
if (priv->list.next == priv->list.prev) {
/* we are the only one device */
@ -99,8 +91,8 @@ fakelb_hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
struct fakelb_dev_priv *dp;
list_for_each_entry(dp, &priv->fake->list, list) {
if (dp != priv &&
(dp->dev->phy->current_channel ==
priv->dev->phy->current_channel))
(dp->hw->phy->current_channel ==
priv->hw->phy->current_channel))
fakelb_hw_deliver(dp, skb);
}
}
@ -110,8 +102,8 @@ fakelb_hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
}
static int
fakelb_hw_start(struct ieee802154_dev *dev) {
struct fakelb_dev_priv *priv = dev->priv;
fakelb_hw_start(struct ieee802154_hw *hw) {
struct fakelb_dev_priv *priv = hw->priv;
int ret = 0;
spin_lock(&priv->lock);
@ -125,17 +117,17 @@ fakelb_hw_start(struct ieee802154_dev *dev) {
}
static void
fakelb_hw_stop(struct ieee802154_dev *dev) {
struct fakelb_dev_priv *priv = dev->priv;
fakelb_hw_stop(struct ieee802154_hw *hw) {
struct fakelb_dev_priv *priv = hw->priv;
spin_lock(&priv->lock);
priv->working = 0;
spin_unlock(&priv->lock);
}
static struct ieee802154_ops fakelb_ops = {
static const struct ieee802154_ops fakelb_ops = {
.owner = THIS_MODULE,
.xmit = fakelb_hw_xmit,
.xmit_sync = fakelb_hw_xmit,
.ed = fakelb_hw_ed,
.set_channel = fakelb_hw_channel,
.start = fakelb_hw_start,
@ -150,54 +142,54 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake)
{
struct fakelb_dev_priv *priv;
int err;
struct ieee802154_dev *ieee;
struct ieee802154_hw *hw;
ieee = ieee802154_alloc_device(sizeof(*priv), &fakelb_ops);
if (!ieee)
hw = ieee802154_alloc_hw(sizeof(*priv), &fakelb_ops);
if (!hw)
return -ENOMEM;
priv = ieee->priv;
priv->dev = ieee;
priv = hw->priv;
priv->hw = hw;
/* 868 MHz BPSK 802.15.4-2003 */
ieee->phy->channels_supported[0] |= 1;
hw->phy->channels_supported[0] |= 1;
/* 915 MHz BPSK 802.15.4-2003 */
ieee->phy->channels_supported[0] |= 0x7fe;
hw->phy->channels_supported[0] |= 0x7fe;
/* 2.4 GHz O-QPSK 802.15.4-2003 */
ieee->phy->channels_supported[0] |= 0x7FFF800;
hw->phy->channels_supported[0] |= 0x7FFF800;
/* 868 MHz ASK 802.15.4-2006 */
ieee->phy->channels_supported[1] |= 1;
hw->phy->channels_supported[1] |= 1;
/* 915 MHz ASK 802.15.4-2006 */
ieee->phy->channels_supported[1] |= 0x7fe;
hw->phy->channels_supported[1] |= 0x7fe;
/* 868 MHz O-QPSK 802.15.4-2006 */
ieee->phy->channels_supported[2] |= 1;
hw->phy->channels_supported[2] |= 1;
/* 915 MHz O-QPSK 802.15.4-2006 */
ieee->phy->channels_supported[2] |= 0x7fe;
hw->phy->channels_supported[2] |= 0x7fe;
/* 2.4 GHz CSS 802.15.4a-2007 */
ieee->phy->channels_supported[3] |= 0x3fff;
hw->phy->channels_supported[3] |= 0x3fff;
/* UWB Sub-gigahertz 802.15.4a-2007 */
ieee->phy->channels_supported[4] |= 1;
hw->phy->channels_supported[4] |= 1;
/* UWB Low band 802.15.4a-2007 */
ieee->phy->channels_supported[4] |= 0x1e;
hw->phy->channels_supported[4] |= 0x1e;
/* UWB High band 802.15.4a-2007 */
ieee->phy->channels_supported[4] |= 0xffe0;
hw->phy->channels_supported[4] |= 0xffe0;
/* 750 MHz O-QPSK 802.15.4c-2009 */
ieee->phy->channels_supported[5] |= 0xf;
hw->phy->channels_supported[5] |= 0xf;
/* 750 MHz MPSK 802.15.4c-2009 */
ieee->phy->channels_supported[5] |= 0xf0;
hw->phy->channels_supported[5] |= 0xf0;
/* 950 MHz BPSK 802.15.4d-2009 */
ieee->phy->channels_supported[6] |= 0x3ff;
hw->phy->channels_supported[6] |= 0x3ff;
/* 950 MHz GFSK 802.15.4d-2009 */
ieee->phy->channels_supported[6] |= 0x3ffc00;
hw->phy->channels_supported[6] |= 0x3ffc00;
INIT_LIST_HEAD(&priv->list);
priv->fake = fake;
spin_lock_init(&priv->lock);
ieee->parent = dev;
hw->parent = dev;
err = ieee802154_register_device(ieee);
err = ieee802154_register_hw(hw);
if (err)
goto err_reg;
@ -208,7 +200,7 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake)
return 0;
err_reg:
ieee802154_free_device(priv->dev);
ieee802154_free_hw(priv->hw);
return err;
}
@ -218,8 +210,8 @@ static void fakelb_del(struct fakelb_dev_priv *priv)
list_del(&priv->list);
write_unlock_bh(&priv->fake->lock);
ieee802154_unregister_device(priv->dev);
ieee802154_free_device(priv->dev);
ieee802154_unregister_hw(priv->hw);
ieee802154_free_hw(priv->hw);
}
static int fakelb_probe(struct platform_device *pdev)

View File

@ -13,18 +13,14 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/spi/spi.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <net/wpan-phy.h>
#include <linux/ieee802154.h>
#include <net/cfg802154.h>
#include <net/mac802154.h>
#include <net/ieee802154.h>
/* MRF24J40 Short Address Registers */
#define REG_RXMCR 0x00 /* Receive MAC control */
@ -43,6 +39,8 @@
#define REG_TXSTBL 0x2E /* TX Stabilization */
#define REG_INTSTAT 0x31 /* Interrupt Status */
#define REG_INTCON 0x32 /* Interrupt Control */
#define REG_GPIO 0x33 /* GPIO */
#define REG_TRISGPIO 0x34 /* GPIO direction */
#define REG_RFCTL 0x36 /* RF Control Mode Register */
#define REG_BBREG1 0x39 /* Baseband Registers */
#define REG_BBREG2 0x3A /* */
@ -63,6 +61,7 @@
#define REG_SLPCON1 0x220
#define REG_WAKETIMEL 0x222 /* Wake-up Time Match Value Low */
#define REG_WAKETIMEH 0x223 /* Wake-up Time Match Value High */
#define REG_TESTMODE 0x22F /* Test mode */
#define REG_RX_FIFO 0x300 /* Receive FIFO */
/* Device configuration: Only channels 11-26 on page 0 are supported. */
@ -75,10 +74,12 @@
#define RX_FIFO_SIZE 144 /* From datasheet */
#define SET_CHANNEL_DELAY_US 192 /* From datasheet */
enum mrf24j40_modules { MRF24J40, MRF24J40MA, MRF24J40MC };
/* Device Private Data */
struct mrf24j40 {
struct spi_device *spi;
struct ieee802154_dev *dev;
struct ieee802154_hw *hw;
struct mutex buffer_mutex; /* only used to protect buf */
struct completion tx_complete;
@ -331,9 +332,9 @@ out:
return ret;
}
static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
static int mrf24j40_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
{
struct mrf24j40 *devrec = dev->priv;
struct mrf24j40 *devrec = hw->priv;
u8 val;
int ret = 0;
@ -382,7 +383,7 @@ err:
return ret;
}
static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level)
static int mrf24j40_ed(struct ieee802154_hw *hw, u8 *level)
{
/* TODO: */
pr_warn("mrf24j40: ed not implemented\n");
@ -390,9 +391,9 @@ static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level)
return 0;
}
static int mrf24j40_start(struct ieee802154_dev *dev)
static int mrf24j40_start(struct ieee802154_hw *hw)
{
struct mrf24j40 *devrec = dev->priv;
struct mrf24j40 *devrec = hw->priv;
u8 val;
int ret;
@ -407,9 +408,9 @@ static int mrf24j40_start(struct ieee802154_dev *dev)
return 0;
}
static void mrf24j40_stop(struct ieee802154_dev *dev)
static void mrf24j40_stop(struct ieee802154_hw *hw)
{
struct mrf24j40 *devrec = dev->priv;
struct mrf24j40 *devrec = hw->priv;
u8 val;
int ret;
@ -422,10 +423,9 @@ static void mrf24j40_stop(struct ieee802154_dev *dev)
write_short_reg(devrec, REG_INTCON, val);
}
static int mrf24j40_set_channel(struct ieee802154_dev *dev,
int page, int channel)
static int mrf24j40_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
struct mrf24j40 *devrec = dev->priv;
struct mrf24j40 *devrec = hw->priv;
u8 val;
int ret;
@ -453,15 +453,15 @@ static int mrf24j40_set_channel(struct ieee802154_dev *dev,
return 0;
}
static int mrf24j40_filter(struct ieee802154_dev *dev,
static int mrf24j40_filter(struct ieee802154_hw *hw,
struct ieee802154_hw_addr_filt *filt,
unsigned long changed)
{
struct mrf24j40 *devrec = dev->priv;
struct mrf24j40 *devrec = hw->priv;
dev_dbg(printdev(devrec), "filter\n");
if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
/* Short Addr */
u8 addrh, addrl;
@ -474,7 +474,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
"Set short addr to %04hx\n", filt->short_addr);
}
if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
/* Device Address */
u8 i, addr[8];
@ -490,7 +490,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
#endif
}
if (changed & IEEE802515_AFILT_PANID_CHANGED) {
if (changed & IEEE802154_AFILT_PANID_CHANGED) {
/* PAN ID */
u8 panidl, panidh;
@ -502,7 +502,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
dev_dbg(printdev(devrec), "Set PANID to %04hx\n", filt->pan_id);
}
if (changed & IEEE802515_AFILT_PANC_CHANGED) {
if (changed & IEEE802154_AFILT_PANC_CHANGED) {
/* Pan Coordinator */
u8 val;
int ret;
@ -543,7 +543,7 @@ static int mrf24j40_handle_rx(struct mrf24j40 *devrec)
val |= 4; /* SET RXDECINV */
write_short_reg(devrec, REG_BBREG1, val);
skb = alloc_skb(len, GFP_KERNEL);
skb = dev_alloc_skb(len);
if (!skb) {
ret = -ENOMEM;
goto out;
@ -563,7 +563,7 @@ static int mrf24j40_handle_rx(struct mrf24j40 *devrec)
/* TODO: Other drivers call ieee20154_rx_irqsafe() here (eg: cc2040,
* also from a workqueue). I think irqsafe is not necessary here.
* Can someone confirm? */
ieee802154_rx_irqsafe(devrec->dev, skb, lqi);
ieee802154_rx_irqsafe(devrec->hw, skb, lqi);
dev_dbg(printdev(devrec), "RX Handled\n");
@ -578,9 +578,9 @@ out:
return ret;
}
static struct ieee802154_ops mrf24j40_ops = {
static const struct ieee802154_ops mrf24j40_ops = {
.owner = THIS_MODULE,
.xmit = mrf24j40_tx,
.xmit_sync = mrf24j40_tx,
.ed = mrf24j40_ed,
.start = mrf24j40_start,
.stop = mrf24j40_stop,
@ -691,6 +691,28 @@ static int mrf24j40_hw_init(struct mrf24j40 *devrec)
if (ret)
goto err_ret;
if (spi_get_device_id(devrec->spi)->driver_data == MRF24J40MC) {
/* Enable external amplifier.
* From MRF24J40MC datasheet section 1.3: Operation.
*/
read_long_reg(devrec, REG_TESTMODE, &val);
val |= 0x7; /* Configure GPIO 0-2 to control amplifier */
write_long_reg(devrec, REG_TESTMODE, val);
read_short_reg(devrec, REG_TRISGPIO, &val);
val |= 0x8; /* Set GPIO3 as output. */
write_short_reg(devrec, REG_TRISGPIO, val);
read_short_reg(devrec, REG_GPIO, &val);
val |= 0x8; /* Set GPIO3 HIGH to enable U5 voltage regulator */
write_short_reg(devrec, REG_GPIO, val);
/* Reduce TX pwr to meet FCC requirements.
* From MRF24J40MC datasheet section 3.1.1
*/
write_long_reg(devrec, REG_RFCON3, 0x28);
}
return 0;
err_ret:
@ -722,17 +744,18 @@ static int mrf24j40_probe(struct spi_device *spi)
/* Register with the 802154 subsystem */
devrec->dev = ieee802154_alloc_device(0, &mrf24j40_ops);
if (!devrec->dev)
devrec->hw = ieee802154_alloc_hw(0, &mrf24j40_ops);
if (!devrec->hw)
goto err_ret;
devrec->dev->priv = devrec;
devrec->dev->parent = &devrec->spi->dev;
devrec->dev->phy->channels_supported[0] = CHANNEL_MASK;
devrec->dev->flags = IEEE802154_HW_OMIT_CKSUM|IEEE802154_HW_AACK;
devrec->hw->priv = devrec;
devrec->hw->parent = &devrec->spi->dev;
devrec->hw->phy->channels_supported[0] = CHANNEL_MASK;
devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
IEEE802154_HW_AFILT;
dev_dbg(printdev(devrec), "registered mrf24j40\n");
ret = ieee802154_register_device(devrec->dev);
ret = ieee802154_register_hw(devrec->hw);
if (ret)
goto err_register_device;
@ -757,9 +780,9 @@ static int mrf24j40_probe(struct spi_device *spi)
err_irq:
err_hw_init:
ieee802154_unregister_device(devrec->dev);
ieee802154_unregister_hw(devrec->hw);
err_register_device:
ieee802154_free_device(devrec->dev);
ieee802154_free_hw(devrec->hw);
err_ret:
return ret;
}
@ -770,8 +793,8 @@ static int mrf24j40_remove(struct spi_device *spi)
dev_dbg(printdev(devrec), "remove\n");
ieee802154_unregister_device(devrec->dev);
ieee802154_free_device(devrec->dev);
ieee802154_unregister_hw(devrec->hw);
ieee802154_free_hw(devrec->hw);
/* TODO: Will ieee802154_free_device() wait until ->xmit() is
* complete? */
@ -779,8 +802,9 @@ static int mrf24j40_remove(struct spi_device *spi)
}
static const struct spi_device_id mrf24j40_ids[] = {
{ "mrf24j40", 0 },
{ "mrf24j40ma", 0 },
{ "mrf24j40", MRF24J40 },
{ "mrf24j40ma", MRF24J40MA },
{ "mrf24j40mc", MRF24J40MC },
{ },
};
MODULE_DEVICE_TABLE(spi, mrf24j40_ids);

View File

@ -148,7 +148,7 @@ struct ath_common {
u16 cachelsz;
u16 curaid;
u8 macaddr[ETH_ALEN];
u8 curbssid[ETH_ALEN];
u8 curbssid[ETH_ALEN] __aligned(2);
u8 bssidmask[ETH_ALEN];
u32 rx_bufsize;

View File

@ -443,12 +443,12 @@ int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
* Guts of ath10k_ce_completed_recv_next.
* The caller takes responsibility for any necessary locking.
*/
static int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
u32 *bufferp,
unsigned int *nbytesp,
unsigned int *transfer_idp,
unsigned int *flagsp)
int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
u32 *bufferp,
unsigned int *nbytesp,
unsigned int *transfer_idp,
unsigned int *flagsp)
{
struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
unsigned int nentries_mask = dest_ring->nentries_mask;
@ -576,11 +576,11 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
* Guts of ath10k_ce_completed_send_next.
* The caller takes responsibility for any necessary locking.
*/
static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
u32 *bufferp,
unsigned int *nbytesp,
unsigned int *transfer_idp)
int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
u32 *bufferp,
unsigned int *nbytesp,
unsigned int *transfer_idp)
{
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
u32 ctrl_addr = ce_state->ctrl_addr;
@ -817,7 +817,10 @@ void ath10k_ce_enable_interrupts(struct ath10k *ar)
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ce_id;
for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
/* Skip the last copy engine, CE7 the diagnostic window, as that
* uses polling and isn't initialized for interrupts.
*/
for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++)
ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]);
}
@ -1020,37 +1023,10 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
* initialized by software/firmware.
*/
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
const struct ce_attr *attr,
void (*send_cb)(struct ath10k_ce_pipe *),
void (*recv_cb)(struct ath10k_ce_pipe *))
const struct ce_attr *attr)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
int ret;
/*
* Make sure there's enough CE ringbuffer entries for HTT TX to avoid
* additional TX locking checks.
*
* For the lack of a better place do the check here.
*/
BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
spin_lock_bh(&ar_pci->ce_lock);
ce_state->ar = ar;
ce_state->id = ce_id;
ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
ce_state->attr_flags = attr->flags;
ce_state->src_sz_max = attr->src_sz_max;
if (attr->src_nentries)
ce_state->send_cb = send_cb;
if (attr->dest_nentries)
ce_state->recv_cb = recv_cb;
spin_unlock_bh(&ar_pci->ce_lock);
if (attr->src_nentries) {
ret = ath10k_ce_init_src_ring(ar, ce_id, attr);
if (ret) {
@ -1098,12 +1074,37 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id)
}
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
const struct ce_attr *attr)
const struct ce_attr *attr,
void (*send_cb)(struct ath10k_ce_pipe *),
void (*recv_cb)(struct ath10k_ce_pipe *))
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
int ret;
/*
* Make sure there's enough CE ringbuffer entries for HTT TX to avoid
* additional TX locking checks.
*
* For the lack of a better place do the check here.
*/
BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
ce_state->ar = ar;
ce_state->id = ce_id;
ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
ce_state->attr_flags = attr->flags;
ce_state->src_sz_max = attr->src_sz_max;
if (attr->src_nentries)
ce_state->send_cb = send_cb;
if (attr->dest_nentries)
ce_state->recv_cb = recv_cb;
if (attr->src_nentries) {
ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
if (IS_ERR(ce_state->src_ring)) {

View File

@ -192,15 +192,21 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
unsigned int *nbytesp,
unsigned int *transfer_idp);
int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
u32 *bufferp,
unsigned int *nbytesp,
unsigned int *transfer_idp);
/*==================CE Engine Initialization=======================*/
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
const struct ce_attr *attr,
void (*send_cb)(struct ath10k_ce_pipe *),
void (*recv_cb)(struct ath10k_ce_pipe *));
const struct ce_attr *attr);
void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
const struct ce_attr *attr);
const struct ce_attr *attr,
void (*send_cb)(struct ath10k_ce_pipe *),
void (*recv_cb)(struct ath10k_ce_pipe *));
void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
/*==================CE Engine Shutdown=======================*/
@ -213,6 +219,13 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
u32 *bufferp);
int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp,
u32 *bufferp,
unsigned int *nbytesp,
unsigned int *transfer_idp,
unsigned int *flagsp);
/*
* Support clean shutdown by allowing the caller to cancel
* pending sends. Target DMA must be stopped before using

View File

@ -138,7 +138,8 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
return fw;
}
static int ath10k_push_board_ext_data(struct ath10k *ar)
static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
size_t data_len)
{
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ;
@ -159,14 +160,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
if (board_ext_data_addr == 0)
return 0;
if (ar->board_len != (board_data_size + board_ext_data_size)) {
if (data_len != (board_data_size + board_ext_data_size)) {
ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n",
ar->board_len, board_data_size, board_ext_data_size);
data_len, board_data_size, board_ext_data_size);
return -EINVAL;
}
ret = ath10k_bmi_write_memory(ar, board_ext_data_addr,
ar->board_data + board_data_size,
data + board_data_size,
board_ext_data_size);
if (ret) {
ath10k_err(ar, "could not write board ext data (%d)\n", ret);
@ -184,13 +185,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
return 0;
}
static int ath10k_download_board_data(struct ath10k *ar)
static int ath10k_download_board_data(struct ath10k *ar, const void *data,
size_t data_len)
{
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
u32 address;
int ret;
ret = ath10k_push_board_ext_data(ar);
ret = ath10k_push_board_ext_data(ar, data, data_len);
if (ret) {
ath10k_err(ar, "could not push board ext data (%d)\n", ret);
goto exit;
@ -202,9 +204,9 @@ static int ath10k_download_board_data(struct ath10k *ar)
goto exit;
}
ret = ath10k_bmi_write_memory(ar, address, ar->board_data,
ret = ath10k_bmi_write_memory(ar, address, data,
min_t(u32, board_data_size,
ar->board_len));
data_len));
if (ret) {
ath10k_err(ar, "could not write board data (%d)\n", ret);
goto exit;
@ -220,11 +222,39 @@ exit:
return ret;
}
static int ath10k_download_cal_file(struct ath10k *ar)
{
int ret;
if (!ar->cal_file)
return -ENOENT;
if (IS_ERR(ar->cal_file))
return PTR_ERR(ar->cal_file);
ret = ath10k_download_board_data(ar, ar->cal_file->data,
ar->cal_file->size);
if (ret) {
ath10k_err(ar, "failed to download cal_file data: %d\n", ret);
return ret;
}
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n");
return 0;
}
static int ath10k_download_and_run_otp(struct ath10k *ar)
{
u32 result, address = ar->hw_params.patch_load_addr;
int ret;
ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len);
if (ret) {
ath10k_err(ar, "failed to download board data: %d\n", ret);
return ret;
}
/* OTP is optional */
if (!ar->otp_data || !ar->otp_len) {
@ -308,6 +338,9 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
if (ar->firmware && !IS_ERR(ar->firmware))
release_firmware(ar->firmware);
if (ar->cal_file && !IS_ERR(ar->cal_file))
release_firmware(ar->cal_file);
ar->board = NULL;
ar->board_data = NULL;
ar->board_len = 0;
@ -319,6 +352,27 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
ar->firmware = NULL;
ar->firmware_data = NULL;
ar->firmware_len = 0;
ar->cal_file = NULL;
}
static int ath10k_fetch_cal_file(struct ath10k *ar)
{
char filename[100];
/* cal-<bus>-<id>.bin */
scnprintf(filename, sizeof(filename), "cal-%s-%s.bin",
ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));
ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename);
if (IS_ERR(ar->cal_file))
/* calibration file is optional, don't print any warnings */
return PTR_ERR(ar->cal_file);
ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n",
ATH10K_FW_DIR, filename);
return 0;
}
static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
@ -562,6 +616,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
{
int ret;
/* calibration file is optional, don't check for any errors */
ath10k_fetch_cal_file(ar);
ar->fw_api = 3;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
@ -589,30 +646,32 @@ success:
return 0;
}
static int ath10k_init_download_firmware(struct ath10k *ar,
enum ath10k_firmware_mode mode)
static int ath10k_download_cal_data(struct ath10k *ar)
{
int ret;
ret = ath10k_download_board_data(ar);
if (ret) {
ath10k_err(ar, "failed to download board data: %d\n", ret);
return ret;
ret = ath10k_download_cal_file(ar);
if (ret == 0) {
ar->cal_mode = ATH10K_CAL_MODE_FILE;
goto done;
}
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot did not find a calibration file, try OTP next: %d\n",
ret);
ret = ath10k_download_and_run_otp(ar);
if (ret) {
ath10k_err(ar, "failed to run otp: %d\n", ret);
return ret;
}
ret = ath10k_download_fw(ar, mode);
if (ret) {
ath10k_err(ar, "failed to download firmware: %d\n", ret);
return ret;
}
ar->cal_mode = ATH10K_CAL_MODE_OTP;
return ret;
done:
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n",
ath10k_cal_mode_str(ar->cal_mode));
return 0;
}
static int ath10k_init_uart(struct ath10k *ar)
@ -729,7 +788,11 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
goto err;
}
status = ath10k_init_download_firmware(ar, mode);
status = ath10k_download_cal_data(ar);
if (status)
goto err;
status = ath10k_download_fw(ar, mode);
if (status)
goto err;
@ -846,9 +909,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
goto err_hif_stop;
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1;
ar->free_vdev_map = (1LL << TARGET_10X_NUM_VDEVS) - 1;
else
ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1;
INIT_LIST_HEAD(&ar->arvifs);
@ -1084,6 +1147,7 @@ void ath10k_core_unregister(struct ath10k *ar)
EXPORT_SYMBOL(ath10k_core_unregister);
struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
enum ath10k_bus bus,
const struct ath10k_hif_ops *hif_ops)
{
struct ath10k *ar;
@ -1100,6 +1164,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
ar->dev = dev;
ar->hif.ops = hif_ops;
ar->hif.bus = bus;
init_completion(&ar->scan.started);
init_completion(&ar->scan.completed);

View File

@ -63,6 +63,20 @@
struct ath10k;
enum ath10k_bus {
ATH10K_BUS_PCI,
};
static inline const char *ath10k_bus_str(enum ath10k_bus bus)
{
switch (bus) {
case ATH10K_BUS_PCI:
return "pci";
}
return "unknown";
}
struct ath10k_skb_cb {
dma_addr_t paddr;
u8 vdev_id;
@ -96,8 +110,6 @@ struct ath10k_bmi {
bool done_sent;
};
#define ATH10K_MAX_MEM_REQS 16
struct ath10k_mem_chunk {
void *vaddr;
dma_addr_t paddr;
@ -115,17 +127,21 @@ struct ath10k_wmi {
struct wmi_pdev_param_map *pdev_param;
u32 num_mem_chunks;
struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS];
struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];
};
struct ath10k_peer_stat {
struct ath10k_fw_stats_peer {
struct list_head list;
u8 peer_macaddr[ETH_ALEN];
u32 peer_rssi;
u32 peer_tx_rate;
u32 peer_rx_rate; /* 10x only */
};
struct ath10k_target_stats {
struct ath10k_fw_stats_pdev {
struct list_head list;
/* PDEV stats */
s32 ch_noise_floor;
u32 tx_frame_count;
@ -180,15 +196,11 @@ struct ath10k_target_stats {
s32 phy_errs;
s32 phy_err_drop;
s32 mpdu_errs;
};
/* VDEV STATS */
/* PEER STATS */
u8 peers;
struct ath10k_peer_stat peer_stat[TARGET_NUM_PEERS];
/* TODO: Beacon filter stats */
struct ath10k_fw_stats {
struct list_head pdevs;
struct list_head peers;
};
struct ath10k_dfs_stats {
@ -234,6 +246,8 @@ struct ath10k_vif {
struct sk_buff *beacon;
/* protected by data_lock */
bool beacon_sent;
void *beacon_buf;
dma_addr_t beacon_paddr;
struct ath10k *ar;
struct ieee80211_vif *vif;
@ -273,6 +287,7 @@ struct ath10k_vif {
u8 force_sgi;
bool use_cts_prot;
int num_legacy_stations;
int txpower;
};
struct ath10k_vif_iter {
@ -292,17 +307,19 @@ struct ath10k_fw_crash_data {
struct ath10k_debug {
struct dentry *debugfs_phy;
struct ath10k_target_stats target_stats;
struct ath10k_fw_stats fw_stats;
struct completion fw_stats_complete;
bool fw_stats_done;
DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_MAX);
struct completion event_stats_compl;
unsigned long htt_stats_mask;
struct delayed_work htt_stats_dwork;
struct ath10k_dfs_stats dfs_stats;
struct ath_dfs_pool_stats dfs_pool_stats;
/* protected by conf_mutex */
u32 fw_dbglog_mask;
u32 pktlog_filter;
u8 htt_max_amsdu;
u8 htt_max_ampdu;
@ -321,7 +338,7 @@ enum ath10k_state {
* stopped in ath10k_core_restart() work holding conf_mutex. The state
* RESTARTED means that the device is up and mac80211 has started hw
* reconfiguration. Once mac80211 is done with the reconfiguration we
* set the state to STATE_ON in restart_complete(). */
* set the state to STATE_ON in reconfig_complete(). */
ATH10K_STATE_RESTARTING,
ATH10K_STATE_RESTARTED,
@ -371,6 +388,23 @@ enum ath10k_dev_flags {
ATH10K_FLAG_CORE_REGISTERED,
};
enum ath10k_cal_mode {
ATH10K_CAL_MODE_FILE,
ATH10K_CAL_MODE_OTP,
};
static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
{
switch (mode) {
case ATH10K_CAL_MODE_FILE:
return "file";
case ATH10K_CAL_MODE_OTP:
return "otp";
}
return "unknown";
}
enum ath10k_scan_state {
ATH10K_SCAN_IDLE,
ATH10K_SCAN_STARTING,
@ -421,6 +455,7 @@ struct ath10k {
bool p2p;
struct {
enum ath10k_bus bus;
const struct ath10k_hif_ops *ops;
} hif;
@ -456,7 +491,10 @@ struct ath10k {
const void *firmware_data;
size_t firmware_len;
const struct firmware *cal_file;
int fw_api;
enum ath10k_cal_mode cal_mode;
struct {
struct completion started;
@ -482,7 +520,7 @@ struct ath10k {
/* current operating channel definition */
struct cfg80211_chan_def chandef;
int free_vdev_map;
unsigned long long free_vdev_map;
bool monitor;
int monitor_vdev_id;
bool monitor_started;
@ -563,11 +601,19 @@ struct ath10k {
bool utf_monitor;
} testmode;
struct {
/* protected by data_lock */
u32 fw_crash_counter;
u32 fw_warm_reset_counter;
u32 fw_cold_reset_counter;
} stats;
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
enum ath10k_bus bus,
const struct ath10k_hif_ops *hif_ops);
void ath10k_core_destroy(struct ath10k *ar);

File diff suppressed because it is too large Load Diff

View File

@ -38,11 +38,20 @@ enum ath10k_debug_mask {
ATH10K_DBG_ANY = 0xffffffff,
};
enum ath10k_pktlog_filter {
ATH10K_PKTLOG_RX = 0x000000001,
ATH10K_PKTLOG_TX = 0x000000002,
ATH10K_PKTLOG_RCFIND = 0x000000004,
ATH10K_PKTLOG_RCUPDATE = 0x000000008,
ATH10K_PKTLOG_DBG_PRINT = 0x000000010,
ATH10K_PKTLOG_ANY = 0x00000001f,
};
extern unsigned int ath10k_debug_mask;
__printf(2, 3) int ath10k_info(struct ath10k *ar, const char *fmt, ...);
__printf(2, 3) int ath10k_err(struct ath10k *ar, const char *fmt, ...);
__printf(2, 3) int ath10k_warn(struct ath10k *ar, const char *fmt, ...);
__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...);
__printf(2, 3) void ath10k_err(struct ath10k *ar, const char *fmt, ...);
__printf(2, 3) void ath10k_warn(struct ath10k *ar, const char *fmt, ...);
void ath10k_print_driver_info(struct ath10k *ar);
#ifdef CONFIG_ATH10K_DEBUGFS
@ -53,17 +62,24 @@ void ath10k_debug_destroy(struct ath10k *ar);
int ath10k_debug_register(struct ath10k *ar);
void ath10k_debug_unregister(struct ath10k *ar);
void ath10k_debug_read_service_map(struct ath10k *ar,
void *service_map,
const void *service_map,
size_t map_size);
void ath10k_debug_read_target_stats(struct ath10k *ar,
struct wmi_stats_event *ev);
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
struct ath10k_fw_crash_data *
ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u32 sset, u8 *data);
int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int sset);
void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data);
#else
static inline int ath10k_debug_start(struct ath10k *ar)
{
@ -93,13 +109,13 @@ static inline void ath10k_debug_unregister(struct ath10k *ar)
}
static inline void ath10k_debug_read_service_map(struct ath10k *ar,
void *service_map,
const void *service_map,
size_t map_size)
{
}
static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
struct wmi_stats_event *ev)
static inline void ath10k_debug_fw_stats_process(struct ath10k *ar,
struct sk_buff *skb)
{
}
@ -116,6 +132,10 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
#define ath10k_debug_get_et_strings NULL
#define ath10k_debug_get_et_sset_count NULL
#define ath10k_debug_get_et_stats NULL
#endif /* CONFIG_ATH10K_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG

View File

@ -43,6 +43,10 @@ struct ath10k_hif_ops {
int (*tx_sg)(struct ath10k *ar, u8 pipe_id,
struct ath10k_hif_sg_item *items, int n_items);
/* read firmware memory through the diagnose interface */
int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
size_t buf_len);
/*
* API to handle HIF-specific BMI message exchanges, this API is
* synchronous and only allowed to be called from a context that
@ -98,6 +102,12 @@ static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items);
}
static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
size_t buf_len)
{
return ar->hif.ops->diag_read(ar, address, buf, buf_len);
}
static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
void *request, u32 request_len,
void *response, u32 *response_len)

View File

@ -725,7 +725,7 @@ static inline u8 *htt_rx_test_get_chars(struct htt_rx_test *rx_test)
*/
struct htt_pktlog_msg {
u8 pad[3];
__le32 payload[1 /* or more */];
u8 payload[0];
} __packed;
struct htt_dbg_stats_rx_reorder_stats {

View File

@ -291,6 +291,9 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
htt->rx_ring.sw_rd_idx.msdu_payld = idx;
htt->rx_ring.fill_cnt--;
trace_ath10k_htt_rx_pop_msdu(ar, msdu->data, msdu->len +
skb_tailroom(msdu));
return msdu;
}
@ -316,6 +319,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
int msdu_len, msdu_chaining = 0;
struct sk_buff *msdu, *next;
struct htt_rx_desc *rx_desc;
u32 tsf;
lockdep_assert_held(&htt->rx_ring.lock);
@ -447,6 +451,9 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
RX_MSDU_END_INFO0_LAST_MSDU;
tsf = __le32_to_cpu(rx_desc->ppdu_end.tsf_timestamp);
trace_ath10k_htt_rx_desc(ar, tsf, &rx_desc->attention,
sizeof(*rx_desc) - sizeof(u32));
if (last_msdu) {
msdu->next = NULL;
break;
@ -1674,6 +1681,15 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
case HTT_T2H_MSG_TYPE_RX_DELBA:
ath10k_htt_rx_delba(ar, resp);
break;
case HTT_T2H_MSG_TYPE_PKTLOG: {
struct ath10k_pktlog_hdr *hdr =
(struct ath10k_pktlog_hdr *)resp->pktlog_msg.payload;
trace_ath10k_htt_pktlog(ar, resp->pktlog_msg.payload,
sizeof(*hdr) +
__le16_to_cpu(hdr->size));
break;
}
case HTT_T2H_MSG_TYPE_RX_FLUSH: {
/* Ignore this event because mac80211 takes care of Rx
* aggregation reordering.
@ -1681,8 +1697,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
default:
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt event (%d) not handled\n",
resp->hdr.msg_type);
ath10k_warn(ar, "htt event (%d) not handled\n",
resp->hdr.msg_type);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
skb->data, skb->len);
break;

View File

@ -557,12 +557,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid);
ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
flags0, flags1, msdu->len, msdu_id, frags_paddr,
(u32)skb_cb->paddr, vdev_id, tid);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
msdu->data, msdu->len);
trace_ath10k_htt_tx_msdu(ar, msdu->data, msdu->len);
sg_items[0].transfer_id = 0;
sg_items[0].transfer_context = NULL;

View File

@ -20,15 +20,16 @@
#include "targaddrs.h"
#define ATH10K_FW_DIR "ath10k"
/* QCA988X 1.0 definitions (unsupported) */
#define QCA988X_HW_1_0_CHIP_ID_REV 0x0
/* QCA988X 2.0 definitions */
#define QCA988X_HW_2_0_VERSION 0x4100016c
#define QCA988X_HW_2_0_CHIP_ID_REV 0x2
#define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0"
#define QCA988X_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA988X/hw2.0"
#define QCA988X_HW_2_0_FW_FILE "firmware.bin"
#define QCA988X_HW_2_0_FW_3_FILE "firmware-3.bin"
#define QCA988X_HW_2_0_OTP_FILE "otp.bin"
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
@ -43,6 +44,8 @@
#define REG_DUMP_COUNT_QCA988X 60
#define QCA988X_CAL_DATA_LEN 2116
struct ath10k_fw_ie {
__le32 id;
__le32 len;
@ -78,6 +81,15 @@ enum ath10k_mcast2ucast_mode {
ATH10K_MCAST2UCAST_ENABLED = 1,
};
struct ath10k_pktlog_hdr {
__le16 flags;
__le16 missed_cnt;
__le16 log_type;
__le16 size;
__le32 timestamp;
u8 payload[0];
} __packed;
/* Target specific defines for MAIN firmware */
#define TARGET_NUM_VDEVS 8
#define TARGET_NUM_PEER_AST 2
@ -279,6 +291,7 @@ enum ath10k_mcast2ucast_mode {
#define SI_RX_DATA1_OFFSET 0x00000014
#define CORE_CTRL_CPU_INTR_MASK 0x00002000
#define CORE_CTRL_PCIE_REG_31_MASK 0x00000800
#define CORE_CTRL_ADDRESS 0x0000
#define PCIE_INTR_ENABLE_ADDRESS 0x0008
#define PCIE_INTR_CAUSE_ADDRESS 0x000c

View File

@ -479,6 +479,40 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
/* Interface management */
/************************/
void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif)
{
struct ath10k *ar = arvif->ar;
lockdep_assert_held(&ar->data_lock);
if (!arvif->beacon)
return;
if (!arvif->beacon_buf)
dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr,
arvif->beacon->len, DMA_TO_DEVICE);
dev_kfree_skb_any(arvif->beacon);
arvif->beacon = NULL;
arvif->beacon_sent = false;
}
static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
{
struct ath10k *ar = arvif->ar;
lockdep_assert_held(&ar->data_lock);
ath10k_mac_vif_beacon_free(arvif);
if (arvif->beacon_buf) {
dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
arvif->beacon_buf, arvif->beacon_paddr);
arvif->beacon_buf = NULL;
}
}
static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
{
int ret;
@ -590,9 +624,9 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar)
return -ENOMEM;
}
bit = ffs(ar->free_vdev_map);
bit = __ffs64(ar->free_vdev_map);
ar->monitor_vdev_id = bit - 1;
ar->monitor_vdev_id = bit;
ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id,
WMI_VDEV_TYPE_MONITOR,
@ -603,7 +637,7 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar)
return ret;
}
ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
ar->free_vdev_map &= ~(1LL << ar->monitor_vdev_id);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
ar->monitor_vdev_id);
@ -623,7 +657,7 @@ static int ath10k_monitor_vdev_delete(struct ath10k *ar)
return ret;
}
ar->free_vdev_map |= 1 << ar->monitor_vdev_id;
ar->free_vdev_map |= 1LL << ar->monitor_vdev_id;
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
ar->monitor_vdev_id);
@ -909,15 +943,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
arvif->is_up = false;
spin_lock_bh(&arvif->ar->data_lock);
if (arvif->beacon) {
dma_unmap_single(arvif->ar->dev,
ATH10K_SKB_CB(arvif->beacon)->paddr,
arvif->beacon->len, DMA_TO_DEVICE);
dev_kfree_skb_any(arvif->beacon);
arvif->beacon = NULL;
arvif->beacon_sent = false;
}
ath10k_mac_vif_beacon_free(arvif);
spin_unlock_bh(&arvif->ar->data_lock);
return;
@ -966,14 +992,6 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
if (is_zero_ether_addr(arvif->bssid))
return;
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
arvif->bssid);
if (ret) {
ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
arvif->bssid, arvif->vdev_id, ret);
return;
}
memset(arvif->bssid, 0, ETH_ALEN);
return;
@ -1042,51 +1060,45 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
/* Station management */
/**********************/
static u32 ath10k_peer_assoc_h_listen_intval(struct ath10k *ar,
struct ieee80211_vif *vif)
{
/* Some firmware revisions have unstable STA powersave when listen
* interval is set too high (e.g. 5). The symptoms are firmware doesn't
* generate NullFunc frames properly even if buffered frames have been
* indicated in Beacon TIM. Firmware would seldom wake up to pull
* buffered frames. Often pinging the device from AP would simply fail.
*
* As a workaround set it to 1.
*/
if (vif->type == NL80211_IFTYPE_STATION)
return 1;
return ar->hw->conf.listen_interval;
}
static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
struct ath10k_vif *arvif,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
lockdep_assert_held(&ar->conf_mutex);
ether_addr_copy(arg->addr, sta->addr);
arg->vdev_id = arvif->vdev_id;
arg->peer_aid = sta->aid;
arg->peer_flags |= WMI_PEER_AUTH;
if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
/*
* Seems FW have problems with Power Save in STA
* mode when we setup this parameter to high (eg. 5).
* Often we see that FW don't send NULL (with clean P flags)
* frame even there is info about buffered frames in beacons.
* Sometimes we have to wait more than 10 seconds before FW
* will wakeup. Often sending one ping from AP to our device
* just fail (more than 50%).
*
* Seems setting this FW parameter to 1 couse FW
* will check every beacon and will wakup immediately
* after detection buffered data.
*/
arg->peer_listen_intval = 1;
else
arg->peer_listen_intval = ar->hw->conf.listen_interval;
arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
arg->peer_num_spatial_streams = 1;
/*
* The assoc capabilities are available only in managed mode.
*/
if (arvif->vdev_type == WMI_VDEV_TYPE_STA && bss_conf)
arg->peer_caps = bss_conf->assoc_capability;
arg->peer_caps = vif->bss_conf.assoc_capability;
}
static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
struct ath10k_vif *arvif,
struct ieee80211_vif *vif,
struct wmi_peer_assoc_complete_arg *arg)
{
struct ieee80211_vif *vif = arvif->vif;
struct ieee80211_bss_conf *info = &vif->bss_conf;
struct cfg80211_bss *bss;
const u8 *rsnie = NULL;
@ -1343,11 +1355,12 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
}
static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
struct ath10k_vif *arvif,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
switch (arvif->vdev_type) {
case WMI_VDEV_TYPE_AP:
if (sta->wme)
@ -1359,7 +1372,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
}
break;
case WMI_VDEV_TYPE_STA:
if (bss_conf->qos)
if (vif->bss_conf.qos)
arg->peer_flags |= WMI_PEER_QOS;
break;
default:
@ -1368,7 +1381,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
}
static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
struct ath10k_vif *arvif,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
@ -1419,22 +1432,21 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
}
static int ath10k_peer_assoc_prepare(struct ath10k *ar,
struct ath10k_vif *arvif,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{
lockdep_assert_held(&ar->conf_mutex);
memset(arg, 0, sizeof(*arg));
ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg);
ath10k_peer_assoc_h_crypto(ar, arvif, arg);
ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
ath10k_peer_assoc_h_crypto(ar, vif, arg);
ath10k_peer_assoc_h_rates(ar, sta, arg);
ath10k_peer_assoc_h_ht(ar, sta, arg);
ath10k_peer_assoc_h_vht(ar, sta, arg);
ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg);
ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg);
ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
return 0;
}
@ -1480,6 +1492,9 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
lockdep_assert_held(&ar->conf_mutex);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n",
arvif->vdev_id, arvif->bssid, arvif->aid);
rcu_read_lock();
ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
@ -1494,8 +1509,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
* before calling ath10k_setup_peer_smps() which might sleep. */
ht_cap = ap_sta->ht_cap;
ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
bss_conf, &peer_arg);
ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg);
if (ret) {
ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n",
bss_conf->bssid, arvif->vdev_id, ret);
@ -1523,6 +1537,8 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
"mac vdev %d up (associated) bssid %pM aid %d\n",
arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
WARN_ON(arvif->is_up);
arvif->aid = bss_conf->aid;
ether_addr_copy(arvif->bssid, bss_conf->bssid);
@ -1536,9 +1552,6 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
arvif->is_up = true;
}
/*
* FIXME: flush TIDs
*/
static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@ -1548,45 +1561,30 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
lockdep_assert_held(&ar->conf_mutex);
/*
* For some reason, calling VDEV-DOWN before VDEV-STOP
* makes the FW to send frames via HTT after disassociation.
* No idea why this happens, even though VDEV-DOWN is supposed
* to be analogous to link down, so just stop the VDEV.
*/
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
arvif->vdev_id);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n",
arvif->vdev_id, arvif->bssid);
/* FIXME: check return value */
ret = ath10k_vdev_stop(arvif);
/*
* If we don't call VDEV-DOWN after VDEV-STOP FW will remain active and
* report beacons from previously associated network through HTT.
* This in turn would spam mac80211 WARN_ON if we bring down all
* interfaces as it expects there is no rx when no interface is
* running.
*/
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
/* FIXME: why don't we print error if wmi call fails? */
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
if (ret)
ath10k_warn(ar, "faield to down vdev %i: %d\n",
arvif->vdev_id, ret);
arvif->def_wep_key_idx = 0;
arvif->is_started = false;
arvif->is_up = false;
}
static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
struct ieee80211_sta *sta, bool reassoc)
static int ath10k_station_assoc(struct ath10k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
bool reassoc)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct wmi_peer_assoc_complete_arg peer_arg;
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
ret = ath10k_peer_assoc_prepare(ar, vif, sta, &peer_arg);
if (ret) {
ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
@ -1601,43 +1599,51 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
return ret;
}
ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
if (ret) {
ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
}
if (!sta->wme && !reassoc) {
arvif->num_legacy_stations++;
ret = ath10k_recalc_rtscts_prot(arvif);
/* Re-assoc is run only to update supported rates for given station. It
* doesn't make much sense to reconfigure the peer completely.
*/
if (!reassoc) {
ret = ath10k_setup_peer_smps(ar, arvif, sta->addr,
&sta->ht_cap);
if (ret) {
ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
}
ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
if (ret) {
ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
sta->addr, arvif->vdev_id, ret);
return ret;
}
if (!sta->wme) {
arvif->num_legacy_stations++;
ret = ath10k_recalc_rtscts_prot(arvif);
if (ret) {
ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
}
}
ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
if (ret) {
ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
}
ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
if (ret) {
ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
if (ret) {
ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
sta->addr, arvif->vdev_id, ret);
return ret;
}
return ret;
}
static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
static int ath10k_station_disassoc(struct ath10k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
@ -1729,6 +1735,7 @@ static int ath10k_update_channel_list(struct ath10k *ar)
ch->passive = passive;
ch->freq = channel->center_freq;
ch->band_center_freq1 = channel->center_freq;
ch->min_power = 0;
ch->max_power = channel->max_power * 2;
ch->max_reg_power = channel->max_reg_power * 2;
@ -2376,16 +2383,8 @@ void ath10k_halt(struct ath10k *ar)
ath10k_hif_power_down(ar);
spin_lock_bh(&ar->data_lock);
list_for_each_entry(arvif, &ar->arvifs, list) {
if (!arvif->beacon)
continue;
dma_unmap_single(arvif->ar->dev,
ATH10K_SKB_CB(arvif->beacon)->paddr,
arvif->beacon->len, DMA_TO_DEVICE);
dev_kfree_skb_any(arvif->beacon);
arvif->beacon = NULL;
}
list_for_each_entry(arvif, &ar->arvifs, list)
ath10k_mac_vif_beacon_cleanup(arvif);
spin_unlock_bh(&ar->data_lock);
}
@ -2677,12 +2676,68 @@ static void ath10k_config_chan(struct ath10k *ar)
ath10k_monitor_recalc(ar);
}
static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower)
{
int ret;
u32 param;
lockdep_assert_held(&ar->conf_mutex);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac txpower %d\n", txpower);
param = ar->wmi.pdev_param->txpower_limit2g;
ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2);
if (ret) {
ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
txpower, ret);
return ret;
}
param = ar->wmi.pdev_param->txpower_limit5g;
ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2);
if (ret) {
ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
txpower, ret);
return ret;
}
return 0;
}
static int ath10k_mac_txpower_recalc(struct ath10k *ar)
{
struct ath10k_vif *arvif;
int ret, txpower = -1;
lockdep_assert_held(&ar->conf_mutex);
list_for_each_entry(arvif, &ar->arvifs, list) {
WARN_ON(arvif->txpower < 0);
if (txpower == -1)
txpower = arvif->txpower;
else
txpower = min(txpower, arvif->txpower);
}
if (WARN_ON(txpower == -1))
return -EINVAL;
ret = ath10k_mac_txpower_setup(ar, txpower);
if (ret) {
ath10k_warn(ar, "failed to setup tx power %d: %d\n",
txpower, ret);
return ret;
}
return 0;
}
static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath10k *ar = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
int ret = 0;
u32 param;
mutex_lock(&ar->conf_mutex);
@ -2706,25 +2761,6 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
}
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config power %d\n",
hw->conf.power_level);
param = ar->wmi.pdev_param->txpower_limit2g;
ret = ath10k_wmi_pdev_set_param(ar, param,
hw->conf.power_level * 2);
if (ret)
ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
hw->conf.power_level, ret);
param = ar->wmi.pdev_param->txpower_limit5g;
ret = ath10k_wmi_pdev_set_param(ar, param,
hw->conf.power_level * 2);
if (ret)
ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
hw->conf.power_level, ret);
}
if (changed & IEEE80211_CONF_CHANGE_PS)
ath10k_config_ps(ar);
@ -2772,9 +2808,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = -EBUSY;
goto err;
}
bit = ffs(ar->free_vdev_map);
bit = __ffs64(ar->free_vdev_map);
arvif->vdev_id = bit - 1;
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac create vdev %i map %llx\n",
bit, ar->free_vdev_map);
arvif->vdev_id = bit;
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
if (ar->p2p)
@ -2804,8 +2843,39 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
break;
}
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
/* Some firmware revisions don't wait for beacon tx completion before
* sending another SWBA event. This could lead to hardware using old
* (freed) beacon data in some cases, e.g. tx credit starvation
* combined with missed TBTT. This is very very rare.
*
* On non-IOMMU-enabled hosts this could be a possible security issue
* because hw could beacon some random data on the air. On
* IOMMU-enabled hosts DMAR faults would occur in most cases and target
* device would crash.
*
* Since there are no beacon tx completions (implicit nor explicit)
* propagated to host the only workaround for this is to allocate a
* DMA-coherent buffer for a lifetime of a vif and use it for all
* beacon tx commands. Worst case for this approach is some beacons may
* become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap.
*/
if (vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_AP) {
arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
IEEE80211_MAX_FRAME_LEN,
&arvif->beacon_paddr,
GFP_ATOMIC);
if (!arvif->beacon_buf) {
ret = -ENOMEM;
ath10k_warn(ar, "failed to allocate beacon buffer: %d\n",
ret);
goto err;
}
}
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n",
arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
arvif->beacon_buf ? "single-buf" : "per-skb");
ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
arvif->vdev_subtype, vif->addr);
@ -2815,7 +2885,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
goto err;
}
ar->free_vdev_map &= ~(1 << arvif->vdev_id);
ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
list_add(&arvif->list, &ar->arvifs);
vdev_param = ar->wmi.vdev_param->def_keyid;
@ -2899,6 +2969,13 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
goto err_peer_delete;
}
arvif->txpower = vif->bss_conf.txpower;
ret = ath10k_mac_txpower_recalc(ar);
if (ret) {
ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
goto err_peer_delete;
}
mutex_unlock(&ar->conf_mutex);
return 0;
@ -2908,10 +2985,16 @@ err_peer_delete:
err_vdev_delete:
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
ar->free_vdev_map |= 1 << arvif->vdev_id;
ar->free_vdev_map |= 1LL << arvif->vdev_id;
list_del(&arvif->list);
err:
if (arvif->beacon_buf) {
dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
arvif->beacon_buf, arvif->beacon_paddr);
arvif->beacon_buf = NULL;
}
mutex_unlock(&ar->conf_mutex);
return ret;
@ -2929,14 +3012,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
cancel_work_sync(&arvif->wep_key_work);
spin_lock_bh(&ar->data_lock);
if (arvif->beacon) {
dma_unmap_single(arvif->ar->dev,
ATH10K_SKB_CB(arvif->beacon)->paddr,
arvif->beacon->len, DMA_TO_DEVICE);
dev_kfree_skb_any(arvif->beacon);
arvif->beacon = NULL;
}
ath10k_mac_vif_beacon_cleanup(arvif);
spin_unlock_bh(&ar->data_lock);
ret = ath10k_spectral_vif_stop(arvif);
@ -2944,7 +3020,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
arvif->vdev_id, ret);
ar->free_vdev_map |= 1 << arvif->vdev_id;
ar->free_vdev_map |= 1LL << arvif->vdev_id;
list_del(&arvif->list);
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
@ -3068,54 +3144,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
arvif->u.ap.hidden_ssid = info->hidden_ssid;
}
/*
* Firmware manages AP self-peer internally so make sure to not create
* it in driver. Otherwise AP self-peer deletion may timeout later.
*/
if (changed & BSS_CHANGED_BSSID &&
vif->type != NL80211_IFTYPE_AP) {
if (!is_zero_ether_addr(info->bssid)) {
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d create peer %pM\n",
arvif->vdev_id, info->bssid);
ret = ath10k_peer_create(ar, arvif->vdev_id,
info->bssid);
if (ret)
ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
info->bssid, arvif->vdev_id, ret);
if (vif->type == NL80211_IFTYPE_STATION) {
/*
* this is never erased as we it for crypto key
* clearing; this is FW requirement
*/
ether_addr_copy(arvif->bssid, info->bssid);
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d start %pM\n",
arvif->vdev_id, info->bssid);
ret = ath10k_vdev_start(arvif);
if (ret) {
ath10k_warn(ar, "failed to start vdev %i: %d\n",
arvif->vdev_id, ret);
goto exit;
}
arvif->is_started = true;
}
/*
* Mac80211 does not keep IBSS bssid when leaving IBSS,
* so driver need to store it. It is needed when leaving
* IBSS in order to remove BSSID peer.
*/
if (vif->type == NL80211_IFTYPE_ADHOC)
memcpy(arvif->bssid, info->bssid,
ETH_ALEN);
}
}
if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
ether_addr_copy(arvif->bssid, info->bssid);
if (changed & BSS_CHANGED_BEACON_ENABLED)
ath10k_control_beaconing(arvif, info);
@ -3177,10 +3207,21 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ath10k_monitor_stop(ar);
ath10k_bss_assoc(hw, vif, info);
ath10k_monitor_recalc(ar);
} else {
ath10k_bss_disassoc(hw, vif);
}
}
exit:
if (changed & BSS_CHANGED_TXPOWER) {
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev_id %i txpower %d\n",
arvif->vdev_id, info->txpower);
arvif->txpower = info->txpower;
ret = ath10k_mac_txpower_recalc(ar);
if (ret)
ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
}
mutex_unlock(&ar->conf_mutex);
}
@ -3453,7 +3494,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
sta->addr);
err = ath10k_station_assoc(ar, arvif, sta, true);
err = ath10k_station_assoc(ar, arvif->vif, sta, true);
if (err)
ath10k_warn(ar, "failed to reassociate station: %pM\n",
sta->addr);
@ -3489,8 +3530,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
mutex_lock(&ar->conf_mutex);
if (old_state == IEEE80211_STA_NOTEXIST &&
new_state == IEEE80211_STA_NONE &&
vif->type != NL80211_IFTYPE_STATION) {
new_state == IEEE80211_STA_NONE) {
/*
* New station addition.
*/
@ -3514,6 +3554,21 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
if (ret)
ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
sta->addr, arvif->vdev_id, ret);
if (vif->type == NL80211_IFTYPE_STATION) {
WARN_ON(arvif->is_started);
ret = ath10k_vdev_start(arvif);
if (ret) {
ath10k_warn(ar, "failed to start vdev %i: %d\n",
arvif->vdev_id, ret);
WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
sta->addr));
goto exit;
}
arvif->is_started = true;
}
} else if ((old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)) {
/*
@ -3522,13 +3577,23 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d peer delete %pM (sta gone)\n",
arvif->vdev_id, sta->addr);
if (vif->type == NL80211_IFTYPE_STATION) {
WARN_ON(!arvif->is_started);
ret = ath10k_vdev_stop(arvif);
if (ret)
ath10k_warn(ar, "failed to stop vdev %i: %d\n",
arvif->vdev_id, ret);
arvif->is_started = false;
}
ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
if (ret)
ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
sta->addr, arvif->vdev_id, ret);
if (vif->type == NL80211_IFTYPE_STATION)
ath10k_bss_disassoc(hw, vif);
} else if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC &&
(vif->type == NL80211_IFTYPE_AP ||
@ -3539,7 +3604,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n",
sta->addr);
ret = ath10k_station_assoc(ar, arvif, sta, false);
ret = ath10k_station_assoc(ar, vif, sta, false);
if (ret)
ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
@ -3553,7 +3618,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
sta->addr);
ret = ath10k_station_disassoc(ar, arvif, sta);
ret = ath10k_station_disassoc(ar, vif, sta);
if (ret)
ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
@ -3929,10 +3994,14 @@ exit:
}
#endif
static void ath10k_restart_complete(struct ieee80211_hw *hw)
static void ath10k_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type)
{
struct ath10k *ar = hw->priv;
if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
return;
mutex_lock(&ar->conf_mutex);
/* If device failed to restart it will be in a different state, e.g.
@ -4450,12 +4519,15 @@ static const struct ieee80211_ops ath10k_ops = {
.tx_last_beacon = ath10k_tx_last_beacon,
.set_antenna = ath10k_set_antenna,
.get_antenna = ath10k_get_antenna,
.restart_complete = ath10k_restart_complete,
.reconfig_complete = ath10k_reconfig_complete,
.get_survey = ath10k_get_survey,
.set_bitrate_mask = ath10k_set_bitrate_mask,
.sta_rc_update = ath10k_sta_rc_update,
.get_tsf = ath10k_get_tsf,
.ampdu_action = ath10k_ampdu_action,
.get_et_sset_count = ath10k_debug_get_et_sset_count,
.get_et_stats = ath10k_debug_get_et_stats,
.get_et_strings = ath10k_debug_get_et_strings,
CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
@ -4800,15 +4872,6 @@ int ath10k_mac_register(struct ath10k *ar)
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP);
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
/* TODO: Have to deal with 2x2 chips if/when the come out. */
ar->supp_tx_chainmask = TARGET_10X_TX_CHAIN_MASK;
ar->supp_rx_chainmask = TARGET_10X_RX_CHAIN_MASK;
} else {
ar->supp_tx_chainmask = TARGET_TX_CHAIN_MASK;
ar->supp_rx_chainmask = TARGET_RX_CHAIN_MASK;
}
ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;

View File

@ -39,6 +39,7 @@ void ath10k_offchan_tx_work(struct work_struct *work);
void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
void ath10k_halt(struct ath10k *ar);
void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{

View File

@ -485,6 +485,8 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
void *data_buf = NULL;
int i;
spin_lock_bh(&ar_pci->ce_lock);
ce_diag = ar_pci->ce_diag;
/*
@ -511,7 +513,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
nbytes = min_t(unsigned int, remaining_bytes,
DIAG_TRANSFER_LIMIT);
ret = ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
if (ret != 0)
goto done;
@ -527,15 +529,15 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem,
address);
ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0,
0);
ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0,
0);
if (ret)
goto done;
i = 0;
while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf,
&completed_nbytes,
&id) != 0) {
while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf,
&completed_nbytes,
&id) != 0) {
mdelay(1);
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
ret = -EBUSY;
@ -554,9 +556,9 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
}
i = 0;
while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf,
&completed_nbytes,
&id, &flags) != 0) {
while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
&completed_nbytes,
&id, &flags) != 0) {
mdelay(1);
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
@ -591,6 +593,8 @@ done:
dma_free_coherent(ar->dev, orig_nbytes, data_buf,
ce_data_base);
spin_unlock_bh(&ar_pci->ce_lock);
return ret;
}
@ -648,6 +652,8 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
dma_addr_t ce_data_base = 0;
int i;
spin_lock_bh(&ar_pci->ce_lock);
ce_diag = ar_pci->ce_diag;
/*
@ -688,7 +694,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
/* Set up to receive directly into Target(!) address */
ret = ath10k_ce_rx_post_buf(ce_diag, NULL, address);
ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, address);
if (ret != 0)
goto done;
@ -696,15 +702,15 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
* Request CE to send caller-supplied data that
* was copied to bounce buffer to Target(!) address.
*/
ret = ath10k_ce_send(ce_diag, NULL, (u32)ce_data,
nbytes, 0, 0);
ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data,
nbytes, 0, 0);
if (ret != 0)
goto done;
i = 0;
while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf,
&completed_nbytes,
&id) != 0) {
while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf,
&completed_nbytes,
&id) != 0) {
mdelay(1);
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
@ -724,9 +730,9 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
}
i = 0;
while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf,
&completed_nbytes,
&id, &flags) != 0) {
while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
&completed_nbytes,
&id, &flags) != 0) {
mdelay(1);
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
@ -760,6 +766,8 @@ done:
ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n",
address, ret);
spin_unlock_bh(&ar_pci->ce_lock);
return ret;
}
@ -861,6 +869,12 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
}
skb_put(skb, nbytes);
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n",
ce_state->id, skb->len);
ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",
skb->data, skb->len);
cb->rx_completion(ar, skb, pipe_info->pipe_num);
}
@ -936,6 +950,12 @@ err:
return err;
}
static int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
size_t buf_len)
{
return ath10k_pci_diag_read_mem(ar, address, buf, buf_len);
}
static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@ -986,6 +1006,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
spin_lock_bh(&ar->data_lock);
ar->stats.fw_crash_counter++;
crash_data = ath10k_debug_get_new_fw_crash_data(ar);
if (crash_data)
@ -1121,15 +1143,38 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
&dl_is_polled);
}
static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
{
u32 val;
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
val &= ~CORE_CTRL_PCIE_REG_31_MASK;
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
}
static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
{
u32 val;
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
val |= CORE_CTRL_PCIE_REG_31_MASK;
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
}
static void ath10k_pci_irq_disable(struct ath10k *ar)
{
ath10k_ce_disable_interrupts(ar);
ath10k_pci_disable_and_clear_legacy_irq(ar);
ath10k_pci_irq_msi_fw_mask(ar);
}
static void ath10k_pci_irq_sync(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int i;
ath10k_ce_disable_interrupts(ar);
ath10k_pci_disable_and_clear_legacy_irq(ar);
/* FIXME: How to mask all MSI interrupts? */
for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
synchronize_irq(ar_pci->pdev->irq + i);
}
@ -1138,7 +1183,7 @@ static void ath10k_pci_irq_enable(struct ath10k *ar)
{
ath10k_ce_enable_interrupts(ar);
ath10k_pci_enable_legacy_irq(ar);
/* FIXME: How to unmask all MSI interrupts? */
ath10k_pci_irq_msi_fw_unmask(ar);
}
static int ath10k_pci_hif_start(struct ath10k *ar)
@ -1266,6 +1311,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_warm_reset(ar);
ath10k_pci_irq_disable(ar);
ath10k_pci_irq_sync(ar);
ath10k_pci_flush(ar);
}
@ -1569,23 +1615,40 @@ static int ath10k_pci_init_config(struct ath10k *ar)
return 0;
}
static int ath10k_pci_alloc_ce(struct ath10k *ar)
static int ath10k_pci_alloc_pipes(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_pci_pipe *pipe;
int i, ret;
for (i = 0; i < CE_COUNT; i++) {
ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
pipe = &ar_pci->pipe_info[i];
pipe->ce_hdl = &ar_pci->ce_states[i];
pipe->pipe_num = i;
pipe->hif_ce_state = ar;
ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i],
ath10k_pci_ce_send_done,
ath10k_pci_ce_recv_data);
if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
i, ret);
return ret;
}
/* Last CE is Diagnostic Window */
if (i == CE_COUNT - 1) {
ar_pci->ce_diag = pipe->ce_hdl;
continue;
}
pipe->buf_sz = (size_t)(host_ce_config_wlan[i].src_sz_max);
}
return 0;
}
static void ath10k_pci_free_ce(struct ath10k *ar)
static void ath10k_pci_free_pipes(struct ath10k *ar)
{
int i;
@ -1593,39 +1656,17 @@ static void ath10k_pci_free_ce(struct ath10k *ar)
ath10k_ce_free_pipe(ar, i);
}
static int ath10k_pci_ce_init(struct ath10k *ar)
static int ath10k_pci_init_pipes(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_pci_pipe *pipe_info;
const struct ce_attr *attr;
int pipe_num, ret;
int i, ret;
for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
pipe_info = &ar_pci->pipe_info[pipe_num];
pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num];
pipe_info->pipe_num = pipe_num;
pipe_info->hif_ce_state = ar;
attr = &host_ce_config_wlan[pipe_num];
ret = ath10k_ce_init_pipe(ar, pipe_num, attr,
ath10k_pci_ce_send_done,
ath10k_pci_ce_recv_data);
for (i = 0; i < CE_COUNT; i++) {
ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);
if (ret) {
ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
pipe_num, ret);
i, ret);
return ret;
}
if (pipe_num == CE_COUNT - 1) {
/*
* Reserve the ultimate CE for
* diagnostic Window support
*/
ar_pci->ce_diag = pipe_info->ce_hdl;
continue;
}
pipe_info->buf_sz = (size_t)(attr->src_sz_max);
}
return 0;
@ -1672,6 +1713,12 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n");
spin_lock_bh(&ar->data_lock);
ar->stats.fw_warm_reset_counter++;
spin_unlock_bh(&ar->data_lock);
/* debug */
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
PCIE_INTR_CAUSE_ADDRESS);
@ -1773,7 +1820,7 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
goto err;
}
ret = ath10k_pci_ce_init(ar);
ret = ath10k_pci_init_pipes(ar);
if (ret) {
ath10k_err(ar, "failed to initialize CE: %d\n", ret);
goto err;
@ -1921,6 +1968,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
.tx_sg = ath10k_pci_hif_tx_sg,
.diag_read = ath10k_pci_hif_diag_read,
.exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg,
.start = ath10k_pci_hif_start,
.stop = ath10k_pci_hif_stop,
@ -2250,14 +2298,14 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
if (ar_pci->num_msi_intrs == 0)
/* Fix potential race by repeating CORE_BASE writes */
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
PCIE_INTR_ENABLE_ADDRESS,
PCIE_INTR_FIRMWARE_MASK |
PCIE_INTR_CE_MASK_ALL);
ath10k_pci_enable_legacy_irq(ar);
mdelay(10);
} while (time_before(jiffies, timeout));
ath10k_pci_disable_and_clear_legacy_irq(ar);
ath10k_pci_irq_msi_fw_mask(ar);
if (val == 0xffffffff) {
ath10k_err(ar, "failed to read device register, device is gone\n");
return -EIO;
@ -2287,6 +2335,12 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
spin_lock_bh(&ar->data_lock);
ar->stats.fw_cold_reset_counter++;
spin_unlock_bh(&ar->data_lock);
/* Put Target, including PCIe, into RESET. */
val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);
val |= 1;
@ -2400,6 +2454,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
u32 chip_id;
ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev,
ATH10K_BUS_PCI,
&ath10k_pci_hif_ops);
if (!ar) {
dev_err(&pdev->dev, "failed to allocate core\n");
@ -2435,7 +2490,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_sleep;
}
ret = ath10k_pci_alloc_ce(ar);
ret = ath10k_pci_alloc_pipes(ar);
if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
ret);
@ -2443,25 +2498,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
}
ath10k_pci_ce_deinit(ar);
ret = ath10k_ce_disable_interrupts(ar);
if (ret) {
ath10k_err(ar, "failed to disable copy engine interrupts: %d\n",
ret);
goto err_free_ce;
}
/* Workaround: There's no known way to mask all possible interrupts via
* device CSR. The only way to make sure device doesn't assert
* interrupts is to reset it. Interrupts are then disabled on host
* after handlers are registered.
*/
ath10k_pci_warm_reset(ar);
ath10k_pci_irq_disable(ar);
ret = ath10k_pci_init_irq(ar);
if (ret) {
ath10k_err(ar, "failed to init irqs: %d\n", ret);
goto err_free_ce;
goto err_free_pipes;
}
ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
@ -2474,9 +2516,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_deinit_irq;
}
/* This shouldn't race as the device has been reset above. */
ath10k_pci_irq_disable(ar);
ret = ath10k_core_register(ar, chip_id);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret);
@ -2492,8 +2531,8 @@ err_free_irq:
err_deinit_irq:
ath10k_pci_deinit_irq(ar);
err_free_ce:
ath10k_pci_free_ce(ar);
err_free_pipes:
ath10k_pci_free_pipes(ar);
err_sleep:
ath10k_pci_sleep(ar);
@ -2527,7 +2566,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
ath10k_pci_kill_tasklet(ar);
ath10k_pci_deinit_irq(ar);
ath10k_pci_ce_deinit(ar);
ath10k_pci_free_ce(ar);
ath10k_pci_free_pipes(ar);
ath10k_pci_sleep(ar);
ath10k_pci_release(ar);
ath10k_core_destroy(ar);
@ -2565,5 +2604,7 @@ module_exit(ath10k_pci_exit);
MODULE_AUTHOR("Qualcomm Atheros");
MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_3_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);

View File

@ -56,14 +56,14 @@ static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,
}
int ath10k_spectral_process_fft(struct ath10k *ar,
struct wmi_single_phyerr_rx_event *event,
struct phyerr_fft_report *fftr,
const struct wmi_phyerr *phyerr,
const struct phyerr_fft_report *fftr,
size_t bin_len, u64 tsf)
{
struct fft_sample_ath10k *fft_sample;
u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
u32 reg0, reg1, nf_list1, nf_list2;
u32 reg0, reg1;
u8 chain_idx, *bins;
int dc_pos;
@ -82,7 +82,7 @@ int ath10k_spectral_process_fft(struct ath10k *ar,
/* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
* but the results/plots suggest that its actually 22/44/88 MHz.
*/
switch (event->hdr.chan_width_mhz) {
switch (phyerr->chan_width_mhz) {
case 20:
fft_sample->chan_width_mhz = 22;
break;
@ -101,7 +101,7 @@ int ath10k_spectral_process_fft(struct ath10k *ar,
fft_sample->chan_width_mhz = 88;
break;
default:
fft_sample->chan_width_mhz = event->hdr.chan_width_mhz;
fft_sample->chan_width_mhz = phyerr->chan_width_mhz;
}
fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
@ -110,36 +110,22 @@ int ath10k_spectral_process_fft(struct ath10k *ar,
peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
fft_sample->rssi = event->hdr.rssi_combined;
fft_sample->rssi = phyerr->rssi_combined;
total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
freq1 = __le16_to_cpu(event->hdr.freq1);
freq2 = __le16_to_cpu(event->hdr.freq2);
freq1 = __le16_to_cpu(phyerr->freq1);
freq2 = __le16_to_cpu(phyerr->freq2);
fft_sample->freq1 = __cpu_to_be16(freq1);
fft_sample->freq2 = __cpu_to_be16(freq2);
nf_list1 = __le32_to_cpu(event->hdr.nf_list_1);
nf_list2 = __le32_to_cpu(event->hdr.nf_list_2);
chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
switch (chain_idx) {
case 0:
fft_sample->noise = __cpu_to_be16(nf_list1 & 0xffffu);
break;
case 1:
fft_sample->noise = __cpu_to_be16((nf_list1 >> 16) & 0xffffu);
break;
case 2:
fft_sample->noise = __cpu_to_be16(nf_list2 & 0xffffu);
break;
case 3:
fft_sample->noise = __cpu_to_be16((nf_list2 >> 16) & 0xffffu);
break;
}
fft_sample->noise = __cpu_to_be16(
__le16_to_cpu(phyerr->nf_chains[chain_idx]));
bins = (u8 *)fftr;
bins += sizeof(*fftr);

View File

@ -47,8 +47,8 @@ enum ath10k_spectral_mode {
#ifdef CONFIG_ATH10K_DEBUGFS
int ath10k_spectral_process_fft(struct ath10k *ar,
struct wmi_single_phyerr_rx_event *event,
struct phyerr_fft_report *fftr,
const struct wmi_phyerr *phyerr,
const struct phyerr_fft_report *fftr,
size_t bin_len, u64 tsf);
int ath10k_spectral_start(struct ath10k *ar);
int ath10k_spectral_vif_stop(struct ath10k_vif *arvif);
@ -59,8 +59,8 @@ void ath10k_spectral_destroy(struct ath10k *ar);
static inline int
ath10k_spectral_process_fft(struct ath10k *ar,
struct wmi_single_phyerr_rx_event *event,
struct phyerr_fft_report *fftr,
const struct wmi_phyerr *phyerr,
const struct phyerr_fft_report *fftr,
size_t bin_len, u64 tsf)
{
return 0;

View File

@ -254,6 +254,169 @@ TRACE_EVENT(ath10k_wmi_dbglog,
)
);
TRACE_EVENT(ath10k_htt_pktlog,
TP_PROTO(struct ath10k *ar, void *buf, u16 buf_len),
TP_ARGS(ar, buf, buf_len),
TP_STRUCT__entry(
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(u16, buf_len)
__dynamic_array(u8, pktlog, buf_len)
),
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
__entry->buf_len = buf_len;
memcpy(__get_dynamic_array(pktlog), buf, buf_len);
),
TP_printk(
"%s %s size %hu",
__get_str(driver),
__get_str(device),
__entry->buf_len
)
);
TRACE_EVENT(ath10k_htt_rx_desc,
TP_PROTO(struct ath10k *ar, u32 tsf, void *rxdesc, u16 len),
TP_ARGS(ar, tsf, rxdesc, len),
TP_STRUCT__entry(
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(u32, tsf)
__field(u16, len)
__dynamic_array(u8, rxdesc, len)
),
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
__entry->tsf = tsf;
__entry->len = len;
memcpy(__get_dynamic_array(rxdesc), rxdesc, len);
),
TP_printk(
"%s %s %u len %hu",
__get_str(driver),
__get_str(device),
__entry->tsf,
__entry->len
)
);
TRACE_EVENT(ath10k_htt_tx,
TP_PROTO(struct ath10k *ar, u16 msdu_id, u16 msdu_len,
u8 vdev_id, u8 tid),
TP_ARGS(ar, msdu_id, msdu_len, vdev_id, tid),
TP_STRUCT__entry(
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(u16, msdu_id)
__field(u16, msdu_len)
__field(u8, vdev_id)
__field(u8, tid)
),
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
__entry->msdu_id = msdu_id;
__entry->msdu_len = msdu_len;
__entry->vdev_id = vdev_id;
__entry->tid = tid;
),
TP_printk(
"%s %s msdu_id %d msdu_len %d vdev_id %d tid %d",
__get_str(driver),
__get_str(device),
__entry->msdu_id,
__entry->msdu_len,
__entry->vdev_id,
__entry->tid
)
);
TRACE_EVENT(ath10k_txrx_tx_unref,
TP_PROTO(struct ath10k *ar, u16 msdu_id),
TP_ARGS(ar, msdu_id),
TP_STRUCT__entry(
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(u16, msdu_id)
),
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
__entry->msdu_id = msdu_id;
),
TP_printk(
"%s %s msdu_id %d",
__get_str(driver),
__get_str(device),
__entry->msdu_id
)
);
DECLARE_EVENT_CLASS(ath10k_data_event,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_ARGS(ar, data, len),
TP_STRUCT__entry(
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(size_t, len)
__dynamic_array(u8, data, len)
),
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
__entry->len = len;
memcpy(__get_dynamic_array(data), data, len);
),
TP_printk(
"%s %s len %zu\n",
__get_str(driver),
__get_str(device),
__entry->len
)
);
DEFINE_EVENT(ath10k_data_event, ath10k_htt_tx_msdu,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_ARGS(ar, data, len)
);
DEFINE_EVENT(ath10k_data_event, ath10k_htt_rx_pop_msdu,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_ARGS(ar, data, len)
);
DEFINE_EVENT(ath10k_data_event, ath10k_wmi_mgmt_tx,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_ARGS(ar, data, len)
);
DEFINE_EVENT(ath10k_data_event, ath10k_wmi_bcn_tx,
TP_PROTO(struct ath10k *ar, void *data, size_t len),
TP_ARGS(ar, data, len)
);
#endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
/* we don't want to use include/trace/events */

View File

@ -78,6 +78,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
info = IEEE80211_SKB_CB(msdu);
memset(&info->status, 0, sizeof(info->status));
trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
if (tx_done->discard) {
ieee80211_free_txskb(htt->ar->hw, msdu);

File diff suppressed because it is too large Load Diff

View File

@ -1428,11 +1428,11 @@ struct wmi_service_ready_event {
* where FW can access this memory directly (or) by DMA.
*/
__le32 num_mem_reqs;
struct wlan_host_mem_req mem_reqs[1];
struct wlan_host_mem_req mem_reqs[0];
} __packed;
/* This is the definition from 10.X firmware branch */
struct wmi_service_ready_event_10x {
struct wmi_10x_service_ready_event {
__le32 sw_version;
__le32 abi_version;
@ -1467,7 +1467,7 @@ struct wmi_service_ready_event_10x {
*/
__le32 num_mem_reqs;
struct wlan_host_mem_req mem_reqs[1];
struct wlan_host_mem_req mem_reqs[0];
} __packed;
#define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ)
@ -1883,38 +1883,26 @@ struct host_memory_chunk {
__le32 size;
} __packed;
struct wmi_host_mem_chunks {
__le32 count;
/* some fw revisions require at least 1 chunk regardless of count */
struct host_memory_chunk items[1];
} __packed;
struct wmi_init_cmd {
struct wmi_resource_config resource_config;
__le32 num_host_mem_chunks;
/*
* variable number of host memory chunks.
* This should be the last element in the structure
*/
struct host_memory_chunk host_mem_chunks[1];
struct wmi_host_mem_chunks mem_chunks;
} __packed;
/* _10x stucture is from 10.X FW API */
struct wmi_init_cmd_10x {
struct wmi_resource_config_10x resource_config;
__le32 num_host_mem_chunks;
/*
* variable number of host memory chunks.
* This should be the last element in the structure
*/
struct host_memory_chunk host_mem_chunks[1];
struct wmi_host_mem_chunks mem_chunks;
} __packed;
struct wmi_init_cmd_10_2 {
struct wmi_resource_config_10_2 resource_config;
__le32 num_host_mem_chunks;
/*
* variable number of host memory chunks.
* This should be the last element in the structure
*/
struct host_memory_chunk host_mem_chunks[1];
struct wmi_host_mem_chunks mem_chunks;
} __packed;
struct wmi_chan_list_entry {
@ -1974,7 +1962,7 @@ enum wmi_scan_priority {
WMI_SCAN_PRIORITY_COUNT /* number of priorities supported */
};
struct wmi_start_scan_cmd {
struct wmi_start_scan_common {
/* Scan ID */
__le32 scan_id;
/* Scan requestor ID */
@ -2032,95 +2020,25 @@ struct wmi_start_scan_cmd {
__le32 probe_delay;
/* Scan control flags */
__le32 scan_ctrl_flags;
} __packed;
/* Burst duration time in msecs */
__le32 burst_duration;
/*
* TLV (tag length value ) paramerters follow the scan_cmd structure.
* TLV can contain channel list, bssid list, ssid list and
* ie. the TLV tags are defined above;
struct wmi_start_scan_tlvs {
/* TLV parameters. These includes channel list, ssid list, bssid list,
* extra ies.
*/
u8 tlvs[0];
} __packed;
struct wmi_start_scan_cmd {
struct wmi_start_scan_common common;
__le32 burst_duration_ms;
struct wmi_start_scan_tlvs tlvs;
} __packed;
/* This is the definition from 10.X firmware branch */
struct wmi_start_scan_cmd_10x {
/* Scan ID */
__le32 scan_id;
/* Scan requestor ID */
__le32 scan_req_id;
/* VDEV id(interface) that is requesting scan */
__le32 vdev_id;
/* Scan Priority, input to scan scheduler */
__le32 scan_priority;
/* Scan events subscription */
__le32 notify_scan_events;
/* dwell time in msec on active channels */
__le32 dwell_time_active;
/* dwell time in msec on passive channels */
__le32 dwell_time_passive;
/*
* min time in msec on the BSS channel,only valid if atleast one
* VDEV is active
*/
__le32 min_rest_time;
/*
* max rest time in msec on the BSS channel,only valid if at least
* one VDEV is active
*/
/*
* the scanner will rest on the bss channel at least min_rest_time
* after min_rest_time the scanner will start checking for tx/rx
* activity on all VDEVs. if there is no activity the scanner will
* switch to off channel. if there is activity the scanner will let
* the radio on the bss channel until max_rest_time expires.at
* max_rest_time scanner will switch to off channel irrespective of
* activity. activity is determined by the idle_time parameter.
*/
__le32 max_rest_time;
/*
* time before sending next set of probe requests.
* The scanner keeps repeating probe requests transmission with
* period specified by repeat_probe_time.
* The number of probe requests specified depends on the ssid_list
* and bssid_list
*/
__le32 repeat_probe_time;
/* time in msec between 2 consequetive probe requests with in a set. */
__le32 probe_spacing_time;
/*
* data inactivity time in msec on bss channel that will be used by
* scanner for measuring the inactivity.
*/
__le32 idle_time;
/* maximum time in msec allowed for scan */
__le32 max_scan_time;
/*
* delay in msec before sending first probe request after switching
* to a channel
*/
__le32 probe_delay;
/* Scan control flags */
__le32 scan_ctrl_flags;
/*
* TLV (tag length value ) paramerters follow the scan_cmd structure.
* TLV can contain channel list, bssid list, ssid list and
* ie. the TLV tags are defined above;
*/
struct wmi_10x_start_scan_cmd {
struct wmi_start_scan_common common;
struct wmi_start_scan_tlvs tlvs;
} __packed;
struct wmi_ssid_arg {
@ -2306,94 +2224,25 @@ struct wmi_mgmt_rx_event_v2 {
#define PHY_ERROR_FALSE_RADAR_EXT 0x24
#define PHY_ERROR_RADAR 0x05
struct wmi_single_phyerr_rx_hdr {
/* TSF timestamp */
struct wmi_phyerr {
__le32 tsf_timestamp;
/*
* Current freq1, freq2
*
* [7:0]: freq1[lo]
* [15:8] : freq1[hi]
* [23:16]: freq2[lo]
* [31:24]: freq2[hi]
*/
__le16 freq1;
__le16 freq2;
/*
* Combined RSSI over all chains and channel width for this PHY error
*
* [7:0]: RSSI combined
* [15:8]: Channel width (MHz)
* [23:16]: PHY error code
* [24:16]: reserved (future use)
*/
u8 rssi_combined;
u8 chan_width_mhz;
u8 phy_err_code;
u8 rsvd0;
/*
* RSSI on chain 0 through 3
*
* This is formatted the same as the PPDU_START RX descriptor
* field:
*
* [7:0]: pri20
* [15:8]: sec20
* [23:16]: sec40
* [31:24]: sec80
*/
__le32 rssi_chain0;
__le32 rssi_chain1;
__le32 rssi_chain2;
__le32 rssi_chain3;
/*
* Last calibrated NF value for chain 0 through 3
*
* nf_list_1:
*
* + [15:0] - chain 0
* + [31:16] - chain 1
*
* nf_list_2:
*
* + [15:0] - chain 2
* + [31:16] - chain 3
*/
__le32 nf_list_1;
__le32 nf_list_2;
/* Length of the frame */
__le32 rssi_chains[4];
__le16 nf_chains[4];
__le32 buf_len;
u8 buf[0];
} __packed;
struct wmi_single_phyerr_rx_event {
/* Phy error event header */
struct wmi_single_phyerr_rx_hdr hdr;
/* frame buffer */
u8 bufp[0];
} __packed;
struct wmi_comb_phyerr_rx_hdr {
/* Phy error phy error count */
__le32 num_phyerr_events;
struct wmi_phyerr_event {
__le32 num_phyerrs;
__le32 tsf_l32;
__le32 tsf_u32;
} __packed;
struct wmi_comb_phyerr_rx_event {
/* Phy error phy error count */
struct wmi_comb_phyerr_rx_hdr hdr;
/*
* frame buffer - contains multiple payloads in the order:
* header - payload, header - payload...
* (The header is of type: wmi_single_phyerr_rx_hdr)
*/
u8 bufp[0];
struct wmi_phyerr phyerrs[0];
} __packed;
#define PHYERR_TLV_SIG 0xBB
@ -2908,11 +2757,6 @@ enum wmi_tp_scale {
WMI_TP_SCALE_SIZE = 5, /* max num of enum */
};
struct wmi_set_channel_cmd {
/* channel (only frequency and mode info are used) */
struct wmi_channel chan;
} __packed;
struct wmi_pdev_chanlist_update_event {
/* number of channels */
__le32 num_chan;
@ -2943,6 +2787,10 @@ struct wmi_pdev_set_channel_cmd {
struct wmi_channel chan;
} __packed;
struct wmi_pdev_pktlog_enable_cmd {
__le32 ev_bitmap;
} __packed;
/* Customize the DSCP (bit) to TID (0-7) mapping for QOS */
#define WMI_DSCP_MAP_MAX (64)
struct wmi_pdev_set_dscp_tid_map_cmd {
@ -3177,7 +3025,7 @@ struct wmi_stats_event {
* PDEV statistics
* TODO: add all PDEV stats here
*/
struct wmi_pdev_stats_old {
struct wmi_pdev_stats {
__le32 chan_nf; /* Channel noise floor */
__le32 tx_frame_count; /* TX frame count */
__le32 rx_frame_count; /* RX frame count */
@ -3188,15 +3036,8 @@ struct wmi_pdev_stats_old {
struct wal_dbg_stats wal; /* WAL dbg stats */
} __packed;
struct wmi_pdev_stats_10x {
__le32 chan_nf; /* Channel noise floor */
__le32 tx_frame_count; /* TX frame count */
__le32 rx_frame_count; /* RX frame count */
__le32 rx_clear_count; /* rx clear count */
__le32 cycle_count; /* cycle count */
__le32 phy_err_count; /* Phy error count */
__le32 chan_tx_pwr; /* channel tx power */
struct wal_dbg_stats wal; /* WAL dbg stats */
struct wmi_10x_pdev_stats {
struct wmi_pdev_stats old;
__le32 ack_rx_bad;
__le32 rts_bad;
__le32 rts_good;
@ -3217,16 +3058,14 @@ struct wmi_vdev_stats {
* peer statistics.
* TODO: add more stats
*/
struct wmi_peer_stats_old {
struct wmi_peer_stats {
struct wmi_mac_addr peer_macaddr;
__le32 peer_rssi;
__le32 peer_tx_rate;
} __packed;
struct wmi_peer_stats_10x {
struct wmi_mac_addr peer_macaddr;
__le32 peer_rssi;
__le32 peer_tx_rate;
struct wmi_10x_peer_stats {
struct wmi_peer_stats old;
__le32 peer_rx_rate;
} __packed;
@ -4719,8 +4558,26 @@ struct wmi_dbglog_cfg_cmd {
/* By default disable power save for IBSS */
#define ATH10K_DEFAULT_ATIM 0
#define WMI_MAX_MEM_REQS 16
struct wmi_svc_rdy_ev_arg {
__le32 min_tx_power;
__le32 max_tx_power;
__le32 ht_cap;
__le32 vht_cap;
__le32 sw_ver0;
__le32 sw_ver1;
__le32 phy_capab;
__le32 num_rf_chains;
__le32 eeprom_rd;
__le32 num_mem_reqs;
const __le32 *service_map;
const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
};
struct ath10k;
struct ath10k_vif;
struct ath10k_fw_stats;
int ath10k_wmi_attach(struct ath10k *ar);
void ath10k_wmi_detach(struct ath10k *ar);
@ -4732,8 +4589,6 @@ int ath10k_wmi_connect(struct ath10k *ar);
struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
const struct wmi_channel_arg *);
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
@ -4794,5 +4649,9 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
enum wmi_force_fw_hang_type type, u32 delay_ms);
int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb);
int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable);
int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
struct ath10k_fw_stats *stats);
int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_list);
int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar);
#endif /* _WMI_H_ */

View File

@ -2976,11 +2976,11 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac)
struct station_del_parameters *params)
{
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
const u8 *addr = mac ? mac : bcast_addr;
const u8 *addr = params->mac ? params->mac : bcast_addr;
return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
addr, WLAN_REASON_PREV_AUTH_NOT_VALID);

View File

@ -22,7 +22,7 @@
#define ATH6KL_MAX_IE 256
__printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...);
__printf(2, 3) void ath6kl_printk(const char *level, const char *fmt, ...);
/*
* Reflects the version of binary interface exposed by ATH6KL target

View File

@ -37,76 +37,64 @@ struct ath6kl_fwlog_slot {
#define ATH6KL_FWLOG_VALID_MASK 0x1ffff
int ath6kl_printk(const char *level, const char *fmt, ...)
void ath6kl_printk(const char *level, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
int rtn;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
rtn = printk("%sath6kl: %pV", level, &vaf);
printk("%sath6kl: %pV", level, &vaf);
va_end(args);
return rtn;
}
EXPORT_SYMBOL(ath6kl_printk);
int ath6kl_info(const char *fmt, ...)
void ath6kl_info(const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
int ret;
va_start(args, fmt);
vaf.va = &args;
ret = ath6kl_printk(KERN_INFO, "%pV", &vaf);
ath6kl_printk(KERN_INFO, "%pV", &vaf);
trace_ath6kl_log_info(&vaf);
va_end(args);
return ret;
}
EXPORT_SYMBOL(ath6kl_info);
int ath6kl_err(const char *fmt, ...)
void ath6kl_err(const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
int ret;
va_start(args, fmt);
vaf.va = &args;
ret = ath6kl_printk(KERN_ERR, "%pV", &vaf);
ath6kl_printk(KERN_ERR, "%pV", &vaf);
trace_ath6kl_log_err(&vaf);
va_end(args);
return ret;
}
EXPORT_SYMBOL(ath6kl_err);
int ath6kl_warn(const char *fmt, ...)
void ath6kl_warn(const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
int ret;
va_start(args, fmt);
vaf.va = &args;
ret = ath6kl_printk(KERN_WARNING, "%pV", &vaf);
ath6kl_printk(KERN_WARNING, "%pV", &vaf);
trace_ath6kl_log_warn(&vaf);
va_end(args);
return ret;
}
EXPORT_SYMBOL(ath6kl_warn);

View File

@ -50,10 +50,10 @@ enum ATH6K_DEBUG_MASK {
};
extern unsigned int debug_mask;
__printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...);
__printf(1, 2) int ath6kl_info(const char *fmt, ...);
__printf(1, 2) int ath6kl_err(const char *fmt, ...);
__printf(1, 2) int ath6kl_warn(const char *fmt, ...);
__printf(2, 3) void ath6kl_printk(const char *level, const char *fmt, ...);
__printf(1, 2) void ath6kl_info(const char *fmt, ...);
__printf(1, 2) void ath6kl_err(const char *fmt, ...);
__printf(1, 2) void ath6kl_warn(const char *fmt, ...);
enum ath6kl_war {
ATH6KL_WAR_INVALID_RATE,
@ -81,10 +81,9 @@ int ath6kl_debug_init_fs(struct ath6kl *ar);
void ath6kl_debug_cleanup(struct ath6kl *ar);
#else
static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
const char *fmt, ...)
static inline void ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
const char *fmt, ...)
{
return 0;
}
static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,

View File

@ -148,6 +148,11 @@ config ATH9K_CHANNEL_CONTEXT
for multi-channel concurrency. Enable this if P2P PowerSave support
is required.
config ATH9K_PCOEM
bool "Atheros ath9k support for PC OEM cards" if EXPERT
depends on ATH9K
default y
config ATH9K_HTC
tristate "Atheros HTC based wireless cards support"
depends on USB && MAC80211

View File

@ -32,7 +32,6 @@ ath9k_hw-y:= \
ar5008_phy.o \
ar9002_calib.o \
ar9003_calib.o \
ar9003_rtt.o \
calib.o \
eeprom.o \
eeprom_def.o \
@ -50,6 +49,8 @@ ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o
ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
ar9003_mci.o
ath9k_hw-$(CONFIG_ATH9K_PCOEM) += ar9003_rtt.o
ath9k_hw-$(CONFIG_ATH9K_DYNACK) += dynack.o
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o

View File

@ -1190,7 +1190,7 @@ static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
static void ar5008_hw_set_radar_params(struct ath_hw *ah,
struct ath_hw_radar_conf *conf)
{
u32 radar_0 = 0, radar_1 = 0;
u32 radar_0 = 0, radar_1;
if (!conf) {
REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
@ -1204,6 +1204,9 @@ static void ar5008_hw_set_radar_params(struct ath_hw *ah,
radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI);
radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND);
radar_1 = REG_READ(ah, AR_PHY_RADAR_1);
radar_1 &= ~(AR_PHY_RADAR_1_MAXLEN | AR_PHY_RADAR_1_RELSTEP_THRESH |
AR_PHY_RADAR_1_RELPWR_THRESH);
radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI;
radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK;
radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN);
@ -1225,7 +1228,7 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah)
conf->fir_power = -33;
conf->radar_rssi = 20;
conf->pulse_height = 10;
conf->pulse_rssi = 24;
conf->pulse_rssi = 15;
conf->pulse_inband = 15;
conf->pulse_maxlen = 255;
conf->pulse_inband_step = 12;

View File

@ -657,31 +657,29 @@ static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah)
ar9280_hw_olc_temp_compensation(ah);
}
static bool ar9002_hw_calibrate(struct ath_hw *ah,
struct ath9k_channel *chan,
u8 rxchainmask,
bool longcal)
static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
u8 rxchainmask, bool longcal)
{
bool iscaldone = true;
struct ath9k_cal_list *currCal = ah->cal_list_curr;
bool nfcal, nfcal_pending = false;
bool nfcal, nfcal_pending = false, percal_pending;
int ret;
nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
if (ah->caldata)
nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
if (currCal && !nfcal &&
(currCal->calState == CAL_RUNNING ||
currCal->calState == CAL_WAITING)) {
iscaldone = ar9002_hw_per_calibration(ah, chan,
rxchainmask, currCal);
if (iscaldone) {
ah->cal_list_curr = currCal = currCal->calNext;
percal_pending = (currCal &&
(currCal->calState == CAL_RUNNING ||
currCal->calState == CAL_WAITING));
if (currCal->calState == CAL_WAITING) {
iscaldone = false;
ath9k_hw_reset_calibration(ah, currCal);
}
if (percal_pending && !nfcal) {
if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal))
return 0;
ah->cal_list_curr = currCal = currCal->calNext;
if (currCal->calState == CAL_WAITING) {
ath9k_hw_reset_calibration(ah, currCal);
return 0;
}
}
@ -698,7 +696,9 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
* NF is slow time-variant, so it is OK to use a
* historical value.
*/
ath9k_hw_loadnf(ah, ah->curchan);
ret = ath9k_hw_loadnf(ah, ah->curchan);
if (ret < 0)
return ret;
}
if (longcal) {
@ -709,7 +709,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
}
}
return iscaldone;
return !percal_pending;
}
/* Carrier leakage Calibration fix */
@ -856,6 +856,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
/* Do PA Calibration */
ar9002_hw_pa_cal(ah, true);
ath9k_hw_loadnf(ah, chan);
ath9k_hw_start_nfcal(ah, true);
if (ah->caldata)
set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);

View File

@ -121,13 +121,12 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
return iscaldone;
}
static bool ar9003_hw_calibrate(struct ath_hw *ah,
struct ath9k_channel *chan,
u8 rxchainmask,
bool longcal)
static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
u8 rxchainmask, bool longcal)
{
bool iscaldone = true;
struct ath9k_cal_list *currCal = ah->cal_list_curr;
int ret;
/*
* For given calibration:
@ -163,7 +162,9 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah,
* NF is slow time-variant, so it is OK to use a historical
* value.
*/
ath9k_hw_loadnf(ah, ah->curchan);
ret = ath9k_hw_loadnf(ah, ah->curchan);
if (ret < 0)
return ret;
/* start NF calibration, without updating BB NF register */
ath9k_hw_start_nfcal(ah, false);

View File

@ -670,9 +670,6 @@ static void ar9003_tx_gain_table_mode5(struct ath_hw *ah)
if (AR_SREV_9485_11_OR_LATER(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9485Modes_green_ob_db_tx_gain_1_1);
else if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9340Modes_ub124_tx_gain_table_1p0);
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_type5_tx_gain_table);

View File

@ -1348,7 +1348,7 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah,
struct ath_hw_radar_conf *conf)
{
unsigned int regWrites = 0;
u32 radar_0 = 0, radar_1 = 0;
u32 radar_0 = 0, radar_1;
if (!conf) {
REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
@ -1362,6 +1362,9 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah,
radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI);
radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND);
radar_1 = REG_READ(ah, AR_PHY_RADAR_1);
radar_1 &= ~(AR_PHY_RADAR_1_MAXLEN | AR_PHY_RADAR_1_RELSTEP_THRESH |
AR_PHY_RADAR_1_RELPWR_THRESH);
radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI;
radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK;
radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN);
@ -1388,7 +1391,7 @@ static void ar9003_hw_set_radar_conf(struct ath_hw *ah)
conf->fir_power = -28;
conf->radar_rssi = 0;
conf->pulse_height = 10;
conf->pulse_rssi = 24;
conf->pulse_rssi = 15;
conf->pulse_inband = 8;
conf->pulse_maxlen = 255;
conf->pulse_inband_step = 12;

View File

@ -17,6 +17,7 @@
#ifndef AR9003_RTT_H
#define AR9003_RTT_H
#ifdef CONFIG_ATH9K_PCOEM
void ar9003_hw_rtt_enable(struct ath_hw *ah);
void ar9003_hw_rtt_disable(struct ath_hw *ah);
void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask);
@ -25,5 +26,40 @@ void ar9003_hw_rtt_load_hist(struct ath_hw *ah);
void ar9003_hw_rtt_fill_hist(struct ath_hw *ah);
void ar9003_hw_rtt_clear_hist(struct ath_hw *ah);
bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan);
#else
static inline void ar9003_hw_rtt_enable(struct ath_hw *ah)
{
}
static inline void ar9003_hw_rtt_disable(struct ath_hw *ah)
{
}
static inline void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask)
{
}
static inline bool ar9003_hw_rtt_force_restore(struct ath_hw *ah)
{
return false;
}
static inline void ar9003_hw_rtt_load_hist(struct ath_hw *ah)
{
}
static inline void ar9003_hw_rtt_fill_hist(struct ath_hw *ah)
{
}
static inline void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
{
}
static inline bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
{
return false;
}
#endif
#endif

View File

@ -507,7 +507,7 @@ static const u32 ar955x_1p0_baseband_core[][2] = {
{0x00009d04, 0x40206c10},
{0x00009d08, 0x009c4060},
{0x00009d0c, 0x9883800a},
{0x00009d10, 0x01834061},
{0x00009d10, 0x01884061},
{0x00009d14, 0x00c0040b},
{0x00009d18, 0x00000000},
{0x00009e08, 0x0038230c},
@ -545,9 +545,9 @@ static const u32 ar955x_1p0_baseband_core[][2] = {
{0x0000a370, 0x00000000},
{0x0000a390, 0x00000001},
{0x0000a394, 0x00000444},
{0x0000a398, 0x1f020503},
{0x0000a39c, 0x29180c03},
{0x0000a3a0, 0x9a8b6844},
{0x0000a398, 0x001f0e0f},
{0x0000a39c, 0x0075393f},
{0x0000a3a0, 0xb79f6427},
{0x0000a3a4, 0x00000000},
{0x0000a3a8, 0xaaaaaaaa},
{0x0000a3ac, 0x3c466478},

View File

@ -24,7 +24,149 @@
#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble
#define ar9580_1p0_radio_core ar9300_2p2_radio_core
static const u32 ar9580_1p0_radio_core[][2] = {
/* Addr allmodes */
{0x00016000, 0x36db2db6},
{0x00016004, 0x6db6db40},
{0x00016008, 0x73f00000},
{0x0001600c, 0x00000000},
{0x00016040, 0x7f80fff8},
{0x0001604c, 0x76d005b5},
{0x00016050, 0x556cf031},
{0x00016054, 0x13449440},
{0x00016058, 0x0c51c92c},
{0x0001605c, 0x3db7fffc},
{0x00016060, 0xfffffffc},
{0x00016064, 0x000f0278},
{0x0001606c, 0x6db60000},
{0x00016080, 0x00000000},
{0x00016084, 0x0e48048c},
{0x00016088, 0x54214514},
{0x0001608c, 0x119f481e},
{0x00016090, 0x24926490},
{0x00016098, 0xd2888888},
{0x000160a0, 0x0a108ffe},
{0x000160a4, 0x812fc370},
{0x000160a8, 0x423c8000},
{0x000160b4, 0x92480080},
{0x000160c0, 0x00adb6d0},
{0x000160c4, 0x6db6db60},
{0x000160c8, 0x6db6db6c},
{0x000160cc, 0x01e6c000},
{0x00016100, 0x3fffbe01},
{0x00016104, 0xfff80000},
{0x00016108, 0x00080010},
{0x00016144, 0x02084080},
{0x00016148, 0x00000000},
{0x00016280, 0x058a0001},
{0x00016284, 0x3d840208},
{0x00016288, 0x05a20408},
{0x0001628c, 0x00038c07},
{0x00016290, 0x00000004},
{0x00016294, 0x458a214f},
{0x00016380, 0x00000000},
{0x00016384, 0x00000000},
{0x00016388, 0x00800700},
{0x0001638c, 0x00800700},
{0x00016390, 0x00800700},
{0x00016394, 0x00000000},
{0x00016398, 0x00000000},
{0x0001639c, 0x00000000},
{0x000163a0, 0x00000001},
{0x000163a4, 0x00000001},
{0x000163a8, 0x00000000},
{0x000163ac, 0x00000000},
{0x000163b0, 0x00000000},
{0x000163b4, 0x00000000},
{0x000163b8, 0x00000000},
{0x000163bc, 0x00000000},
{0x000163c0, 0x000000a0},
{0x000163c4, 0x000c0000},
{0x000163c8, 0x14021402},
{0x000163cc, 0x00001402},
{0x000163d0, 0x00000000},
{0x000163d4, 0x00000000},
{0x00016400, 0x36db2db6},
{0x00016404, 0x6db6db40},
{0x00016408, 0x73f00000},
{0x0001640c, 0x00000000},
{0x00016440, 0x7f80fff8},
{0x0001644c, 0x76d005b5},
{0x00016450, 0x556cf031},
{0x00016454, 0x13449440},
{0x00016458, 0x0c51c92c},
{0x0001645c, 0x3db7fffc},
{0x00016460, 0xfffffffc},
{0x00016464, 0x000f0278},
{0x0001646c, 0x6db60000},
{0x00016500, 0x3fffbe01},
{0x00016504, 0xfff80000},
{0x00016508, 0x00080010},
{0x00016544, 0x02084080},
{0x00016548, 0x00000000},
{0x00016780, 0x00000000},
{0x00016784, 0x00000000},
{0x00016788, 0x00800700},
{0x0001678c, 0x00800700},
{0x00016790, 0x00800700},
{0x00016794, 0x00000000},
{0x00016798, 0x00000000},
{0x0001679c, 0x00000000},
{0x000167a0, 0x00000001},
{0x000167a4, 0x00000001},
{0x000167a8, 0x00000000},
{0x000167ac, 0x00000000},
{0x000167b0, 0x00000000},
{0x000167b4, 0x00000000},
{0x000167b8, 0x00000000},
{0x000167bc, 0x00000000},
{0x000167c0, 0x000000a0},
{0x000167c4, 0x000c0000},
{0x000167c8, 0x14021402},
{0x000167cc, 0x00001402},
{0x000167d0, 0x00000000},
{0x000167d4, 0x00000000},
{0x00016800, 0x36db2db6},
{0x00016804, 0x6db6db40},
{0x00016808, 0x73f00000},
{0x0001680c, 0x00000000},
{0x00016840, 0x7f80fff8},
{0x0001684c, 0x76d005b5},
{0x00016850, 0x556cf031},
{0x00016854, 0x13449440},
{0x00016858, 0x0c51c92c},
{0x0001685c, 0x3db7fffc},
{0x00016860, 0xfffffffc},
{0x00016864, 0x000f0278},
{0x0001686c, 0x6db60000},
{0x00016900, 0x3fffbe01},
{0x00016904, 0xfff80000},
{0x00016908, 0x00080010},
{0x00016944, 0x02084080},
{0x00016948, 0x00000000},
{0x00016b80, 0x00000000},
{0x00016b84, 0x00000000},
{0x00016b88, 0x00800700},
{0x00016b8c, 0x00800700},
{0x00016b90, 0x00800700},
{0x00016b94, 0x00000000},
{0x00016b98, 0x00000000},
{0x00016b9c, 0x00000000},
{0x00016ba0, 0x00000001},
{0x00016ba4, 0x00000001},
{0x00016ba8, 0x00000000},
{0x00016bac, 0x00000000},
{0x00016bb0, 0x00000000},
{0x00016bb4, 0x00000000},
{0x00016bb8, 0x00000000},
{0x00016bbc, 0x00000000},
{0x00016bc0, 0x000000a0},
{0x00016bc4, 0x000c0000},
{0x00016bc8, 0x14021402},
{0x00016bcc, 0x00001402},
{0x00016bd0, 0x00000000},
{0x00016bd4, 0x00000000},
};
#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble

View File

@ -345,6 +345,7 @@ struct ath_chanctx {
u64 tsf_val;
u32 last_beacon;
int flush_timeout;
u16 txpower;
bool offchannel;
bool stopped;
@ -362,7 +363,7 @@ enum ath_chanctx_event {
ATH_CHANCTX_EVENT_BEACON_SENT,
ATH_CHANCTX_EVENT_TSF_TIMER,
ATH_CHANCTX_EVENT_BEACON_RECEIVED,
ATH_CHANCTX_EVENT_ASSOC,
ATH_CHANCTX_EVENT_AUTHORIZED,
ATH_CHANCTX_EVENT_SWITCH,
ATH_CHANCTX_EVENT_ASSIGN,
ATH_CHANCTX_EVENT_UNASSIGN,
@ -384,6 +385,7 @@ struct ath_chanctx_sched {
bool wait_switch;
bool force_noa_update;
bool extend_absence;
bool mgd_prepare_tx;
enum ath_chanctx_state state;
u8 beacon_miss;
@ -468,6 +470,7 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force);
void ath_offchannel_next(struct ath_softc *sc);
void ath_scan_complete(struct ath_softc *sc, bool abort);
void ath_roc_complete(struct ath_softc *sc, bool abort);
struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc);
#else
@ -540,7 +543,6 @@ static inline void ath_chanctx_check_active(struct ath_softc *sc,
#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan);
void ath_startrecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc);
u32 ath_calcrxfilter(struct ath_softc *sc);
@ -595,7 +597,7 @@ struct ath_vif {
u16 seq_no;
/* BSS info */
u8 bssid[ETH_ALEN];
u8 bssid[ETH_ALEN] __aligned(2);
u16 aid;
bool assoc;
@ -618,6 +620,7 @@ struct ath_vif {
u32 noa_start;
u32 noa_duration;
bool periodic_noa;
bool oneshot_noa;
};
struct ath9k_vif_iter_data {
@ -715,7 +718,8 @@ int ath_update_survey_stats(struct ath_softc *sc);
void ath_update_survey_nf(struct ath_softc *sc, int channel);
void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
void ath_ps_full_sleep(unsigned long data);
void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
bool sw_pending, bool timeout_override);
/**********/
/* BTCOEX */
@ -975,6 +979,7 @@ struct ath_softc {
struct ath_chanctx_sched sched;
struct ath_offchannel offchannel;
struct ath_chanctx *next_chan;
struct completion go_beacon;
#endif
unsigned long driver_data;
@ -1069,7 +1074,7 @@ void ath9k_tasklet(unsigned long data);
int ath_cabq_update(struct ath_softc *);
u8 ath9k_parse_mpdudensity(u8 mpdudensity);
irqreturn_t ath_isr(int irq, void *dev);
int ath_reset(struct ath_softc *sc);
int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan);
void ath_cancel_work(struct ath_softc *sc);
void ath_restart_work(struct ath_softc *sc);
int ath9k_init_device(u16 devid, struct ath_softc *sc,

View File

@ -234,7 +234,7 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update)
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
}
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
{
struct ath9k_nfcal_hist *h = NULL;
unsigned i, j;
@ -301,7 +301,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
ath_dbg(common, ANY,
"Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
REG_READ(ah, AR_PHY_AGC_CONTROL));
return;
return -ETIMEDOUT;
}
/*
@ -322,6 +322,8 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
}
}
REGWRITE_BUFFER_FLUSH(ah);
return 0;
}

View File

@ -109,7 +109,7 @@ struct ath9k_pacal_info{
bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update);
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
struct ath9k_channel *chan);

View File

@ -66,7 +66,7 @@ static int ath_set_channel(struct ath_softc *sc)
}
hchan = &sc->sc_ah->channels[pos];
r = ath_reset_internal(sc, hchan);
r = ath_reset(sc, hchan);
if (r)
return r;
@ -117,6 +117,7 @@ void ath_chanctx_init(struct ath_softc *sc)
cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
INIT_LIST_HEAD(&ctx->vifs);
ctx->txpower = ATH_TXPOWER_MAX;
ctx->flush_timeout = HZ / 5; /* 200ms */
for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
INIT_LIST_HEAD(&ctx->acq[j]);
}
@ -145,6 +146,36 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
/*************/
/* Utilities */
/*************/
struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc)
{
struct ath_chanctx *ctx;
struct ath_vif *avp;
struct ieee80211_vif *vif;
spin_lock_bh(&sc->chan_lock);
ath_for_each_chanctx(sc, ctx) {
if (!ctx->active)
continue;
list_for_each_entry(avp, &ctx->vifs, list) {
vif = avp->vif;
if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_P2P_GO) {
spin_unlock_bh(&sc->chan_lock);
return ctx;
}
}
}
spin_unlock_bh(&sc->chan_lock);
return NULL;
}
/**********************************************************/
/* Functions to handle the channel context state machine. */
/**********************************************************/
@ -171,7 +202,7 @@ static const char *chanctx_event_string(enum ath_chanctx_event ev)
case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT);
case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER);
case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED);
case_rtn_string(ATH_CHANCTX_EVENT_ASSOC);
case_rtn_string(ATH_CHANCTX_EVENT_AUTHORIZED);
case_rtn_string(ATH_CHANCTX_EVENT_SWITCH);
case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN);
case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN);
@ -198,6 +229,7 @@ static const char *chanctx_state_string(enum ath_chanctx_state state)
void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_chanctx *ictx;
struct ath_vif *avp;
bool active = false;
u8 n_active = 0;
@ -205,6 +237,28 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
if (!ctx)
return;
if (ctx == &sc->offchannel.chan) {
spin_lock_bh(&sc->chan_lock);
if (likely(sc->sched.channel_switch_time))
ctx->flush_timeout =
usecs_to_jiffies(sc->sched.channel_switch_time);
else
ctx->flush_timeout =
msecs_to_jiffies(10);
spin_unlock_bh(&sc->chan_lock);
/*
* There is no need to iterate over the
* active/assigned channel contexts if
* the current context is offchannel.
*/
return;
}
ictx = ctx;
list_for_each_entry(avp, &ctx->vifs, list) {
struct ieee80211_vif *vif = avp->vif;
@ -227,12 +281,23 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
n_active++;
}
spin_lock_bh(&sc->chan_lock);
if (n_active <= 1) {
ictx->flush_timeout = HZ / 5;
clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
spin_unlock_bh(&sc->chan_lock);
return;
}
if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
ictx->flush_timeout = usecs_to_jiffies(sc->sched.channel_switch_time);
if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) {
spin_unlock_bh(&sc->chan_lock);
return;
}
spin_unlock_bh(&sc->chan_lock);
if (ath9k_is_chanctx_enabled()) {
ath_chanctx_event(sc, NULL,
@ -301,6 +366,111 @@ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
"Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
}
static void ath_chanctx_handle_bmiss(struct ath_softc *sc,
struct ath_chanctx *ctx,
struct ath_vif *avp)
{
/*
* Clear the extend_absence flag if it had been
* set during the previous beacon transmission,
* since we need to revert to the normal NoA
* schedule.
*/
if (ctx->active && sc->sched.extend_absence) {
avp->noa_duration = 0;
sc->sched.extend_absence = false;
}
/* If at least two consecutive beacons were missed on the STA
* chanctx, stay on the STA channel for one extra beacon period,
* to resync the timer properly.
*/
if (ctx->active && sc->sched.beacon_miss >= 2) {
avp->noa_duration = 0;
sc->sched.extend_absence = true;
}
}
static void ath_chanctx_offchannel_noa(struct ath_softc *sc,
struct ath_chanctx *ctx,
struct ath_vif *avp,
u32 tsf_time)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
avp->noa_index++;
avp->offchannel_start = tsf_time;
avp->offchannel_duration = sc->sched.offchannel_duration;
ath_dbg(common, CHAN_CTX,
"offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
avp->offchannel_duration,
avp->offchannel_start,
avp->noa_index);
/*
* When multiple contexts are active, the NoA
* has to be recalculated and advertised after
* an offchannel operation.
*/
if (ctx->active && avp->noa_duration)
avp->noa_duration = 0;
}
static void ath_chanctx_set_periodic_noa(struct ath_softc *sc,
struct ath_vif *avp,
struct ath_beacon_config *cur_conf,
u32 tsf_time,
u32 beacon_int)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
avp->noa_index++;
avp->noa_start = tsf_time;
if (sc->sched.extend_absence)
avp->noa_duration = (3 * beacon_int / 2) +
sc->sched.channel_switch_time;
else
avp->noa_duration =
TU_TO_USEC(cur_conf->beacon_interval) / 2 +
sc->sched.channel_switch_time;
if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
sc->sched.extend_absence)
avp->periodic_noa = false;
else
avp->periodic_noa = true;
ath_dbg(common, CHAN_CTX,
"noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
avp->noa_duration,
avp->noa_start,
avp->noa_index,
avp->periodic_noa);
}
static void ath_chanctx_set_oneshot_noa(struct ath_softc *sc,
struct ath_vif *avp,
u32 tsf_time,
u32 duration)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
avp->noa_index++;
avp->noa_start = tsf_time;
avp->periodic_noa = false;
avp->oneshot_noa = true;
avp->noa_duration = duration + sc->sched.channel_switch_time;
ath_dbg(common, CHAN_CTX,
"oneshot noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
avp->noa_duration,
avp->noa_start,
avp->noa_index,
avp->periodic_noa);
}
void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
enum ath_chanctx_event ev)
{
@ -327,6 +497,14 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
if (avp->offchannel_duration)
avp->offchannel_duration = 0;
if (avp->oneshot_noa) {
avp->noa_duration = 0;
avp->oneshot_noa = false;
ath_dbg(common, CHAN_CTX,
"Clearing oneshot NoA\n");
}
if (avp->chanctx != sc->cur_chan) {
ath_dbg(common, CHAN_CTX,
"Contexts differ, not preparing beacon\n");
@ -356,6 +534,24 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
"Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n");
}
if (sc->sched.mgd_prepare_tx)
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
/*
* When a context becomes inactive, for example,
* disassociation of a station context, the NoA
* attribute needs to be removed from subsequent
* beacons.
*/
if (!ctx->active && avp->noa_duration &&
sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) {
avp->noa_duration = 0;
avp->periodic_noa = false;
ath_dbg(common, CHAN_CTX,
"Clearing NoA schedule\n");
}
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
break;
@ -378,45 +574,22 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
* values and increment the index.
*/
if (sc->next_chan == &sc->offchannel.chan) {
avp->noa_index++;
avp->offchannel_start = tsf_time;
avp->offchannel_duration = sc->sched.offchannel_duration;
ath_dbg(common, CHAN_CTX,
"offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
avp->offchannel_duration,
avp->offchannel_start,
avp->noa_index);
/*
* When multiple contexts are active, the NoA
* has to be recalculated and advertised after
* an offchannel operation.
*/
if (ctx->active && avp->noa_duration)
avp->noa_duration = 0;
ath_chanctx_offchannel_noa(sc, ctx, avp, tsf_time);
break;
}
/*
* Clear the extend_absence flag if it had been
* set during the previous beacon transmission,
* since we need to revert to the normal NoA
* schedule.
*/
if (ctx->active && sc->sched.extend_absence) {
avp->noa_duration = 0;
sc->sched.extend_absence = false;
}
ath_chanctx_handle_bmiss(sc, ctx, avp);
/* If at least two consecutive beacons were missed on the STA
* chanctx, stay on the STA channel for one extra beacon period,
* to resync the timer properly.
/*
* If a mgd_prepare_tx() has been called by mac80211,
* a one-shot NoA needs to be sent. This can happen
* with one or more active channel contexts - in both
* cases, a new NoA schedule has to be advertised.
*/
if (ctx->active && sc->sched.beacon_miss >= 2) {
avp->noa_duration = 0;
sc->sched.extend_absence = true;
if (sc->sched.mgd_prepare_tx) {
ath_chanctx_set_oneshot_noa(sc, avp, tsf_time,
jiffies_to_usecs(HZ / 5));
break;
}
/* Prevent wrap-around issues */
@ -429,31 +602,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
* announcement.
*/
if (ctx->active &&
(!avp->noa_duration || sc->sched.force_noa_update)) {
avp->noa_index++;
avp->noa_start = tsf_time;
if (sc->sched.extend_absence)
avp->noa_duration = (3 * beacon_int / 2) +
sc->sched.channel_switch_time;
else
avp->noa_duration =
TU_TO_USEC(cur_conf->beacon_interval) / 2 +
sc->sched.channel_switch_time;
if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
sc->sched.extend_absence)
avp->periodic_noa = false;
else
avp->periodic_noa = true;
ath_dbg(common, CHAN_CTX,
"noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
avp->noa_duration,
avp->noa_start,
avp->noa_index,
avp->periodic_noa);
}
(!avp->noa_duration || sc->sched.force_noa_update))
ath_chanctx_set_periodic_noa(sc, avp, cur_conf,
tsf_time, beacon_int);
if (ctx->active && sc->sched.force_noa_update)
sc->sched.force_noa_update = false;
@ -467,6 +618,15 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
}
sc->sched.beacon_pending = false;
if (sc->sched.mgd_prepare_tx) {
sc->sched.mgd_prepare_tx = false;
complete(&sc->go_beacon);
ath_dbg(common, CHAN_CTX,
"Beacon sent, complete go_beacon\n");
break;
}
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
break;
@ -495,10 +655,15 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->cur_chan == &sc->offchannel.chan)
break;
ath_chanctx_adjust_tbtt_delta(sc);
sc->sched.beacon_pending = false;
sc->sched.beacon_miss = 0;
if (sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE ||
!sc->cur_chan->tsf_val)
break;
ath_chanctx_adjust_tbtt_delta(sc);
/* TSF time might have been updated by the incoming beacon,
* need update the channel switch timer to reflect the change.
*/
@ -510,7 +675,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
ath_chanctx_setup_timer(sc, tsf_time);
break;
case ATH_CHANCTX_EVENT_ASSOC:
case ATH_CHANCTX_EVENT_AUTHORIZED:
if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE ||
avp->chanctx != sc->cur_chan)
break;
@ -578,22 +743,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
ieee80211_queue_work(sc->hw, &sc->chanctx_work);
break;
case ATH_CHANCTX_EVENT_ASSIGN:
/*
* When adding a new channel context, check if a scan
* is in progress and abort it since the addition of
* a new channel context is usually followed by VIF
* assignment, in which case we have to start multi-channel
* operation.
*/
if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
ath_dbg(common, CHAN_CTX,
"Aborting HW scan to add new context\n");
spin_unlock_bh(&sc->chan_lock);
del_timer_sync(&sc->offchannel.timer);
ath_scan_complete(sc, true);
spin_lock_bh(&sc->chan_lock);
}
break;
case ATH_CHANCTX_EVENT_CHANGE:
break;
@ -770,7 +919,7 @@ void ath_roc_complete(struct ath_softc *sc, bool abort)
sc->offchannel.roc_vif = NULL;
sc->offchannel.roc_chan = NULL;
if (!abort)
if (abort)
ieee80211_remain_on_channel_expired(sc->hw);
ath_offchannel_next(sc);
ath9k_ps_restore(sc);
@ -904,6 +1053,7 @@ static void ath_offchannel_timer(unsigned long data)
case ATH_OFFCHANNEL_ROC_WAIT:
ctx = ath_chanctx_get_oper_chan(sc, false);
sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
ieee80211_remain_on_channel_expired(sc->hw);
ath_chanctx_switch(sc, ctx, NULL);
break;
default:
@ -1082,10 +1232,11 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force)
ath9k_chanctx_stop_queues(sc, sc->cur_chan);
queues_stopped = true;
__ath9k_flush(sc->hw, ~0, true);
__ath9k_flush(sc->hw, ~0, true, false, false);
if (ath_chanctx_send_ps_frame(sc, true))
__ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
__ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO),
false, false, false);
send_ps = true;
spin_lock_bh(&sc->chan_lock);
@ -1177,6 +1328,8 @@ void ath9k_init_channel_context(struct ath_softc *sc)
(unsigned long)sc);
setup_timer(&sc->sched.timer, ath_chanctx_timer,
(unsigned long)sc);
init_completion(&sc->go_beacon);
}
void ath9k_deinit_channel_context(struct ath_softc *sc)

View File

@ -852,36 +852,31 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
static const char * const reset_cause[__RESET_TYPE_MAX] = {
[RESET_TYPE_BB_HANG] = "Baseband Hang",
[RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog",
[RESET_TYPE_FATAL_INT] = "Fatal HW Error",
[RESET_TYPE_TX_ERROR] = "TX HW error",
[RESET_TYPE_TX_GTT] = "Transmit timeout",
[RESET_TYPE_TX_HANG] = "TX Path Hang",
[RESET_TYPE_PLL_HANG] = "PLL RX Hang",
[RESET_TYPE_MAC_HANG] = "MAC Hang",
[RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
[RESET_TYPE_MCI] = "MCI Reset",
[RESET_TYPE_CALIBRATION] = "Calibration error",
};
char buf[512];
unsigned int len = 0;
int i;
len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "Baseband Hang",
sc->debug.stats.reset[RESET_TYPE_BB_HANG]);
len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "Baseband Watchdog",
sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]);
len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "Fatal HW Error",
sc->debug.stats.reset[RESET_TYPE_FATAL_INT]);
len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "TX HW error",
sc->debug.stats.reset[RESET_TYPE_TX_ERROR]);
len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "TX Path Hang",
sc->debug.stats.reset[RESET_TYPE_TX_HANG]);
len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "PLL RX Hang",
sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "MAC Hang",
sc->debug.stats.reset[RESET_TYPE_MAC_HANG]);
len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "Stuck Beacon",
sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]);
len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "MCI Reset",
sc->debug.stats.reset[RESET_TYPE_MCI]);
for (i = 0; i < ARRAY_SIZE(reset_cause); i++) {
if (!reset_cause[i])
continue;
len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", reset_cause[i],
sc->debug.stats.reset[i]);
}
if (len > sizeof(buf))
len = sizeof(buf);

View File

@ -49,6 +49,7 @@ enum ath_reset_type {
RESET_TYPE_MAC_HANG,
RESET_TYPE_BEACON_STUCK,
RESET_TYPE_MCI,
RESET_TYPE_CALIBRATION,
__RESET_TYPE_MAX
};

View File

@ -262,7 +262,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
{
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
struct ath_common *common = ath9k_hw_common(ah);
u16 *eepdata, temp, magic, magic2;
u16 *eepdata, temp, magic;
u32 sum = 0, el;
bool need_swap = false;
int i, addr, size;
@ -272,27 +272,16 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
return false;
}
if (!ath9k_hw_use_flash(ah)) {
ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
if (swab16(magic) == AR5416_EEPROM_MAGIC &&
!(ah->ah_flags & AH_NO_EEP_SWAP)) {
size = sizeof(struct ar5416_eeprom_def);
need_swap = true;
eepdata = (u16 *) (&ah->eeprom);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
if (magic2 == AR5416_EEPROM_MAGIC) {
size = sizeof(struct ar5416_eeprom_def);
need_swap = true;
eepdata = (u16 *) (&ah->eeprom);
for (addr = 0; addr < size / sizeof(u16); addr++) {
temp = swab16(*eepdata);
*eepdata = temp;
eepdata++;
}
} else {
ath_err(common,
"Invalid EEPROM Magic. Endianness mismatch.\n");
return -EINVAL;
}
for (addr = 0; addr < size / sizeof(u16); addr++) {
temp = swab16(*eepdata);
*eepdata = temp;
eepdata++;
}
}

View File

@ -41,10 +41,9 @@ static inline void ath9k_hw_set_desc_link(struct ath_hw *ah, void *ds,
ath9k_hw_ops(ah)->set_desc_link(ds, link);
}
static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
struct ath9k_channel *chan,
u8 rxchainmask,
bool longcal)
static inline int ath9k_hw_calibrate(struct ath_hw *ah,
struct ath9k_channel *chan,
u8 rxchainmask, bool longcal)
{
return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);
}

View File

@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/time.h>
#include <linux/bitops.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
#include "hw.h"
@ -446,8 +447,16 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
common->macaddr[2 * i] = eeval >> 8;
common->macaddr[2 * i + 1] = eeval & 0xff;
}
if (sum == 0 || sum == 0xffff * 3)
return -EADDRNOTAVAIL;
if (!is_valid_ether_addr(common->macaddr)) {
ath_err(common,
"eeprom contains invalid mac address: %pM\n",
common->macaddr);
random_ether_addr(common->macaddr);
ath_err(common,
"random mac address will be used: %pM\n",
common->macaddr);
}
return 0;
}
@ -1953,8 +1962,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_check_bt(ah);
ath9k_hw_loadnf(ah, chan);
ath9k_hw_start_nfcal(ah, true);
if (AR_SREV_9300_20_OR_LATER(ah)) {
ath9k_hw_loadnf(ah, chan);
ath9k_hw_start_nfcal(ah, true);
}
if (AR_SREV_9300_20_OR_LATER(ah))
ar9003_hw_bb_watchdog_config(ah);
@ -2342,17 +2353,25 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
ath_err(common,
"no band has been marked as supported in EEPROM\n");
return -EINVAL;
if (eeval & AR5416_OPFLAGS_11A) {
if (ah->disable_5ghz)
ath_warn(common, "disabling 5GHz band\n");
else
pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
}
if (eeval & AR5416_OPFLAGS_11A)
pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
if (eeval & AR5416_OPFLAGS_11G) {
if (ah->disable_2ghz)
ath_warn(common, "disabling 2GHz band\n");
else
pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
}
if (eeval & AR5416_OPFLAGS_11G)
pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
if ((pCap->hw_caps & (ATH9K_HW_CAP_2GHZ | ATH9K_HW_CAP_5GHZ)) == 0) {
ath_err(common, "both bands are disabled\n");
return -EINVAL;
}
if (AR_SREV_9485(ah) ||
AR_SREV_9285(ah) ||

View File

@ -244,13 +244,20 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_2GHZ = BIT(11),
ATH9K_HW_CAP_5GHZ = BIT(12),
ATH9K_HW_CAP_APM = BIT(13),
#ifdef CONFIG_ATH9K_PCOEM
ATH9K_HW_CAP_RTT = BIT(14),
ATH9K_HW_CAP_MCI = BIT(15),
ATH9K_HW_CAP_DFS = BIT(16),
ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17),
ATH9K_HW_CAP_PAPRD = BIT(18),
ATH9K_HW_CAP_FCC_BAND_SWITCH = BIT(19),
ATH9K_HW_CAP_BT_ANT_DIV = BIT(20),
ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(16),
ATH9K_HW_CAP_BT_ANT_DIV = BIT(17),
#else
ATH9K_HW_CAP_RTT = 0,
ATH9K_HW_CAP_MCI = 0,
ATH9K_HW_WOW_DEVICE_CAPABLE = 0,
ATH9K_HW_CAP_BT_ANT_DIV = 0,
#endif
ATH9K_HW_CAP_DFS = BIT(18),
ATH9K_HW_CAP_PAPRD = BIT(19),
ATH9K_HW_CAP_FCC_BAND_SWITCH = BIT(20),
};
/*
@ -681,10 +688,8 @@ struct ath_hw_ops {
bool power_off);
void (*rx_enable)(struct ath_hw *ah);
void (*set_desc_link)(void *ds, u32 link);
bool (*calibrate)(struct ath_hw *ah,
struct ath9k_channel *chan,
u8 rxchainmask,
bool longcal);
int (*calibrate)(struct ath_hw *ah, struct ath9k_channel *chan,
u8 rxchainmask, bool longcal);
bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked,
u32 *sync_cause_p);
void (*set_txdesc)(struct ath_hw *ah, void *ds,
@ -726,6 +731,7 @@ enum ath_cal_list {
#define AH_USE_EEPROM 0x1
#define AH_UNPLUGGED 0x2 /* The card has been physically removed. */
#define AH_FASTCC 0x4
#define AH_NO_EEP_SWAP 0x8 /* Do not swap EEPROM data */
struct ath_hw {
struct ath_ops reg_ops;
@ -924,6 +930,8 @@ struct ath_hw {
bool is_clk_25mhz;
int (*get_mac_revision)(void);
int (*external_reset)(void);
bool disable_2ghz;
bool disable_5ghz;
const struct firmware *eeprom_blob;

View File

@ -362,6 +362,9 @@ static void ath9k_init_pcoem_platform(struct ath_softc *sc)
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah);
if (!IS_ENABLED(CONFIG_ATH9K_PCOEM))
return;
if (common->bus_ops->ath_bus_type != ATH_PCI)
return;
@ -528,6 +531,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ah->is_clk_25mhz = pdata->is_clk_25mhz;
ah->get_mac_revision = pdata->get_mac_revision;
ah->external_reset = pdata->external_reset;
ah->disable_2ghz = pdata->disable_2ghz;
ah->disable_5ghz = pdata->disable_5ghz;
if (!pdata->endian_check)
ah->ah_flags |= AH_NO_EEP_SWAP;
}
common->ops = &ah->reg_ops;

View File

@ -371,9 +371,15 @@ void ath_ani_calibrate(unsigned long data)
/* Perform calibration if necessary */
if (longcal || shortcal) {
common->ani.caldone =
ath9k_hw_calibrate(ah, ah->curchan,
ah->rxchainmask, longcal);
int ret = ath9k_hw_calibrate(ah, ah->curchan, ah->rxchainmask,
longcal);
if (ret < 0) {
common->ani.caldone = 0;
ath9k_queue_reset(sc, RESET_TYPE_CALIBRATION);
return;
}
common->ani.caldone = ret;
}
ath_dbg(common, ANI,

View File

@ -54,7 +54,8 @@ u8 ath9k_parse_mpdudensity(u8 mpdudensity)
}
}
static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq)
static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq,
bool sw_pending)
{
bool pending = false;
@ -65,6 +66,9 @@ static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq)
goto out;
}
if (!sw_pending)
goto out;
if (txq->mac80211_qnum >= 0) {
struct list_head *list;
@ -270,7 +274,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
return true;
}
int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
@ -281,6 +285,7 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
__ath_cancel_work(sc);
tasklet_disable(&sc->intr_tq);
tasklet_disable(&sc->bcon_tasklet);
spin_lock_bh(&sc->sc_pcu_lock);
if (!sc->cur_chan->offchannel) {
@ -326,6 +331,7 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
out:
spin_unlock_bh(&sc->sc_pcu_lock);
tasklet_enable(&sc->bcon_tasklet);
tasklet_enable(&sc->intr_tq);
return r;
@ -539,11 +545,10 @@ irqreturn_t ath_isr(int irq, void *dev)
sched = true;
/*
* If a FATAL or RXORN interrupt is received, we have to reset the
* chip immediately.
* If a FATAL interrupt is received, we have to reset the chip
* immediately.
*/
if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) &&
!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
if (status & ATH9K_INT_FATAL)
goto chip_reset;
if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
@ -598,17 +603,29 @@ chip_reset:
#undef SCHED_INTR
}
int ath_reset(struct ath_softc *sc)
/*
* This function is called when a HW reset cannot be deferred
* and has to be immediate.
*/
int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int r;
set_bit(ATH_OP_HW_RESET, &common->op_flags);
ath9k_ps_wakeup(sc);
r = ath_reset_internal(sc, NULL);
r = ath_reset_internal(sc, hchan);
ath9k_ps_restore(sc);
return r;
}
/*
* When a HW reset can be deferred, it is added to the
* hw_reset_work workqueue, but we set ATH_OP_HW_RESET before
* queueing.
*/
void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@ -623,7 +640,9 @@ void ath_reset_work(struct work_struct *work)
{
struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
ath_reset(sc);
ath9k_ps_wakeup(sc);
ath_reset_internal(sc, NULL);
ath9k_ps_restore(sc);
}
/**********************/
@ -1037,7 +1056,7 @@ static void ath9k_set_offchannel_state(struct ath_softc *sc)
eth_zero_addr(common->curbssid);
eth_broadcast_addr(common->bssidmask);
ether_addr_copy(common->macaddr, vif->addr);
memcpy(common->macaddr, vif->addr, ETH_ALEN);
common->curaid = 0;
ah->opmode = vif->type;
ah->imask &= ~ATH9K_INT_SWBA;
@ -1078,7 +1097,7 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
ath9k_calculate_iter_data(sc, ctx, &iter_data);
if (iter_data.has_hw_macaddr)
ether_addr_copy(common->macaddr, iter_data.hw_macaddr);
memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN);
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
ath_hw_setbssidmask(common);
@ -1550,6 +1569,40 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw,
return 0;
}
static int ath9k_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state)
{
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int ret = 0;
if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC) {
ret = ath9k_sta_add(hw, vif, sta);
ath_dbg(common, CONFIG,
"Add station: %pM\n", sta->addr);
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTH) {
ret = ath9k_sta_remove(hw, vif, sta);
ath_dbg(common, CONFIG,
"Remove station: %pM\n", sta->addr);
}
if (ath9k_is_chanctx_enabled()) {
if (vif->type == NL80211_IFTYPE_STATION) {
if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTHORIZED)
ath_chanctx_event(sc, vif,
ATH_CHANCTX_EVENT_AUTHORIZED);
}
}
return ret;
}
static void ath9k_sta_set_tx_filter(struct ath_hw *ah,
struct ath_node *an,
bool set)
@ -1734,17 +1787,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
bss_conf->bssid, bss_conf->assoc);
ether_addr_copy(avp->bssid, bss_conf->bssid);
memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
avp->aid = bss_conf->aid;
avp->assoc = bss_conf->assoc;
ath9k_calculate_summary_state(sc, avp->chanctx);
if (ath9k_is_chanctx_enabled()) {
if (bss_conf->assoc)
ath_chanctx_event(sc, vif,
ATH_CHANCTX_EVENT_ASSOC);
}
}
if (changed & BSS_CHANGED_IBSS) {
@ -1840,6 +1887,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
u16 tid, u16 *ssn, u8 buf_size)
{
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
bool flush = false;
int ret = 0;
@ -1851,6 +1899,12 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_STOP:
break;
case IEEE80211_AMPDU_TX_START:
if (ath9k_is_chanctx_enabled()) {
if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
ret = -EBUSY;
break;
}
}
ath9k_ps_wakeup(sc);
ret = ath_tx_aggr_start(sc, sta, tid, ssn);
if (!ret)
@ -1964,7 +2018,8 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw,
mutex_unlock(&sc->mutex);
}
static bool ath9k_has_tx_pending(struct ath_softc *sc)
static bool ath9k_has_tx_pending(struct ath_softc *sc,
bool sw_pending)
{
int i, npend = 0;
@ -1972,7 +2027,8 @@ static bool ath9k_has_tx_pending(struct ath_softc *sc)
if (!ATH_TXQ_SETUP(sc, i))
continue;
npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i],
sw_pending);
if (npend)
break;
}
@ -1984,18 +2040,38 @@ static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
if (ath9k_is_chanctx_enabled()) {
if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
goto flush;
/*
* If MCC is active, extend the flush timeout
* and wait for the HW/SW queues to become
* empty. This needs to be done outside the
* sc->mutex lock to allow the channel scheduler
* to switch channel contexts.
*
* The vif queues have been stopped in mac80211,
* so there won't be any incoming frames.
*/
__ath9k_flush(hw, queues, drop, true, true);
return;
}
flush:
mutex_lock(&sc->mutex);
__ath9k_flush(hw, queues, drop);
__ath9k_flush(hw, queues, drop, true, false);
mutex_unlock(&sc->mutex);
}
void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
bool sw_pending, bool timeout_override)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
int timeout = HZ / 5; /* 200 ms */
int timeout;
bool drain_txq;
cancel_delayed_work_sync(&sc->tx_complete_work);
@ -2010,7 +2086,17 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
return;
}
if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc),
spin_lock_bh(&sc->chan_lock);
if (timeout_override)
timeout = HZ / 5;
else
timeout = sc->cur_chan->flush_timeout;
spin_unlock_bh(&sc->chan_lock);
ath_dbg(common, CHAN_CTX,
"Flush timeout: %d\n", jiffies_to_msecs(timeout));
if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc, sw_pending),
timeout) > 0)
drop = false;
@ -2021,7 +2107,7 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
spin_unlock_bh(&sc->sc_pcu_lock);
if (!drain_txq)
ath_reset(sc);
ath_reset(sc, NULL);
ath9k_ps_restore(sc);
}
@ -2033,7 +2119,7 @@ static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
return ath9k_has_tx_pending(sc);
return ath9k_has_tx_pending(sc, true);
}
static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
@ -2310,7 +2396,6 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw,
conf->def.chan->center_freq);
ath_chanctx_set_channel(sc, ctx, &conf->def);
ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ASSIGN);
mutex_unlock(&sc->mutex);
return 0;
@ -2419,7 +2504,11 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
struct ath_beacon_config *cur_conf;
struct ath_chanctx *go_ctx;
unsigned long timeout;
bool changed = false;
u32 beacon_int;
if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
return;
@ -2430,19 +2519,59 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
spin_lock_bh(&sc->chan_lock);
if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
sc->next_chan = avp->chanctx;
if (sc->next_chan || (sc->cur_chan != avp->chanctx))
changed = true;
spin_unlock_bh(&sc->chan_lock);
if (!changed)
goto out;
if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
ath_dbg(common, CHAN_CTX,
"%s: Aborting HW scan\n", __func__);
mutex_unlock(&sc->mutex);
del_timer_sync(&sc->offchannel.timer);
ath_scan_complete(sc, true);
flush_work(&sc->chanctx_work);
mutex_lock(&sc->mutex);
}
go_ctx = ath_is_go_chanctx_present(sc);
if (go_ctx) {
/*
* Wait till the GO interface gets a chance
* to send out an NoA.
*/
spin_lock_bh(&sc->chan_lock);
sc->sched.mgd_prepare_tx = true;
cur_conf = &go_ctx->beacon;
beacon_int = TU_TO_USEC(cur_conf->beacon_interval);
spin_unlock_bh(&sc->chan_lock);
timeout = usecs_to_jiffies(beacon_int);
init_completion(&sc->go_beacon);
if (wait_for_completion_timeout(&sc->go_beacon,
timeout) == 0)
ath_dbg(common, CHAN_CTX,
"Failed to send new NoA\n");
}
ath_dbg(common, CHAN_CTX,
"%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n",
__func__, changed);
"%s: Set chanctx state to FORCE_ACTIVE for vif: %pM\n",
__func__, vif->addr);
spin_lock_bh(&sc->chan_lock);
sc->next_chan = avp->chanctx;
sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
spin_unlock_bh(&sc->chan_lock);
if (changed)
ath_chanctx_set_next(sc, true);
ath_chanctx_set_next(sc, true);
out:
mutex_unlock(&sc->mutex);
}
@ -2474,8 +2603,7 @@ struct ieee80211_ops ath9k_ops = {
.remove_interface = ath9k_remove_interface,
.config = ath9k_config,
.configure_filter = ath9k_configure_filter,
.sta_add = ath9k_sta_add,
.sta_remove = ath9k_sta_remove,
.sta_state = ath9k_sta_state,
.sta_notify = ath9k_sta_notify,
.conf_tx = ath9k_conf_tx,
.bss_info_changed = ath9k_bss_info_changed,

View File

@ -30,6 +30,7 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
#ifdef CONFIG_ATH9K_PCOEM
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x002A,
PCI_VENDOR_ID_AZWAVE,
@ -82,6 +83,7 @@ static const struct pci_device_id ath_pci_id_table[] = {
PCI_VENDOR_ID_AZWAVE,
0x2C37),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
#endif
{ PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
@ -102,6 +104,7 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */
#ifdef CONFIG_ATH9K_PCOEM
/* PCI-E CUS198 */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
@ -294,10 +297,12 @@ static const struct pci_device_id ath_pci_id_table[] = {
PCI_VENDOR_ID_ASUSTEK,
0x850D),
.driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
#endif
{ PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */
{ PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */
#ifdef CONFIG_ATH9K_PCOEM
/* PCI-E CUS217 */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0034,
@ -657,6 +662,7 @@ static const struct pci_device_id ath_pci_id_table[] = {
/* PCI-E AR9565 (WB335) */
{ PCI_VDEVICE(ATHEROS, 0x0036),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
#endif
{ 0 }
};

View File

@ -892,10 +892,21 @@
(AR_SREV_9330((_ah)) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_12))
#ifdef CONFIG_ATH9K_PCOEM
#define AR_SREV_9462(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462))
#define AR_SREV_9485(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
#define AR_SREV_9565(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
#else
#define AR_SREV_9462(_ah) 0
#define AR_SREV_9485(_ah) 0
#define AR_SREV_9565(_ah) 0
#endif
#define AR_SREV_9485_11_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485) && \
(AR_SREV_9485(_ah) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9485_11))
#define AR_SREV_9485_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485))
@ -915,34 +926,30 @@
(AR_SREV_9285_12_OR_LATER(_ah) && \
((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
#define AR_SREV_9462(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462))
#define AR_SREV_9462_20(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
(AR_SREV_9462(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20))
#define AR_SREV_9462_21(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
(AR_SREV_9462(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_21))
#define AR_SREV_9462_20_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
(AR_SREV_9462(_ah) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20))
#define AR_SREV_9462_21_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
(AR_SREV_9462(_ah) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_21))
#define AR_SREV_9565(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
#define AR_SREV_9565_10(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
(AR_SREV_9565(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_10))
#define AR_SREV_9565_101(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
(AR_SREV_9565(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_101))
#define AR_SREV_9565_11(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
(AR_SREV_9565(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_11))
#define AR_SREV_9565_11_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
(AR_SREV_9565(_ah) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9565_11))
#define AR_SREV_9550(_ah) \

View File

@ -99,7 +99,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
static void ath9k_tx99_deinit(struct ath_softc *sc)
{
ath_reset(sc);
ath_reset(sc, NULL);
ath9k_ps_wakeup(sc);
ath9k_tx99_stop(sc);
@ -127,7 +127,7 @@ static int ath9k_tx99_init(struct ath_softc *sc)
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
ath_reset(sc);
ath_reset(sc, NULL);
ath9k_ps_wakeup(sc);

View File

@ -994,7 +994,7 @@ static int carl9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz,
refsel0 = 0;
refsel1 = 1;
}
chansel = byte_rev_table[chansel];
chansel = bitrev8(chansel);
} else {
if (freq == 2484) {
chansel = 10 + (freq - 2274) / 5;
@ -1002,7 +1002,7 @@ static int carl9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz,
} else
chansel = 16 + (freq - 2272) / 5;
chansel *= 4;
chansel = byte_rev_table[chansel];
chansel = bitrev8(chansel);
}
d1 = chansel;

View File

@ -792,12 +792,13 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
}
static int wil_cfg80211_del_station(struct wiphy *wiphy,
struct net_device *dev, const u8 *mac)
struct net_device *dev,
struct station_del_parameters *params)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, mac);
wil6210_disconnect(wil, params->mac, false);
mutex_unlock(&wil->mutex);
return 0;

View File

@ -38,6 +38,35 @@ static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT;
module_param(itr_trsh, uint, S_IRUGO);
MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs.");
/* 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 - ETH_HLEN;
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 > IEEE80211_MAX_DATA_LEN_DMG)
ret = -EINVAL;
return ret;
}
static 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.");
#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 */
@ -74,7 +103,8 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
__raw_writel(*s++, d++);
}
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
bool from_event)
{
uint i;
struct net_device *ndev = wil_to_ndev(wil);
@ -86,7 +116,10 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
sta->data_port_open = false;
if (sta->status != wil_sta_unused) {
wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
if (!from_event)
wmi_disconnect_sta(wil, sta->addr,
WLAN_REASON_DEAUTH_LEAVING);
switch (wdev->iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
@ -118,7 +151,8 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
memset(&sta->stats, 0, sizeof(sta->stats));
}
static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
bool from_event)
{
int cid = -ENOENT;
struct net_device *ndev = wil_to_ndev(wil);
@ -133,10 +167,10 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
}
if (cid >= 0) /* disconnect 1 peer */
wil_disconnect_cid(wil, cid);
wil_disconnect_cid(wil, cid, from_event);
else /* disconnect all */
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
wil_disconnect_cid(wil, cid);
wil_disconnect_cid(wil, cid, from_event);
/* link state */
switch (wdev->iftype) {
@ -166,7 +200,7 @@ static void wil_disconnect_worker(struct work_struct *work)
struct wil6210_priv, disconnect_worker);
mutex_lock(&wil->mutex);
_wil6210_disconnect(wil, NULL);
_wil6210_disconnect(wil, NULL, false);
mutex_unlock(&wil->mutex);
}
@ -223,6 +257,11 @@ static void wil_fw_error_worker(struct work_struct *work)
wil_dbg_misc(wil, "fw error worker\n");
if (!netif_running(wil_to_ndev(wil))) {
wil_info(wil, "No recovery - interface is down\n");
return;
}
/* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
* passed since last recovery attempt
*/
@ -257,9 +296,12 @@ static void wil_fw_error_worker(struct work_struct *work)
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
wil_info(wil, "No recovery for AP-like interface\n");
/* recovery in these modes is done by upper layers */
break;
default:
wil_err(wil, "No recovery - unknown interface type %d\n",
wdev->iftype);
break;
}
mutex_unlock(&wil->mutex);
@ -346,12 +388,22 @@ int wil_priv_init(struct wil6210_priv *wil)
return 0;
}
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
/**
* wil6210_disconnect - disconnect one connection
* @wil: driver context
* @bssid: peer to disconnect, NULL to disconnect all
* @from_event: whether is invoked from FW event handler
*
* Disconnect and release associated resources. If invoked not from the
* FW event handler, issue WMI command(s) to trigger MAC disconnect.
*/
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
bool from_event)
{
wil_dbg_misc(wil, "%s()\n", __func__);
del_timer_sync(&wil->connect_timer);
_wil6210_disconnect(wil, bssid);
_wil6210_disconnect(wil, bssid, from_event);
}
void wil_priv_deinit(struct wil6210_priv *wil)
@ -363,7 +415,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
cancel_work_sync(&wil->disconnect_worker);
cancel_work_sync(&wil->fw_error_worker);
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, NULL);
wil6210_disconnect(wil, NULL, false);
mutex_unlock(&wil->mutex);
wmi_event_flush(wil);
destroy_workqueue(wil->wmi_wq_conn);
@ -395,7 +447,7 @@ static inline void wil_release_cpu(struct wil6210_priv *wil)
static int wil_target_reset(struct wil6210_priv *wil)
{
int delay = 0;
u32 hw_state;
u32 x;
u32 rev_id;
bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
@ -410,9 +462,22 @@ static int wil_target_reset(struct wil6210_priv *wil)
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
wil_halt_cpu(wil);
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */
if (is_sparrow) {
S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);
/* XTAL stabilization should take about 3ms */
usleep_range(5000, 7000);
x = R(RGF_CAF_PLL_LOCK_STATUS);
if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) {
wil_err(wil, "Xtal stabilization timeout\n"
"RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x);
return -ETIME;
}
/* switch 10k to XTAL*/
C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF);
/* 40 MHz */
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL);
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
}
@ -453,13 +518,13 @@ static int wil_target_reset(struct wil6210_priv *wil)
/* wait until device ready. typical time is 200..250 msec */
do {
msleep(RST_DELAY);
hw_state = R(RGF_USER_HW_MACHINE_STATE);
x = R(RGF_USER_HW_MACHINE_STATE);
if (delay++ > RST_COUNT) {
wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
hw_state);
x);
return -ETIME;
}
} while (hw_state != HW_MACHINE_BOOT_DONE);
} while (x != HW_MACHINE_BOOT_DONE);
/* TODO: Erez check rev_id != 1 */
if (!is_sparrow && (rev_id != 1))
@ -535,7 +600,7 @@ int wil_reset(struct wil6210_priv *wil)
WARN_ON(test_bit(wil_status_napi_en, &wil->status));
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL);
wil6210_disconnect(wil, NULL, false);
wil->status = 0; /* prevent NAPI from being scheduled */

View File

@ -41,7 +41,7 @@ static int wil_change_mtu(struct net_device *ndev, int new_mtu)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
if (new_mtu < 68 || new_mtu > (TX_BUF_LEN - ETH_HLEN)) {
if (new_mtu < 68 || new_mtu > mtu_max) {
wil_err(wil, "invalid MTU %d\n", new_mtu);
return -EINVAL;
}

View File

@ -206,7 +206,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
u32 i, int headroom)
{
struct device *dev = wil_to_dev(wil);
unsigned int sz = RX_BUF_LEN;
unsigned int sz = mtu_max + ETH_HLEN;
struct vring_rx_desc dd, *d = &dd;
volatile struct vring_rx_desc *_d = &vring->va[i].rx;
dma_addr_t pa;
@ -385,7 +385,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
struct vring_rx_desc *d;
struct sk_buff *skb;
dma_addr_t pa;
unsigned int sz = RX_BUF_LEN;
unsigned int sz = mtu_max + ETH_HLEN;
u16 dmalen;
u8 ftype;
u8 ds_bits;
@ -646,7 +646,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
.action = cpu_to_le32(WMI_VRING_CMD_ADD),
.vring_cfg = {
.tx_sw_ring = {
.max_mpdu_size = cpu_to_le16(TX_BUF_LEN),
.max_mpdu_size =
cpu_to_le16(mtu_max + ETH_HLEN),
.ring_size = cpu_to_le16(size),
},
.ringid = id,

View File

@ -21,8 +21,8 @@
#define BUF_HW_OWNED (0)
/* size of max. Tx/Rx buffers, as supported by FW */
#define RX_BUF_LEN (2242)
#define TX_BUF_LEN (2242)
#define TXRX_BUF_LEN_DEFAULT (2242)
/* how many bytes to reserve for rtap header? */
#define WIL6210_RTAP_SIZE (128)

View File

@ -24,6 +24,7 @@
#include "wil_platform.h"
extern bool no_fw_recovery;
extern unsigned int mtu_max;
#define WIL_NAME "wil6210"
#define WIL_FW_NAME "wil6210.fw"
@ -117,6 +118,8 @@ struct RGF_ICR {
#define BIT_USER_USER_ICR_SW_INT_2 BIT(18)
#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 (0x880c18)
#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c)
#define RGF_USER_SPARROW_M_4 (0x880c50) /* Sparrow */
#define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF BIT(2)
#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
#define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
@ -152,6 +155,10 @@ struct RGF_ICR {
#define RGF_MAC_MTRL_COUNTER_0 (0x886aa8)
#define RGF_CAF_ICR (0x88946c) /* struct RGF_ICR */
#define RGF_CAF_OSC_CONTROL (0x88afa4)
#define BIT_CAF_OSC_XTAL_EN BIT(0)
#define RGF_CAF_PLL_LOCK_STATUS (0x88afec)
#define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0)
/* popular locations */
#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
@ -463,8 +470,11 @@ struct wil6210_priv {
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
#define wil_to_pcie_dev(i) (&i->pdev->dev)
__printf(2, 3)
void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
__printf(2, 3)
void wil_err(struct wil6210_priv *wil, const char *fmt, ...);
__printf(2, 3)
void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg(wil, fmt, arg...) do { \
netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
@ -575,7 +585,8 @@ void wil_wdev_free(struct wil6210_priv *wil);
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
int wmi_pcp_stop(struct wil6210_priv *wil);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
bool from_event);
int wil_rx_init(struct wil6210_priv *wil);
void wil_rx_fini(struct wil6210_priv *wil);

View File

@ -486,7 +486,7 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
wil->sinfo_gen++;
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, evt->bssid);
wil6210_disconnect(wil, evt->bssid, true);
mutex_unlock(&wil->mutex);
}
@ -1025,7 +1025,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
struct wmi_cfg_rx_chain_cmd cmd = {
.action = WMI_RX_CHAIN_ADD,
.rx_sw_ring = {
.max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
.max_mpdu_size = cpu_to_le16(mtu_max + ETH_HLEN),
.ring_mem_base = cpu_to_le64(vring->pa),
.ring_size = cpu_to_le16(vring->size),
},

View File

@ -23,15 +23,15 @@ ccflags-y += -D__CHECK_ENDIAN__
obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
brcmfmac-objs += \
wl_cfg80211.o \
cfg80211.o \
chip.o \
fwil.o \
fweh.o \
fwsignal.o \
p2p.o \
proto.o \
dhd_common.o \
dhd_linux.o \
common.o \
core.o \
firmware.o \
feature.o \
btcoex.o \
@ -43,14 +43,14 @@ brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \
flowring.o \
msgbuf.o
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
dhd_sdio.o \
sdio.o \
bcmsdh.o
brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
usb.o
brcmfmac-$(CONFIG_BRCMFMAC_PCIE) += \
pcie.o
brcmfmac-$(CONFIG_BRCMDBG) += \
dhd_dbg.o
debug.o
brcmfmac-$(CONFIG_BRCM_TRACING) += \
tracepoint.o
brcmfmac-$(CONFIG_OF) += \

View File

@ -25,10 +25,10 @@
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "core.h"
#include "bus.h"
#include "fwsignal.h"
#include "dhd_dbg.h"
#include "debug.h"
#include "tracepoint.h"
#include "proto.h"
#include "bcdc.h"

View File

@ -41,9 +41,9 @@
#include <chipcommon.h>
#include <soc.h>
#include "chip.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "sdio_host.h"
#include "bus.h"
#include "debug.h"
#include "sdio.h"
#include "of.h"
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
@ -1064,6 +1064,16 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
if (!sdiodev->pdata)
brcmf_of_probe(sdiodev);
#ifdef CONFIG_PM_SLEEP
/* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
* is true or when platform data OOB irq is true).
*/
if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
(sdiodev->pdata->oob_irq_supported)))
bus_if->wowl_supported = true;
#endif
atomic_set(&sdiodev->suspend, false);
init_waitqueue_head(&sdiodev->request_word_wait);
init_waitqueue_head(&sdiodev->request_buffer_wait);
@ -1116,34 +1126,39 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
brcmf_dbg(SDIO, "Exit\n");
}
void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);
sdiodev->wowl_enabled = enabled;
}
#ifdef CONFIG_PM_SLEEP
static int brcmf_ops_sdio_suspend(struct device *dev)
{
mmc_pm_flag_t sdio_flags;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
int ret = 0;
mmc_pm_flag_t sdio_flags;
brcmf_dbg(SDIO, "Enter\n");
sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
brcmf_err("Host can't keep power while suspended\n");
return -EINVAL;
}
atomic_set(&sdiodev->suspend, true);
ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
if (ret) {
brcmf_err("Failed to set pm_flags\n");
atomic_set(&sdiodev->suspend, false);
return ret;
if (sdiodev->wowl_enabled) {
sdio_flags = MMC_PM_KEEP_POWER;
if (sdiodev->pdata->oob_irq_supported)
enable_irq_wake(sdiodev->pdata->oob_irq_nr);
else
sdio_flags = MMC_PM_WAKE_SDIO_IRQ;
if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
}
brcmf_sdio_wd_timer(sdiodev->bus, 0);
return ret;
return 0;
}
static int brcmf_ops_sdio_resume(struct device *dev)
@ -1152,6 +1167,8 @@ static int brcmf_ops_sdio_resume(struct device *dev)
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_dbg(SDIO, "Enter\n");
if (sdiodev->pdata->oob_irq_supported)
disable_irq_wake(sdiodev->pdata->oob_irq_nr);
brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
atomic_set(&sdiodev->suspend, false);
return 0;

View File

@ -20,13 +20,13 @@
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include <defs.h>
#include <dhd.h>
#include <dhd_dbg.h>
#include "core.h"
#include "debug.h"
#include "fwil.h"
#include "fwil_types.h"
#include "btcoex.h"
#include "p2p.h"
#include "wl_cfg80211.h"
#include "cfg80211.h"
/* T1 start SCO/eSCO priority suppression */
#define BRCMF_BTCOEX_OPPR_WIN_TIME 2000

View File

@ -14,10 +14,10 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCMF_BUS_H_
#define _BRCMF_BUS_H_
#ifndef BRCMFMAC_BUS_H
#define BRCMFMAC_BUS_H
#include "dhd_dbg.h"
#include "debug.h"
/* IDs of the 6 default common rings of msgbuf protocol */
#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT 0
@ -227,8 +227,7 @@ void brcmf_txflowblock(struct device *dev, bool state);
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
int brcmf_bus_start(struct device *dev);
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data,
u32 len);
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len);
void brcmf_bus_add_txhdrlen(struct device *dev, uint len);
#ifdef CONFIG_BRCMFMAC_SDIO
@ -241,4 +240,4 @@ void brcmf_usb_exit(void);
void brcmf_usb_register(void);
#endif
#endif /* _BRCMF_BUS_H_ */
#endif /* BRCMFMAC_BUS_H */

View File

@ -26,18 +26,18 @@
#include <brcmu_utils.h>
#include <defs.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_dbg.h"
#include "core.h"
#include "debug.h"
#include "tracepoint.h"
#include "fwil_types.h"
#include "p2p.h"
#include "btcoex.h"
#include "wl_cfg80211.h"
#include "cfg80211.h"
#include "feature.h"
#include "fwil.h"
#include "proto.h"
#include "vendor.h"
#include "dhd_bus.h"
#include "bus.h"
#define BRCMF_SCAN_IE_LEN_MAX 2048
#define BRCMF_PNO_VERSION 2
@ -2779,6 +2779,44 @@ static __always_inline void brcmf_delay(u32 ms)
}
}
static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
u8 *pattern, u32 patternsize, u8 *mask,
u32 packet_offset)
{
struct brcmf_fil_wowl_pattern_le *filter;
u32 masksize;
u32 patternoffset;
u8 *buf;
u32 bufsize;
s32 ret;
masksize = (patternsize + 7) / 8;
patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
bufsize = sizeof(*filter) + patternsize + masksize;
buf = kzalloc(bufsize, GFP_KERNEL);
if (!buf)
return -ENOMEM;
filter = (struct brcmf_fil_wowl_pattern_le *)buf;
memcpy(filter->cmd, cmd, 4);
filter->masksize = cpu_to_le32(masksize);
filter->offset = cpu_to_le32(packet_offset);
filter->patternoffset = cpu_to_le32(patternoffset);
filter->patternsize = cpu_to_le32(patternsize);
filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
if ((mask) && (masksize))
memcpy(buf + sizeof(*filter), mask, masksize);
if ((pattern) && (patternsize))
memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
kfree(buf);
return ret;
}
static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
@ -2788,10 +2826,11 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
brcmf_dbg(TRACE, "Enter\n");
if (cfg->wowl_enabled) {
brcmf_configure_arp_offload(ifp, true);
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
cfg->pre_wowl_pmmode);
brcmf_fil_iovar_data_set(ifp, "wowl_pattern", "clr", 4);
brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
cfg->wowl_enabled = false;
}
return 0;
@ -2802,21 +2841,29 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
struct cfg80211_wowlan *wowl)
{
u32 wowl_config;
u32 i;
brcmf_dbg(TRACE, "Suspend, wowl config.\n");
brcmf_configure_arp_offload(ifp, false);
brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->pre_wowl_pmmode);
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
wowl_config = 0;
if (wowl->disconnect)
wowl_config |= WL_WOWL_DIS | WL_WOWL_BCN | WL_WOWL_RETR;
/* Note: if "wowl" target and not "wowlpf" then wowl_bcn_loss
* should be configured. This paramater is not supported by
* wowlpf.
*/
wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
if (wowl->magic_pkt)
wowl_config |= WL_WOWL_MAGIC;
wowl_config |= BRCMF_WOWL_MAGIC;
if ((wowl->patterns) && (wowl->n_patterns)) {
wowl_config |= BRCMF_WOWL_NET;
for (i = 0; i < wowl->n_patterns; i++) {
brcmf_config_wowl_pattern(ifp, "add",
(u8 *)wowl->patterns[i].pattern,
wowl->patterns[i].pattern_len,
(u8 *)wowl->patterns[i].mask,
wowl->patterns[i].pkt_offset);
}
}
brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
brcmf_bus_wowl_config(cfg->pub->bus_if, true);
@ -3998,24 +4045,24 @@ brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
static int
brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
const u8 *mac)
struct station_del_parameters *params)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_scb_val_le scbval;
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err;
if (!mac)
if (!params->mac)
return -EFAULT;
brcmf_dbg(TRACE, "Enter %pM\n", mac);
brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
if (!check_vif_up(ifp->vif))
return -EIO;
memcpy(&scbval.ea, mac, ETH_ALEN);
memcpy(&scbval.ea, params->mac, ETH_ALEN);
scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
&scbval, sizeof(scbval));
@ -5440,10 +5487,13 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
}
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support brcmf_wowlan_support = {
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
.n_patterns = BRCMF_WOWL_MAXPATTERNS,
.pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
.pattern_min_len = 1,
.max_pkt_offset = 1500,
};
#endif
@ -5607,7 +5657,8 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
return wdev->iftype;
}
bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state)
bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
unsigned long state)
{
struct brcmf_cfg80211_vif *vif;

View File

@ -14,8 +14,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _wl_cfg80211_h_
#define _wl_cfg80211_h_
#ifndef BRCMFMAC_CFG80211_H
#define BRCMFMAC_CFG80211_H
/* for brcmu_d11inf */
#include <brcmu_d11.h>
@ -480,7 +480,8 @@ const struct brcmf_tlv *
brcmf_parse_tlvs(const void *buf, int buflen, uint key);
u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
struct ieee80211_channel *ch);
bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state);
bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
unsigned long state);
void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif);
bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
@ -493,4 +494,4 @@ void brcmf_set_mpc(struct brcmf_if *ndev, int mpc);
void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
void brcmf_cfg80211_free_netdev(struct net_device *ndev);
#endif /* _wl_cfg80211_h_ */
#endif /* BRCMFMAC_CFG80211_H */

View File

@ -25,7 +25,7 @@
#include <brcm_hw_ids.h>
#include <brcmu_utils.h>
#include <chipcommon.h>
#include "dhd_dbg.h"
#include "debug.h"
#include "chip.h"
/* SOC Interconnect types (aka chip types) */

View File

@ -0,0 +1,168 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* 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/kernel.h>
#include <linux/string.h>
#include <linux/netdevice.h>
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "core.h"
#include "bus.h"
#include "debug.h"
#include "fwil.h"
#include "fwil_types.h"
#include "tracepoint.h"
#define BRCMF_DEFAULT_BCN_TIMEOUT 3
#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40
#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40
/* boost value for RSSI_DELTA in preferred join selection */
#define BRCMF_JOIN_PREF_RSSI_BOOST 8
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
{
s8 eventmask[BRCMF_EVENTING_MASK_LEN];
u8 buf[BRCMF_DCMD_SMLEN];
struct brcmf_join_pref_params join_pref_params[2];
char *ptr;
s32 err;
/* retreive mac address */
err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
sizeof(ifp->mac_addr));
if (err < 0) {
brcmf_err("Retreiving cur_etheraddr failed, %d\n",
err);
goto done;
}
memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
strcpy(buf, "ver");
err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
if (err < 0) {
brcmf_err("Retreiving version information failed, %d\n",
err);
goto done;
}
ptr = (char *)buf;
strsep(&ptr, "\n");
/* Print fw version info */
brcmf_err("Firmware version = %s\n", buf);
/* locate firmware version number for ethtool */
ptr = strrchr(buf, ' ') + 1;
strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
/* set mpc */
err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
if (err) {
brcmf_err("failed setting mpc\n");
goto done;
}
/*
* Setup timeout if Beacons are lost and roam is off to report
* link down
*/
err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout",
BRCMF_DEFAULT_BCN_TIMEOUT);
if (err) {
brcmf_err("bcn_timeout error (%d)\n", err);
goto done;
}
/* Enable/Disable build-in roaming to allowed ext supplicant to take
* of romaing
*/
err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
if (err) {
brcmf_err("roam_off error (%d)\n", err);
goto done;
}
/* Setup join_pref to select target by RSSI(with boost on 5GHz) */
join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
join_pref_params[0].len = 2;
join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
join_pref_params[0].band = WLC_BAND_5G;
join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
join_pref_params[1].len = 2;
join_pref_params[1].rssi_gain = 0;
join_pref_params[1].band = 0;
err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
sizeof(join_pref_params));
if (err)
brcmf_err("Set join_pref error (%d)\n", err);
/* Setup event_msgs, enable E_IF */
err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
BRCMF_EVENTING_MASK_LEN);
if (err) {
brcmf_err("Get event_msgs error (%d)\n", err);
goto done;
}
setbit(eventmask, BRCMF_E_IF);
err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
BRCMF_EVENTING_MASK_LEN);
if (err) {
brcmf_err("Set event_msgs error (%d)\n", err);
goto done;
}
/* Setup default scan channel time */
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
if (err) {
brcmf_err("BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
err);
goto done;
}
/* Setup default scan unassoc time */
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
if (err) {
brcmf_err("BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
err);
goto done;
}
/* do bus specific preinit here */
err = brcmf_bus_preinit(ifp->drvr->bus_if);
done:
return err;
}
#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
va_start(args, fmt);
vaf.va = &args;
if (brcmf_msg_level & level)
pr_debug("%s %pV", func, &vaf);
trace_brcmf_dbg(level, func, &vaf);
va_end(args);
}
#endif

View File

@ -19,7 +19,7 @@
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "core.h"
#include "commonring.h"

View File

@ -22,12 +22,12 @@
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "core.h"
#include "bus.h"
#include "debug.h"
#include "fwil_types.h"
#include "p2p.h"
#include "wl_cfg80211.h"
#include "cfg80211.h"
#include "fwil.h"
#include "fwsignal.h"
#include "feature.h"

View File

@ -18,8 +18,8 @@
* Common types *
*/
#ifndef _BRCMF_H_
#define _BRCMF_H_
#ifndef BRCMFMAC_CORE_H
#define BRCMFMAC_CORE_H
#include "fweh.h"
@ -83,7 +83,6 @@ struct brcmf_pub {
/* Internal brcmf items */
uint hdrlen; /* Total BRCMF header length (proto + bus) */
uint rxsz; /* Rx buffer size bus module should use */
u8 wme_dp; /* wme discard priority */
/* Dongle media info */
char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN];
@ -186,4 +185,4 @@ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
/* Sets dongle media info (drv_version, mac address). */
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
#endif /* _BRCMF_H_ */
#endif /* BRCMFMAC_CORE_H */

View File

@ -19,9 +19,9 @@
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "core.h"
#include "bus.h"
#include "debug.h"
static struct dentry *root_folder;

View File

@ -14,8 +14,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCMF_DBG_H_
#define _BRCMF_DBG_H_
#ifndef BRCMFMAC_DEBUG_H
#define BRCMFMAC_DEBUG_H
/* message levels */
#define BRCMF_TRACE_VAL 0x00000002
@ -133,4 +133,4 @@ int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
}
#endif
#endif /* _BRCMF_DBG_H_ */
#endif /* BRCMFMAC_DEBUG_H */

View File

@ -1,400 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* 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/kernel.h>
#include <linux/string.h>
#include <linux/netdevice.h>
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "fwil.h"
#include "fwil_types.h"
#include "tracepoint.h"
#define PKTFILTER_BUF_SIZE 128
#define BRCMF_DEFAULT_BCN_TIMEOUT 3
#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40
#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40
#define BRCMF_DEFAULT_PACKET_FILTER "100 0 0 0 0x01 0x00"
/* boost value for RSSI_DELTA in preferred join selection */
#define BRCMF_JOIN_PREF_RSSI_BOOST 8
bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
struct sk_buff *pkt, int prec)
{
struct sk_buff *p;
int eprec = -1; /* precedence to evict from */
bool discard_oldest;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
/* Fast case, precedence queue is not full and we are also not
* exceeding total queue length
*/
if (!pktq_pfull(q, prec) && !pktq_full(q)) {
brcmu_pktq_penq(q, prec, pkt);
return true;
}
/* Determine precedence from which to evict packet, if any */
if (pktq_pfull(q, prec))
eprec = prec;
else if (pktq_full(q)) {
p = brcmu_pktq_peek_tail(q, &eprec);
if (eprec > prec)
return false;
}
/* Evict if needed */
if (eprec >= 0) {
/* Detect queueing to unconfigured precedence */
discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec);
if (eprec == prec && !discard_oldest)
return false; /* refuse newer (incoming) packet */
/* Evict packet according to discard policy */
p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
brcmu_pktq_pdeq_tail(q, eprec);
if (p == NULL)
brcmf_err("brcmu_pktq_penq() failed, oldest %d\n",
discard_oldest);
brcmu_pkt_buf_free_skb(p);
}
/* Enqueue */
p = brcmu_pktq_penq(q, prec, pkt);
if (p == NULL)
brcmf_err("brcmu_pktq_penq() failed\n");
return p != NULL;
}
/* Convert user's input in hex pattern to byte-size mask */
static int brcmf_c_pattern_atoh(char *src, char *dst)
{
int i;
if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
brcmf_err("Mask invalid format. Needs to start with 0x\n");
return -EINVAL;
}
src = src + 2; /* Skip past 0x */
if (strlen(src) % 2 != 0) {
brcmf_err("Mask invalid format. Length must be even.\n");
return -EINVAL;
}
for (i = 0; *src != '\0'; i++) {
unsigned long res;
char num[3];
strncpy(num, src, 2);
num[2] = '\0';
if (kstrtoul(num, 16, &res))
return -EINVAL;
dst[i] = (u8)res;
src += 2;
}
return i;
}
static void
brcmf_c_pktfilter_offload_enable(struct brcmf_if *ifp, char *arg, int enable,
int master_mode)
{
unsigned long res;
char *argv;
char *arg_save = NULL, *arg_org = NULL;
s32 err;
struct brcmf_pkt_filter_enable_le enable_parm;
arg_save = kstrdup(arg, GFP_ATOMIC);
if (!arg_save)
goto fail;
arg_org = arg_save;
argv = strsep(&arg_save, " ");
if (argv == NULL) {
brcmf_err("No args provided\n");
goto fail;
}
/* Parse packet filter id. */
enable_parm.id = 0;
if (!kstrtoul(argv, 0, &res))
enable_parm.id = cpu_to_le32((u32)res);
/* Enable/disable the specified filter. */
enable_parm.enable = cpu_to_le32(enable);
err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_enable", &enable_parm,
sizeof(enable_parm));
if (err)
brcmf_err("Set pkt_filter_enable error (%d)\n", err);
/* Control the master mode */
err = brcmf_fil_iovar_int_set(ifp, "pkt_filter_mode", master_mode);
if (err)
brcmf_err("Set pkt_filter_mode error (%d)\n", err);
fail:
kfree(arg_org);
}
static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg)
{
struct brcmf_pkt_filter_le *pkt_filter;
unsigned long res;
int buf_len;
s32 err;
u32 mask_size;
u32 pattern_size;
char *argv[8], *buf = NULL;
int i = 0;
char *arg_save = NULL, *arg_org = NULL;
arg_save = kstrdup(arg, GFP_ATOMIC);
if (!arg_save)
goto fail;
arg_org = arg_save;
buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC);
if (!buf)
goto fail;
argv[i] = strsep(&arg_save, " ");
while (argv[i]) {
i++;
if (i >= 8) {
brcmf_err("Too many parameters\n");
goto fail;
}
argv[i] = strsep(&arg_save, " ");
}
if (i != 6) {
brcmf_err("Not enough args provided %d\n", i);
goto fail;
}
pkt_filter = (struct brcmf_pkt_filter_le *)buf;
/* Parse packet filter id. */
pkt_filter->id = 0;
if (!kstrtoul(argv[0], 0, &res))
pkt_filter->id = cpu_to_le32((u32)res);
/* Parse filter polarity. */
pkt_filter->negate_match = 0;
if (!kstrtoul(argv[1], 0, &res))
pkt_filter->negate_match = cpu_to_le32((u32)res);
/* Parse filter type. */
pkt_filter->type = 0;
if (!kstrtoul(argv[2], 0, &res))
pkt_filter->type = cpu_to_le32((u32)res);
/* Parse pattern filter offset. */
pkt_filter->u.pattern.offset = 0;
if (!kstrtoul(argv[3], 0, &res))
pkt_filter->u.pattern.offset = cpu_to_le32((u32)res);
/* Parse pattern filter mask. */
mask_size = brcmf_c_pattern_atoh(argv[4],
(char *)pkt_filter->u.pattern.mask_and_pattern);
/* Parse pattern filter pattern. */
pattern_size = brcmf_c_pattern_atoh(argv[5],
(char *)&pkt_filter->u.pattern.mask_and_pattern[mask_size]);
if (mask_size != pattern_size) {
brcmf_err("Mask and pattern not the same size\n");
goto fail;
}
pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size);
buf_len = offsetof(struct brcmf_pkt_filter_le,
u.pattern.mask_and_pattern);
buf_len += mask_size + pattern_size;
err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter,
buf_len);
if (err)
brcmf_err("Set pkt_filter_add error (%d)\n", err);
fail:
kfree(arg_org);
kfree(buf);
}
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
{
s8 eventmask[BRCMF_EVENTING_MASK_LEN];
u8 buf[BRCMF_DCMD_SMLEN];
struct brcmf_join_pref_params join_pref_params[2];
char *ptr;
s32 err;
/* retreive mac address */
err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
sizeof(ifp->mac_addr));
if (err < 0) {
brcmf_err("Retreiving cur_etheraddr failed, %d\n",
err);
goto done;
}
memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
strcpy(buf, "ver");
err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
if (err < 0) {
brcmf_err("Retreiving version information failed, %d\n",
err);
goto done;
}
ptr = (char *)buf;
strsep(&ptr, "\n");
/* Print fw version info */
brcmf_err("Firmware version = %s\n", buf);
/* locate firmware version number for ethtool */
ptr = strrchr(buf, ' ') + 1;
strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
/* set mpc */
err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
if (err) {
brcmf_err("failed setting mpc\n");
goto done;
}
/*
* Setup timeout if Beacons are lost and roam is off to report
* link down
*/
err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout",
BRCMF_DEFAULT_BCN_TIMEOUT);
if (err) {
brcmf_err("bcn_timeout error (%d)\n", err);
goto done;
}
/* Enable/Disable build-in roaming to allowed ext supplicant to take
* of romaing
*/
err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
if (err) {
brcmf_err("roam_off error (%d)\n", err);
goto done;
}
/* Setup join_pref to select target by RSSI(with boost on 5GHz) */
join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
join_pref_params[0].len = 2;
join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
join_pref_params[0].band = WLC_BAND_5G;
join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
join_pref_params[1].len = 2;
join_pref_params[1].rssi_gain = 0;
join_pref_params[1].band = 0;
err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
sizeof(join_pref_params));
if (err)
brcmf_err("Set join_pref error (%d)\n", err);
/* Setup event_msgs, enable E_IF */
err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
BRCMF_EVENTING_MASK_LEN);
if (err) {
brcmf_err("Get event_msgs error (%d)\n", err);
goto done;
}
setbit(eventmask, BRCMF_E_IF);
err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
BRCMF_EVENTING_MASK_LEN);
if (err) {
brcmf_err("Set event_msgs error (%d)\n", err);
goto done;
}
/* Setup default scan channel time */
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
if (err) {
brcmf_err("BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
err);
goto done;
}
/* Setup default scan unassoc time */
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
if (err) {
brcmf_err("BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
err);
goto done;
}
/* Setup packet filter */
brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER);
brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
0, true);
/* do bus specific preinit here */
err = brcmf_bus_preinit(ifp->drvr->bus_if);
done:
return err;
}
#ifdef CONFIG_BRCM_TRACING
void __brcmf_err(const char *func, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
va_start(args, fmt);
vaf.va = &args;
pr_err("%s: %pV", func, &vaf);
trace_brcmf_err(func, &vaf);
va_end(args);
}
#endif
#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
va_start(args, fmt);
vaf.va = &args;
if (brcmf_msg_level & level)
pr_debug("%s %pV", func, &vaf);
trace_brcmf_dbg(level, func, &vaf);
va_end(args);
}
#endif

View File

@ -17,17 +17,12 @@
#include <linux/netdevice.h>
#include <brcm_hw_ids.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "core.h"
#include "bus.h"
#include "debug.h"
#include "fwil.h"
#include "feature.h"
/*
* firmware error code received if iovar is unsupported.
*/
#define EBRCMF_FEAT_UNSUPPORTED 23
/*
* expand feature list to array of feature strings.
*/

View File

@ -20,7 +20,7 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include "dhd_dbg.h"
#include "debug.h"
#include "firmware.h"
char brcmf_firmware_path[BRCMF_FW_PATH_LEN];

View File

@ -19,9 +19,9 @@
#include <linux/etherdevice.h>
#include <brcmu_utils.h>
#include "dhd.h"
#include "dhd_dbg.h"
#include "dhd_bus.h"
#include "core.h"
#include "debug.h"
#include "bus.h"
#include "proto.h"
#include "flowring.h"
#include "msgbuf.h"

View File

@ -18,8 +18,8 @@
#include "brcmu_wifi.h"
#include "brcmu_utils.h"
#include "dhd.h"
#include "dhd_dbg.h"
#include "core.h"
#include "debug.h"
#include "tracepoint.h"
#include "fwsignal.h"
#include "fweh.h"

View File

@ -22,9 +22,9 @@
#include <linux/netdevice.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "core.h"
#include "bus.h"
#include "debug.h"
#include "tracepoint.h"
#include "fwil.h"
#include "proto.h"
@ -32,6 +32,76 @@
#define MAX_HEX_DUMP_LEN 64
#ifdef DEBUG
static const char * const brcmf_fil_errstr[] = {
"BCME_OK",
"BCME_ERROR",
"BCME_BADARG",
"BCME_BADOPTION",
"BCME_NOTUP",
"BCME_NOTDOWN",
"BCME_NOTAP",
"BCME_NOTSTA",
"BCME_BADKEYIDX",
"BCME_RADIOOFF",
"BCME_NOTBANDLOCKED",
"BCME_NOCLK",
"BCME_BADRATESET",
"BCME_BADBAND",
"BCME_BUFTOOSHORT",
"BCME_BUFTOOLONG",
"BCME_BUSY",
"BCME_NOTASSOCIATED",
"BCME_BADSSIDLEN",
"BCME_OUTOFRANGECHAN",
"BCME_BADCHAN",
"BCME_BADADDR",
"BCME_NORESOURCE",
"BCME_UNSUPPORTED",
"BCME_BADLEN",
"BCME_NOTREADY",
"BCME_EPERM",
"BCME_NOMEM",
"BCME_ASSOCIATED",
"BCME_RANGE",
"BCME_NOTFOUND",
"BCME_WME_NOT_ENABLED",
"BCME_TSPEC_NOTFOUND",
"BCME_ACM_NOTSUPPORTED",
"BCME_NOT_WME_ASSOCIATION",
"BCME_SDIO_ERROR",
"BCME_DONGLE_DOWN",
"BCME_VERSION",
"BCME_TXFAIL",
"BCME_RXFAIL",
"BCME_NODEVICE",
"BCME_NMODE_DISABLED",
"BCME_NONRESIDENT",
"BCME_SCANREJECT",
"BCME_USAGE_ERROR",
"BCME_IOCTL_ERROR",
"BCME_SERIAL_PORT_ERR",
"BCME_DISABLED",
"BCME_DECERR",
"BCME_ENCERR",
"BCME_MICERR",
"BCME_REPLAY",
"BCME_IE_NOTFOUND",
};
static const char *brcmf_fil_get_errstr(u32 err)
{
if (err >= ARRAY_SIZE(brcmf_fil_errstr))
return "(unknown)";
return brcmf_fil_errstr[err];
}
#else
static const char *brcmf_fil_get_errstr(u32 err)
{
return "";
}
#endif /* DEBUG */
static s32
brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
@ -52,11 +122,11 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
if (err >= 0)
err = 0;
else
brcmf_dbg(FIL, "Failed err=%d\n", err);
return 0;
return err;
brcmf_dbg(FIL, "Failed: %s (%d)\n",
brcmf_fil_get_errstr((u32)(-err)), err);
return -EBADE;
}
s32

View File

@ -55,59 +55,63 @@
/* WOWL bits */
/* Wakeup on Magic packet: */
#define WL_WOWL_MAGIC (1 << 0)
#define BRCMF_WOWL_MAGIC (1 << 0)
/* Wakeup on Netpattern */
#define WL_WOWL_NET (1 << 1)
#define BRCMF_WOWL_NET (1 << 1)
/* Wakeup on loss-of-link due to Disassoc/Deauth: */
#define WL_WOWL_DIS (1 << 2)
#define BRCMF_WOWL_DIS (1 << 2)
/* Wakeup on retrograde TSF: */
#define WL_WOWL_RETR (1 << 3)
#define BRCMF_WOWL_RETR (1 << 3)
/* Wakeup on loss of beacon: */
#define WL_WOWL_BCN (1 << 4)
#define BRCMF_WOWL_BCN (1 << 4)
/* Wakeup after test: */
#define WL_WOWL_TST (1 << 5)
#define BRCMF_WOWL_TST (1 << 5)
/* Wakeup after PTK refresh: */
#define WL_WOWL_M1 (1 << 6)
#define BRCMF_WOWL_M1 (1 << 6)
/* Wakeup after receipt of EAP-Identity Req: */
#define WL_WOWL_EAPID (1 << 7)
#define BRCMF_WOWL_EAPID (1 << 7)
/* Wakeind via PME(0) or GPIO(1): */
#define WL_WOWL_PME_GPIO (1 << 8)
#define BRCMF_WOWL_PME_GPIO (1 << 8)
/* need tkip phase 1 key to be updated by the driver: */
#define WL_WOWL_NEEDTKIP1 (1 << 9)
#define BRCMF_WOWL_NEEDTKIP1 (1 << 9)
/* enable wakeup if GTK fails: */
#define WL_WOWL_GTK_FAILURE (1 << 10)
#define BRCMF_WOWL_GTK_FAILURE (1 << 10)
/* support extended magic packets: */
#define WL_WOWL_EXTMAGPAT (1 << 11)
#define BRCMF_WOWL_EXTMAGPAT (1 << 11)
/* support ARP/NS/keepalive offloading: */
#define WL_WOWL_ARPOFFLOAD (1 << 12)
#define BRCMF_WOWL_ARPOFFLOAD (1 << 12)
/* read protocol version for EAPOL frames: */
#define WL_WOWL_WPA2 (1 << 13)
#define BRCMF_WOWL_WPA2 (1 << 13)
/* If the bit is set, use key rotaton: */
#define WL_WOWL_KEYROT (1 << 14)
#define BRCMF_WOWL_KEYROT (1 << 14)
/* If the bit is set, frm received was bcast frame: */
#define WL_WOWL_BCAST (1 << 15)
#define BRCMF_WOWL_BCAST (1 << 15)
/* If the bit is set, scan offload is enabled: */
#define WL_WOWL_SCANOL (1 << 16)
#define BRCMF_WOWL_SCANOL (1 << 16)
/* Wakeup on tcpkeep alive timeout: */
#define WL_WOWL_TCPKEEP_TIME (1 << 17)
#define BRCMF_WOWL_TCPKEEP_TIME (1 << 17)
/* Wakeup on mDNS Conflict Resolution: */
#define WL_WOWL_MDNS_CONFLICT (1 << 18)
#define BRCMF_WOWL_MDNS_CONFLICT (1 << 18)
/* Wakeup on mDNS Service Connect: */
#define WL_WOWL_MDNS_SERVICE (1 << 19)
#define BRCMF_WOWL_MDNS_SERVICE (1 << 19)
/* tcp keepalive got data: */
#define WL_WOWL_TCPKEEP_DATA (1 << 20)
#define BRCMF_WOWL_TCPKEEP_DATA (1 << 20)
/* Firmware died in wowl mode: */
#define WL_WOWL_FW_HALT (1 << 21)
#define BRCMF_WOWL_FW_HALT (1 << 21)
/* Enable detection of radio button changes: */
#define WL_WOWL_ENAB_HWRADIO (1 << 22)
#define BRCMF_WOWL_ENAB_HWRADIO (1 << 22)
/* Offloads detected MIC failure(s): */
#define WL_WOWL_MIC_FAIL (1 << 23)
#define BRCMF_WOWL_MIC_FAIL (1 << 23)
/* Wakeup in Unassociated state (Net/Magic Pattern): */
#define WL_WOWL_UNASSOC (1 << 24)
#define BRCMF_WOWL_UNASSOC (1 << 24)
/* Wakeup if received matched secured pattern: */
#define WL_WOWL_SECURE (1 << 25)
#define BRCMF_WOWL_SECURE (1 << 25)
/* Link Down indication in WoWL mode: */
#define WL_WOWL_LINKDOWN (1 << 31)
#define BRCMF_WOWL_LINKDOWN (1 << 31)
#define BRCMF_WOWL_MAXPATTERNS 8
#define BRCMF_WOWL_MAXPATTERNSIZE 128
/* join preference types for join_pref iovar */
enum brcmf_join_pref_types {
@ -124,6 +128,12 @@ enum brcmf_fil_p2p_if_types {
BRCMF_FIL_P2P_IF_DEV,
};
enum brcmf_wowl_pattern_type {
BRCMF_WOWL_PATTERN_TYPE_BITMAP = 0,
BRCMF_WOWL_PATTERN_TYPE_ARP,
BRCMF_WOWL_PATTERN_TYPE_NA
};
struct brcmf_fil_p2p_if_le {
u8 addr[ETH_ALEN];
__le16 type;
@ -484,4 +494,29 @@ struct brcmf_rx_mgmt_data {
__be32 rate;
};
/**
* struct brcmf_fil_wowl_pattern_le - wowl pattern configuration struct.
*
* @cmd: "add", "del" or "clr".
* @masksize: Size of the mask in #of bytes
* @offset: Pattern byte offset in packet
* @patternoffset: Offset of start of pattern. Starting from field masksize.
* @patternsize: Size of the pattern itself in #of bytes
* @id: id
* @reasonsize: Size of the wakeup reason code
* @type: Type of pattern (enum brcmf_wowl_pattern_type)
*/
struct brcmf_fil_wowl_pattern_le {
u8 cmd[4];
__le32 masksize;
__le32 offset;
__le32 patternoffset;
__le32 patternsize;
__le32 id;
__le32 reasonsize;
__le32 type;
/* u8 mask[] - Mask follows the structure above */
/* u8 pattern[] - Pattern follows the mask is at 'patternoffset' */
};
#endif /* FWIL_TYPES_H_ */

View File

@ -26,15 +26,15 @@
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_dbg.h"
#include "dhd_bus.h"
#include "core.h"
#include "debug.h"
#include "bus.h"
#include "fwil.h"
#include "fwil_types.h"
#include "fweh.h"
#include "fwsignal.h"
#include "p2p.h"
#include "wl_cfg80211.h"
#include "cfg80211.h"
#include "proto.h"
/**

View File

@ -24,13 +24,13 @@
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_dbg.h"
#include "core.h"
#include "debug.h"
#include "proto.h"
#include "msgbuf.h"
#include "commonring.h"
#include "flowring.h"
#include "dhd_bus.h"
#include "bus.h"
#include "tracepoint.h"

View File

@ -21,8 +21,8 @@
#include <linux/mmc/sdio_func.h>
#include <defs.h>
#include "dhd_dbg.h"
#include "sdio_host.h"
#include "debug.h"
#include "sdio.h"
void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
{

View File

@ -21,12 +21,12 @@
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include <defs.h>
#include <dhd.h>
#include <dhd_dbg.h>
#include "core.h"
#include "debug.h"
#include "fwil.h"
#include "fwil_types.h"
#include "p2p.h"
#include "wl_cfg80211.h"
#include "cfg80211.h"
/* parameters used for p2p escan */
#define P2PAPI_SCAN_NPROBES 1

View File

@ -30,8 +30,8 @@
#include <brcmu_wifi.h>
#include <brcm_hw_ids.h>
#include "dhd_dbg.h"
#include "dhd_bus.h"
#include "debug.h"
#include "bus.h"
#include "commonring.h"
#include "msgbuf.h"
#include "pcie.h"

View File

@ -20,9 +20,9 @@
#include <linux/netdevice.h>
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "core.h"
#include "bus.h"
#include "debug.h"
#include "proto.h"
#include "bcdc.h"
#include "msgbuf.h"

Some files were not shown because too many files have changed in this diff Show More