lkml.org 
[lkml]   [2017]   [Jul]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH 1/2] staging: net: wireless: add ESP8089 WiFi driver
    Yeah.  This feels like it could go into the main linux-wireless tree
    with a little work. I put some random review comments inline. Nothing
    super drastic stands out.

    regards,
    dan carpenter


    On Fri, Jul 21, 2017 at 04:35:01PM +0200, Quentin Schulz wrote:
    > The Espressif ESP8089 WiFi chips can be often found in cheap tablets.
    > There is one in A23 Polaroid tablets for example.
    >
    > The chip is often embedded as an eMMC SDIO device.
    >
    > The code was taken from an out-of-tree repository and has seen a first
    > pass in the cleanup process.
    >
    > At the moment, there is no publicly available datasheet for this chip.
    >
    > Cc: Hans de Goede <hdegoede@redhat.com>
    > Cc: Icenowy Zheng <icenowy@aosc.xyz>
    > Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
    > ---
    > drivers/staging/Kconfig | 2 +
    > drivers/staging/Makefile | 1 +
    > drivers/staging/esp8089/Kconfig | 13 +
    > drivers/staging/esp8089/Makefile | 7 +
    > drivers/staging/esp8089/esp_ctrl.c | 527 ++++++++
    > drivers/staging/esp8089/esp_ctrl.h | 48 +
    > drivers/staging/esp8089/esp_debug.c | 247 ++++
    > drivers/staging/esp8089/esp_debug.h | 69 ++
    > drivers/staging/esp8089/esp_file.c | 221 ++++
    > drivers/staging/esp8089/esp_file.h | 30 +
    > drivers/staging/esp8089/esp_init_data.h | 17 +
    > drivers/staging/esp8089/esp_io.c | 294 +++++
    > drivers/staging/esp8089/esp_mac80211.c | 1496 +++++++++++++++++++++++
    > drivers/staging/esp8089/esp_mac80211.h | 33 +
    > drivers/staging/esp8089/esp_main.c | 199 ++++
    > drivers/staging/esp8089/esp_pub.h | 188 +++
    > drivers/staging/esp8089/esp_sif.h | 131 ++
    > drivers/staging/esp8089/esp_sip.c | 1718 +++++++++++++++++++++++++++
    > drivers/staging/esp8089/esp_sip.h | 150 +++
    > drivers/staging/esp8089/esp_utils.c | 133 +++
    > drivers/staging/esp8089/esp_utils.h | 27 +
    > drivers/staging/esp8089/esp_wl.h | 35 +
    > drivers/staging/esp8089/esp_wmac.h | 87 ++
    > drivers/staging/esp8089/sdio_sif_esp.c | 552 +++++++++
    > drivers/staging/esp8089/sip2_common.h | 388 ++++++
    > drivers/staging/esp8089/slc_host_register.h | 263 ++++
    > 26 files changed, 6876 insertions(+)
    > create mode 100644 drivers/staging/esp8089/Kconfig
    > create mode 100644 drivers/staging/esp8089/Makefile
    > create mode 100644 drivers/staging/esp8089/esp_ctrl.c
    > create mode 100644 drivers/staging/esp8089/esp_ctrl.h
    > create mode 100644 drivers/staging/esp8089/esp_debug.c
    > create mode 100644 drivers/staging/esp8089/esp_debug.h
    > create mode 100644 drivers/staging/esp8089/esp_file.c
    > create mode 100644 drivers/staging/esp8089/esp_file.h
    > create mode 100644 drivers/staging/esp8089/esp_init_data.h
    > create mode 100644 drivers/staging/esp8089/esp_io.c
    > create mode 100644 drivers/staging/esp8089/esp_mac80211.c
    > create mode 100644 drivers/staging/esp8089/esp_mac80211.h
    > create mode 100644 drivers/staging/esp8089/esp_main.c
    > create mode 100644 drivers/staging/esp8089/esp_pub.h
    > create mode 100644 drivers/staging/esp8089/esp_sif.h
    > create mode 100644 drivers/staging/esp8089/esp_sip.c
    > create mode 100644 drivers/staging/esp8089/esp_sip.h
    > create mode 100644 drivers/staging/esp8089/esp_utils.c
    > create mode 100644 drivers/staging/esp8089/esp_utils.h
    > create mode 100644 drivers/staging/esp8089/esp_wl.h
    > create mode 100644 drivers/staging/esp8089/esp_wmac.h
    > create mode 100644 drivers/staging/esp8089/sdio_sif_esp.c
    > create mode 100644 drivers/staging/esp8089/sip2_common.h
    > create mode 100644 drivers/staging/esp8089/slc_host_register.h
    >
    > diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
    > index e97d72e3bc40..0bd007837429 100644
    > --- a/drivers/staging/Kconfig
    > +++ b/drivers/staging/Kconfig
    > @@ -114,4 +114,6 @@ source "drivers/staging/vboxvideo/Kconfig"
    >
    > source "drivers/staging/pi433/Kconfig"
    >
    > +source "drivers/staging/esp8089/Kconfig"
    > +
    > endif # STAGING
    > diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
    > index 993ed0c1556c..23cfa1258c4e 100644
    > --- a/drivers/staging/Makefile
    > +++ b/drivers/staging/Makefile
    > @@ -46,3 +46,4 @@ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
    > obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/
    > obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/
    > obj-$(CONFIG_PI433) += pi433/
    > +obj-$(CONFIG_ESP8089) += esp8089/
    > diff --git a/drivers/staging/esp8089/Kconfig b/drivers/staging/esp8089/Kconfig
    > new file mode 100644
    > index 000000000000..8fdd8fa828ad
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/Kconfig
    > @@ -0,0 +1,13 @@
    > +config ESP8089
    > + tristate "Espressif ESP8089 SDIO WiFi"
    > + depends on MAC80211
    > + ---help---
    > + ESP8089 is a low-budget 2.4GHz WiFi chip by Espressif, used in many
    > + cheap tablets with Allwinner or Rockchip SoC
    > +
    > +config ESP8089_DEBUG_FS
    > + bool "Enable DebugFS support for ESP8089"
    > + depends on ESP8089
    > + default y
    > + ---help---
    > + DebugFS support for ESP8089
    > diff --git a/drivers/staging/esp8089/Makefile b/drivers/staging/esp8089/Makefile
    > new file mode 100644
    > index 000000000000..827c66d8b5d5
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/Makefile
    > @@ -0,0 +1,7 @@
    > +MODULE_NAME = esp8089
    > +
    > +$(MODULE_NAME)-y := esp_debug.o sdio_sif_esp.o esp_io.o \
    > + esp_file.o esp_main.o esp_sip.o esp_ctrl.o \
    > + esp_mac80211.o esp_debug.o esp_utils.o
    > +
    > +obj-$(CONFIG_ESP8089) := esp8089.o
    > diff --git a/drivers/staging/esp8089/esp_ctrl.c b/drivers/staging/esp8089/esp_ctrl.c
    > new file mode 100644
    > index 000000000000..e5a95e7b313f
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_ctrl.c
    > @@ -0,0 +1,527 @@
    > +/*
    > + * Copyright (c) 2009 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#include <net/mac80211.h>
    > +#include <net/cfg80211.h>
    > +#include <linux/skbuff.h>
    > +#include <linux/bitops.h>
    > +#include <linux/firmware.h>
    > +
    > +#include "esp_init_data.h"
    > +#include "esp_pub.h"
    > +#include "esp_sip.h"
    > +#include "esp_ctrl.h"
    > +#include "esp_sif.h"
    > +#include "esp_debug.h"
    > +#include "esp_wmac.h"
    > +#include "esp_utils.h"
    > +#include "esp_wl.h"
    > +#include "esp_file.h"
    > +#include "esp_version.h"
    > +
    > +#define DRIVER_VER 0xbdf5087c3debll
    > +
    > +static void esp_tx_ba_session_op(struct esp_sip *sip, struct esp_node *node,
    > + enum trc_ampdu_state state, u8 tid)
    > +{
    > + struct esp_tx_tid *txtid = &node->tid[tid];
    > +
    > + if (state != TRC_TX_AMPDU_STOPPED && state != TRC_TX_AMPDU_OPERATIONAL)
    > + return;
    > +
    > + if (state == TRC_TX_AMPDU_STOPPED) {
    > + if (txtid->state != ESP_TID_STATE_OPERATIONAL) {
    > + dev_err(sip->epub->dev,
    > + "%s tid %d TXAMPDU GOT STOP EVT IN WRONG STATE %d\n",
    > + __func__, tid, txtid->state);
    > + return;
    > + }
    > +
    > + dev_dbg(sip->epub->dev, "%s tid %d TXAMPDU GOT STOP EVT\n",
    > + __func__, tid);
    > +
    > + spin_lock_bh(&sip->epub->tx_ampdu_lock);
    > + txtid->state = ESP_TID_STATE_WAIT_STOP;
    > + spin_unlock_bh(&sip->epub->tx_ampdu_lock);
    > +
    > + ieee80211_stop_tx_ba_session(node->sta, (u16)tid);
    > + return;
    > + }
    > +
    > + if (txtid->state == ESP_TID_STATE_STOP) {
    > + dev_dbg(sip->epub->dev, "%s tid %d TXAMPDU GOT OPERATIONAL\n",
    > + __func__, tid);
    > +
    > + spin_lock_bh(&sip->epub->tx_ampdu_lock);
    > + txtid->state = ESP_TID_STATE_TRIGGER;
    > + spin_unlock_bh(&sip->epub->tx_ampdu_lock);
    > +
    > + ieee80211_start_tx_ba_session(node->sta, (u16)tid, 0);
    > + return;
    > + } else if (txtid->state == ESP_TID_STATE_OPERATIONAL) {
    > + sip_send_ampdu_action(sip->epub, SIP_AMPDU_TX_OPERATIONAL,
    > + node->sta->addr, tid, node->ifidx, 0);
    > + return;
    > + }
    > +
    > + dev_err(sip->epub->dev,
    > + "%s tid %d TXAMPDU GOT OPERATIONAL EVT IN WRONG STATE %d\n",
    > + __func__, tid, txtid->state);
    > +}
    > +
    > +int sip_parse_events(struct esp_sip *sip, u8 *buf)
    > +{
    > + struct sip_hdr *hdr = (struct sip_hdr *)buf;
    > + struct sip_evt_bootup2 *bootup_evt;
    > + struct sip_evt_scan_report *report;
    > + struct sip_evt_roc *roc;
    > + struct sip_evt_trc_ampdu *ampdu;
    > + struct sip_evt_noisefloor *noisefloor;
    > + struct esp_node *node;
    > + char *ep;
    > + u8 *p;
    > + u16 *len;
    > + int i;
    > +
    > + switch (hdr->c_evtid) {
    > + case SIP_EVT_TARGET_ON:
    > + /* use rx work queue to send... */
    > + if (atomic_read(&sip->state) == SIP_PREPARE_BOOT ||
    > + atomic_read(&sip->state) == SIP_BOOT) {
    > + atomic_set(&sip->state, SIP_SEND_INIT);
    > + queue_work(sip->epub->esp_wkq, &sip->rx_process_work);
    > + break;
    > + }
    > + dev_err(sip->epub->dev, "%s boot during wrong state %d\n",
    > + __func__, atomic_read(&sip->state));
    > + break;
    > +
    > + case SIP_EVT_BOOTUP:
    > + bootup_evt = (struct sip_evt_bootup2 *)(buf + SIP_CTRL_HDR_LEN);
    > +
    > + kfree(sip->rawbuf);
    > +
    > + sip_post_init(sip, bootup_evt);
    > + if (gl_bootup_cplx)
    > + complete(gl_bootup_cplx);
    > +
    > + break;
    > +
    > + case SIP_EVT_RESETTING:
    > + sip->epub->wait_reset = 1;
    > + if (gl_bootup_cplx)
    > + complete(gl_bootup_cplx);
    > + break;
    > +
    > + case SIP_EVT_SCAN_RESULT:
    > + if (!atomic_read(&sip->epub->wl.off)) {
    > + report = (struct sip_evt_scan_report *)(buf + SIP_CTRL_HDR_LEN);
    > + sip_scandone_process(sip, report);
    > + break;
    > + }
    > +
    > + dev_err(sip->epub->dev, "%s scan result while wlan off\n",
    > + __func__);
    > + break;
    > +
    > + case SIP_EVT_ROC:
    > + roc = (struct sip_evt_roc *)(buf + SIP_CTRL_HDR_LEN);
    > + esp_rocdone_process(sip->epub->hw, roc);
    > + break;
    > +
    > + case SIP_EVT_SNPRINTF_TO_HOST:
    > + p = buf + sizeof(struct sip_hdr) + sizeof(u16);
    > + len = (u16 *)(buf + sizeof(struct sip_hdr));
    > + dev_dbg(sip->epub->dev, "esp_host:%llx\nesp_target: %.*s\n",
    > + DRIVER_VER, *len, p);
    > +
    > + if (!*len || sip->epub->sdio_state != ESP_SDIO_STATE_FIRST_INIT)
    > + break;
    > +
    > + dev_dbg(sip->epub->dev,
    > + "SNPRINTF TO HOST: esp_host:%llx\nesp_target: %.*s\n",
    > + DRIVER_VER, *len, p);
    > + break;
    > +
    > + case SIP_EVT_TRC_AMPDU:
    > + if (atomic_read(&sip->epub->wl.off)) {
    > + dev_err(sip->epub->dev,
    > + "%s scan result while wlan off\n", __func__);
    > + break;
    > + }
    > +
    > + ampdu = (struct sip_evt_trc_ampdu *)(buf + SIP_CTRL_HDR_LEN);
    > + node = esp_get_node_by_addr(sip->epub, ampdu->addr);
    > + if (!node)
    > + break;
    > + for (i = 0; i < 8; i++)
    > + if (ampdu->tid & BIT(i))
    > + esp_tx_ba_session_op(sip, node, ampdu->state,
    > + i);
    > + break;
    > +
    > + case SIP_EVT_INIT_EP:
    > + ep = (char *)(buf + SIP_CTRL_HDR_LEN);
    > + dev_dbg(sip->epub->dev, "Phy Init: %s\n", ep);
    > + break;
    > +
    > + case SIP_EVT_NOISEFLOOR:
    > + noisefloor = (struct sip_evt_noisefloor *)(buf + SIP_CTRL_HDR_LEN);
    > + atomic_set(&sip->noise_floor, noisefloor->noise_floor);
    > + break;
    > +
    > + default:
    > + break;
    > + }
    > +
    > + return 0;
    > +}
    > +
    > +/* FIXME: ugly af */
    > +void sip_send_chip_init(struct esp_sip *sip)
    > +{
    > + size_t size = sizeof(esp_init_data);
    > +
    > + fix_init_data(esp_init_data, size);
    > + atomic_sub(1, &sip->tx_credits);
    > + sip_send_cmd(sip, SIP_CMD_INIT, size, (void *)esp_init_data);
    > +}
    > +
    > +int sip_send_config(struct esp_pub *epub, struct ieee80211_conf *conf)
    > +{
    > + struct sk_buff *skb;
    > + struct sip_cmd_config *configcmd;
    > +
    > + skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_config) +
    > + sizeof(struct sip_hdr), SIP_CMD_CONFIG);
    > + if (!skb)
    > + return -ENOMEM;
    > +
    > + dev_dbg(epub->dev, "%s config center freq %d\n", __func__,
    > + conf->chandef.chan->center_freq);
    > +
    > + configcmd = (struct sip_cmd_config *)(skb->data + sizeof(struct sip_hdr));
    > + configcmd->center_freq = conf->chandef.chan->center_freq;
    > + configcmd->duration = 0;
    > +
    > + return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
    > +}
    > +
    > +int sip_send_bss_info_update(struct esp_pub *epub, struct esp_vif *evif,
    > + u8 *bssid, int assoc)
    > +{
    > + struct sk_buff *skb;
    > + struct sip_cmd_bss_info_update *bsscmd;
    > +
    > + skb = sip_alloc_ctrl_skbuf(epub->sip,
    > + sizeof(struct sip_cmd_bss_info_update) +
    > + sizeof(struct sip_hdr),
    > + SIP_CMD_BSS_INFO_UPDATE);
    > + if (!skb)
    > + return -ENOMEM;
    > +
    > + bsscmd = (struct sip_cmd_bss_info_update *)(skb->data + sizeof(struct sip_hdr));
    > +
    > + if (assoc == 2) //hack for softAP mode
    > + bsscmd->beacon_int = evif->beacon_interval;
    > + else if (assoc == 1)
    > + set_bit(ESP_WL_FLAG_CONNECT, &epub->wl.flags);
    > + else
    > + clear_bit(ESP_WL_FLAG_CONNECT, &epub->wl.flags);
    > +
    > + bsscmd->bssid_no = evif->index;
    > + bsscmd->isassoc = assoc;
    > + bsscmd->beacon_int = evif->beacon_interval;
    > + memcpy(bsscmd->bssid, bssid, ETH_ALEN);
    > +
    > + return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
    > +}
    > +
    > +int sip_send_wmm_params(struct esp_pub *epub, u8 aci,
    > + const struct ieee80211_tx_queue_params *params)
    > +{
    > + struct sk_buff *skb;
    > + struct sip_cmd_set_wmm_params *bsscmd;
    > +
    > + skb = sip_alloc_ctrl_skbuf(epub->sip,
    > + sizeof(struct sip_cmd_set_wmm_params) +
    > + sizeof(struct sip_hdr),
    > + SIP_CMD_SET_WMM_PARAM);
    > + if (!skb)
    > + return -ENOMEM;
    > +
    > + bsscmd = (struct sip_cmd_set_wmm_params *)(skb->data + sizeof(struct sip_hdr));
    > + bsscmd->aci = aci;
    > + bsscmd->aifs = params->aifs;
    > + bsscmd->txop_us = params->txop * 32;
    > + bsscmd->ecw_min = 32 - __builtin_clz(params->cw_min);
    > + bsscmd->ecw_max = 32 - __builtin_clz(params->cw_max);
    > +
    > + return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
    > +}
    > +
    > +int sip_send_ampdu_action(struct esp_pub *epub, u8 action_num, const u8 *addr,
    > + u16 tid, u16 ssn, u8 buf_size)
    > +{
    > + int index = 0;
    > + struct sk_buff *skb;
    > + struct sip_cmd_ampdu_action *action;
    > +
    > + if (action_num == SIP_AMPDU_RX_START)
    > + index = esp_get_empty_rxampdu(epub, addr, tid);
    > + else if (action_num == SIP_AMPDU_RX_STOP)
    > + index = esp_get_exist_rxampdu(epub, addr, tid);
    > +
    > + if (index < 0)
    > + return -EACCES;
    > +
    > + skb = sip_alloc_ctrl_skbuf(epub->sip,
    > + sizeof(struct sip_cmd_ampdu_action) +
    > + sizeof(struct sip_hdr),
    > + SIP_CMD_AMPDU_ACTION);
    > + if (!skb)
    > + return -ENOMEM;
    > +
    > + action = (struct sip_cmd_ampdu_action *)(skb->data + sizeof(struct sip_hdr));
    > + action->action = action_num;
    > + //for TX, it means interface index
    > + action->index = ssn;
    > +
    > + switch (action_num) {
    > + case SIP_AMPDU_RX_START:
    > + action->ssn = ssn;
    > + case SIP_AMPDU_RX_STOP:
    > + action->index = index;
    > + case SIP_AMPDU_TX_OPERATIONAL:
    > + case SIP_AMPDU_TX_STOP:
    > + action->win_size = buf_size;
    > + action->tid = tid;
    > + memcpy(action->addr, addr, ETH_ALEN);
    > + break;
    > + }
    > +
    > + return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
    > +}
    > +
    > +#ifdef HW_SCAN
    > +/* send cmd to target, if aborted is true, inform target stop scan, report scan complete imediately
    > + * return 1: complete over, 0: success, still have next scan, -1: hardware failure
    > + */
    > +int sip_send_scan(struct esp_pub *epub)
    > +{
    > + struct cfg80211_scan_request *scan_req = epub->wl.scan_req;
    > + struct sk_buff *skb;
    > + struct sip_cmd_scan *scancmd;
    > + u8 *ptr;
    > + int i;
    > + u8 append_len, ssid_len;
    > +
    > + ESSERT(scan_req);
    > + if (!scan_req->n_ssids)
    > + ssid_len = 0;
    > + else if (scan_req->n_ssids == 1)
    > + ssid_len = scan_req->ssids->ssid_len;
    > + /* Limit to two SSIDs */
    > + else
    > + ssid_len = scan_req->ssids->ssid_len +
    > + (scan_req->ssids + 1)->ssid_len;
    > +
    > + append_len = ssid_len + scan_req->n_channels + scan_req->ie_len;
    > +
    > + skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_scan) +
    > + sizeof(struct sip_hdr) + append_len,
    > + SIP_CMD_SCAN);
    > +
    > + if (!skb)
    > + return -ENOMEM;
    > +
    > + ptr = skb->data;
    > + scancmd = (struct sip_cmd_scan *)(ptr + sizeof(struct sip_hdr));
    > +
    > + ptr += sizeof(struct sip_hdr) + sizeof(struct sip_cmd_scan);
    > + scancmd->aborted = false;
    > +
    > + /* FIXME: meh */
    > + if (scan_req->n_ssids <= 0) {
    > + scancmd->ssid_len = 0;
    > + } else {
    > + scancmd->ssid_len = ssid_len;
    > + if (scan_req->n_ssids == 1)
    > + memcpy(ptr, scan_req->ssids->ssid, scancmd->ssid_len);
    > + /* Limit to two SSIDs */
    > + else
    > + memcpy(ptr, (scan_req->ssids + 1)->ssid,
    > + scancmd->ssid_len);
    > + }
    > +
    > + ptr += scancmd->ssid_len;
    > + scancmd->n_channels = scan_req->n_channels;
    > + for (i = 0; i < scan_req->n_channels; i++)
    > + ptr[i] = scan_req->channels[i]->hw_value;
    > +
    > + ptr += scancmd->n_channels;
    > + if (scan_req->ie_len && scan_req->ie) {
    > + scancmd->ie_len = scan_req->ie_len;
    > + memcpy(ptr, scan_req->ie, scan_req->ie_len);
    > + } else {
    > + scancmd->ie_len = 0;
    > + }
    > + //add a flag that support two ssids,
    > + if (scan_req->n_ssids > 1)
    > + scancmd->ssid_len |= 0x80;
    > +
    > + return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
    > +}
    > +#endif
    > +
    > +void sip_scandone_process(struct esp_sip *sip,
    > + struct sip_evt_scan_report *scan_report)
    > +{
    > + struct esp_pub *epub = sip->epub;
    > +
    > + if (epub->wl.scan_req) {
    > + hw_scan_done(epub, scan_report->aborted);
    > + epub->wl.scan_req = NULL;
    > + }
    > +}
    > +
    > +int sip_send_setkey(struct esp_pub *epub, u8 bssid_no, u8 *peer_addr,
    > + struct ieee80211_key_conf *key, u8 isvalid)
    > +{
    > + struct sip_cmd_setkey *setkeycmd;
    > + struct sk_buff *skb;
    > +
    > + skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_setkey) +
    > + sizeof(struct sip_hdr), SIP_CMD_SETKEY);
    > +
    > + if (!skb)
    > + return -ENOMEM;
    > +
    > + setkeycmd = (struct sip_cmd_setkey *)(skb->data + sizeof(struct sip_hdr));
    > +
    > + if (peer_addr)
    > + memcpy(setkeycmd->addr, peer_addr, ETH_ALEN);
    > + else
    > + memset(setkeycmd->addr, 0, ETH_ALEN);
    > +
    > + setkeycmd->bssid_no = bssid_no;
    > + setkeycmd->hw_key_idx = key->hw_key_idx;
    > +
    > + if (isvalid) {
    > + setkeycmd->alg = esp_cipher2alg(key->cipher);
    > + setkeycmd->keyidx = key->keyidx;
    > + setkeycmd->keylen = key->keylen;
    > + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
    > + memcpy(setkeycmd->key, key->key, 16);
    > + memcpy(setkeycmd->key + 16, key->key + 24, 8);
    > + memcpy(setkeycmd->key + 24, key->key + 16, 8);
    > + } else {
    > + memcpy(setkeycmd->key, key->key, key->keylen);
    > + }
    > +
    > + setkeycmd->flags = 1;
    > + } else {
    > + setkeycmd->flags = 0;
    > + }
    > +
    > + return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
    > +}
    > +
    > +//remain_on_channel
    > +int sip_send_roc(struct esp_pub *epub, u16 center_freq, u16 duration)
    > +{
    > + struct sk_buff *skb;
    > + struct sip_cmd_config *configcmd;
    > +
    > + skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_config) +
    > + sizeof(struct sip_hdr), SIP_CMD_CONFIG);
    > + if (!skb)
    > + return -ENOMEM;
    > +
    > + configcmd = (struct sip_cmd_config *)(skb->data + sizeof(struct sip_hdr));
    > + configcmd->center_freq = center_freq;
    > + configcmd->duration = duration;
    > +
    > + return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
    > +}
    > +
    > +int sip_send_set_sta(struct esp_pub *epub, u8 ifidx, u8 set,
    > + struct ieee80211_sta *sta, struct ieee80211_vif *vif,
    > + u8 index)
    > +{
    > + struct sk_buff *skb;
    > + struct sip_cmd_setsta *setstacmd;
    > +
    > + skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_setsta) +
    > + sizeof(struct sip_hdr), SIP_CMD_SETSTA);
    > + if (!skb)
    > + return -ENOMEM;
    > +
    > + setstacmd = (struct sip_cmd_setsta *)(skb->data + sizeof(struct sip_hdr));
    > + setstacmd->ifidx = ifidx;
    > + setstacmd->index = index;
    > + setstacmd->set = set;
    > +
    > + if (!sta->aid)
    > + setstacmd->aid = vif->bss_conf.aid;
    > + else
    > + setstacmd->aid = sta->aid;
    > +
    > + memcpy(setstacmd->mac, sta->addr, ETH_ALEN);
    > +
    > + if (!set)
    > + goto send;
    > +
    > + if (sta->ht_cap.ht_supported) {
    > + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
    > + setstacmd->phymode = ESP_IEEE80211_T_HT20_S;
    > + else
    > + setstacmd->phymode = ESP_IEEE80211_T_HT20_L;
    > + setstacmd->ampdu_factor = sta->ht_cap.ampdu_factor;
    > + setstacmd->ampdu_density = sta->ht_cap.ampdu_density;
    > + goto send;
    > + }
    > +
    > + if (sta->supp_rates[NL80211_BAND_2GHZ] & ~CONF_HW_BIT_RATE_11B_MASK)
    > + setstacmd->phymode = ESP_IEEE80211_T_OFDM;
    > + else
    > + setstacmd->phymode = ESP_IEEE80211_T_CCK;
    > +
    > +send:
    > + return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
    > +}
    > +
    > +int sip_send_recalc_credit(struct esp_pub *epub)
    > +{
    > + struct sk_buff *skb;
    > +
    > + skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_hdr),
    > + SIP_CMD_RECALC_CREDIT);
    > + if (!skb)
    > + return -ENOMEM;
    > +
    > + return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_HEAD);
    > +}
    > +
    > +int sip_cmd(struct esp_pub *epub, enum sip_cmd_id cmd_id, u8 *cmd_buf,
    > + u8 cmd_len)
    > +{
    > + struct sk_buff *skb;
    > +
    > + skb = sip_alloc_ctrl_skbuf(epub->sip, cmd_len + sizeof(struct sip_hdr),
    > + cmd_id);
    > + if (!skb)
    > + return -ENOMEM;
    > +
    > + memcpy(skb->data + sizeof(struct sip_hdr), cmd_buf, cmd_len);
    > +
    > + return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
    > +}
    > diff --git a/drivers/staging/esp8089/esp_ctrl.h b/drivers/staging/esp8089/esp_ctrl.h
    > new file mode 100644
    > index 000000000000..b9143bb135b3
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_ctrl.h
    > @@ -0,0 +1,48 @@
    > +/*
    > + * Copyright (c) 2009 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +#ifndef _ESP_CTRL_H_
    > +#define _ESP_CTRL_H_
    > +
    > +extern struct completion *gl_bootup_cplx;
    > +
    > +int sip_send_config(struct esp_pub *epub, struct ieee80211_conf *conf);
    > +
    > +int sip_send_setkey(struct esp_pub *epub, u8 bssid_no, u8 *peer_addr,
    > + struct ieee80211_key_conf *key, u8 isvalid);
    > +
    > +int sip_send_scan(struct esp_pub *epub);
    > +
    > +void sip_scandone_process(struct esp_sip *sip,
    > + struct sip_evt_scan_report *scan_report);
    > +
    > +int sip_send_bss_info_update(struct esp_pub *epub, struct esp_vif *evif,
    > + u8 *bssid, int assoc);
    > +
    > +int sip_send_wmm_params(struct esp_pub *epub, u8 aci,
    > + const struct ieee80211_tx_queue_params *params);
    > +
    > +int sip_send_ampdu_action(struct esp_pub *epub, u8 action_num, const u8 *addr,
    > + u16 tid, u16 ssn, u8 buf_size);
    > +
    > +int sip_send_roc(struct esp_pub *epub, u16 center_freq, u16 duration);
    > +
    > +int sip_send_set_sta(struct esp_pub *epub, u8 ifidx, u8 set,
    > + struct ieee80211_sta *sta, struct ieee80211_vif *vif,
    > + u8 index);
    > +
    > +int sip_parse_events(struct esp_sip *sip, u8 *buf);
    > +
    > +int sip_send_recalc_credit(struct esp_pub *epub);
    > +
    > +int sip_cmd(struct esp_pub *epub, enum sip_cmd_id cmd_id, u8 *cmd_buf,
    > + u8 cmd_len);
    > +
    > +#endif /* _ESP_CTRL_H_ */
    > diff --git a/drivers/staging/esp8089/esp_debug.c b/drivers/staging/esp8089/esp_debug.c
    > new file mode 100644
    > index 000000000000..26472b433768
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_debug.c
    > @@ -0,0 +1,247 @@
    > +/*
    > + * Copyright (c) 2011 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#include <linux/types.h>
    > +#include <linux/kernel.h>
    > +
    > +#include <net/mac80211.h>
    > +#include "sip2_common.h"
    > +
    > +#include "esp_debug.h"
    > +
    > +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_ESP8089_DEBUG_FS)
    > +
    > +static struct dentry *esp_debugfs_root;
    > +
    > +static ssize_t esp_debugfs_read(struct file *filp, char __user *buffer,
    > + size_t count, loff_t *ppos)
    > +{
    > + if (*ppos >= 32)
    > + return 0;
    > +
    > + if (*ppos + count > 32)
    > + count = 32 - *ppos;
    > +
    > + if (copy_to_user(buffer, filp->private_data + *ppos, count))
    > + return -EFAULT;
    > +
    > + *ppos += count;
    > +
    > + return count;
    > +}
    > +
    > +static ssize_t esp_debugfs_write(struct file *filp, const char __user *buffer,
    > + size_t count, loff_t *ppos)
    > +{
    > + if (*ppos >= 32)
    > + return 0;
    > +
    > + if (*ppos + count > 32)
    > + count = 32 - *ppos;
    > +
    > + if (copy_from_user(filp->private_data + *ppos, buffer, count))
    > + return -EFAULT;
    > +
    > + *ppos += count;
    > +
    > + return count;
    > +}
    > +
    > +const struct file_operations esp_debugfs_fops = {
    > + .owner = THIS_MODULE,
    > + .open = simple_open,
    > + .read = esp_debugfs_read,
    > + .write = esp_debugfs_write,
    > +};
    > +
    > +struct dentry *esp_dump_var(const char *name, struct dentry *parent,
    > + void *value, enum esp_type type)
    > +{
    > + struct dentry *rc = NULL;
    > + umode_t mode = 0644;
    > +
    > + if (!esp_debugfs_root)
    > + return NULL;
    > +
    > + if (!parent)
    > + parent = esp_debugfs_root;
    > +
    > + switch (type) {
    > + case ESP_U8:
    > + rc = debugfs_create_u8(name, mode, parent, (u8 *)value);
    > + break;
    > + case ESP_U16:
    > + rc = debugfs_create_u16(name, mode, parent, (u16 *)value);
    > + break;
    > + case ESP_U32:
    > + rc = debugfs_create_u32(name, mode, parent, (u32 *)value);
    > + break;
    > + case ESP_U64:
    > + rc = debugfs_create_u64(name, mode, parent, (u64 *)value);
    > + break;
    > + case ESP_BOOL:
    > + rc = debugfs_create_bool(name, mode, parent, (bool *)value);
    > + break;
    > + default: //32
    > + rc = debugfs_create_u32(name, mode, parent, (u32 *)value);
    > + }
    > +
    > + if (!rc)
    > + goto _fail;
    > +
    > + return rc;
    > +
    > +_fail:
    > + debugfs_remove_recursive(esp_debugfs_root);
    > + esp_debugfs_root = NULL;
    > + printk("%s failed, debugfs root removed; var name: %s\n", __func__,
    > + name);
    > + return NULL;
    > +}
    > +
    > +struct dentry *esp_dump_array(const char *name, struct dentry *parent,
    > + struct debugfs_blob_wrapper *blob)
    > +{
    > + struct dentry *rc;
    > + umode_t mode = 0644;
    > +
    > + if (!esp_debugfs_root)
    > + return NULL;
    > +
    > + if (!parent)
    > + parent = esp_debugfs_root;
    > +
    > + rc = debugfs_create_blob(name, mode, parent, blob);
    > + if (!rc)
    > + goto _fail;
    > +
    > + return rc;
    > +
    > +_fail:
    > + debugfs_remove_recursive(esp_debugfs_root);
    > + esp_debugfs_root = NULL;
    > + printk("%s failed, debugfs root removed; var name: %s\n", __func__,
    > + name);
    > + return NULL;
    > +}
    > +
    > +struct dentry *esp_dump(const char *name, struct dentry *parent,
    > + void *data, int size)
    > +{
    > + struct dentry *rc;
    > + umode_t mode = 0644;
    > +
    > + if (!esp_debugfs_root)
    > + return NULL;
    > +
    > + if (!parent)
    > + parent = esp_debugfs_root;
    > +
    > + rc = debugfs_create_file(name, mode, parent, data, &esp_debugfs_fops);
    > + if (!rc)
    > + goto _fail;
    > +
    > + return rc;
    > +
    > +_fail:
    > + debugfs_remove_recursive(esp_debugfs_root);
    > + esp_debugfs_root = NULL;
    > + printk("%s failed, debugfs root removed; var name: %s\n", __func__,
    > + name);
    > + return NULL;
    > +}
    > +
    > +struct dentry *esp_debugfs_add_sub_dir(const char *name)
    > +{
    > + struct dentry *sub_dir;
    > +
    > + sub_dir = debugfs_create_dir(name, esp_debugfs_root);
    > + if (!sub_dir)
    > + goto _fail;
    > +
    > + return sub_dir;
    > +
    > +_fail:
    > + debugfs_remove_recursive(esp_debugfs_root);
    > + esp_debugfs_root = NULL;
    > + printk("%s failed, debugfs root removed; dir name: %s\n", __func__,
    > + name);
    > + return NULL;
    > +}
    > +
    > +int esp_debugfs_init(void)
    > +{
    > + esp_debugfs_root = debugfs_create_dir("esp_debug", NULL);
    > +
    > + if (IS_ERR_OR_NULL(esp_debugfs_root))
    > + return -ENOENT;
    > +
    > + return 0;
    > +}
    > +
    > +void esp_debugfs_exit(void)
    > +{
    > + debugfs_remove_recursive(esp_debugfs_root);
    > +}
    > +
    > +#else
    > +
    > +inline struct dentry *esp_dump_var(const char *name, struct dentry *parent,
    > + void *value, enum esp_type type)
    > +{
    > + return NULL;
    > +}
    > +
    > +inline struct dentry *esp_dump_array(const char *name, struct dentry *parent,
    > + struct debugfs_blob_wrapper *blob)
    > +{
    > + return NULL;
    > +}
    > +
    > +inline struct dentry *esp_dump(const char *name, struct dentry *parent,
    > + void *data, int size)
    > +{
    > + return NULL;
    > +}
    > +
    > +struct dentry *esp_debugfs_add_sub_dir(const char *name)
    > +{
    > + return NULL;
    > +}
    > +
    > +inline int esp_debugfs_init(void)
    > +{
    > + return -EPERM;
    > +}
    > +
    > +inline void esp_debugfs_exit(void)
    > +{
    > +}
    > +
    > +#endif
    > +
    > +/* FIXME: What's the actual usecase? */
    > +void show_buf(u8 *buf, u32 len)
    > +{
    > + int i = 0, j;
    > +
    > + printk(KERN_INFO "\n++++++++++++++++show rbuf+++++++++++++++\n");
    > + for (i = 0; i < (len / 16); i++) {
    > + j = i * 16;
    > + printk(KERN_INFO
    > + "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
    > + buf[j], buf[j + 1], buf[j + 2], buf[j + 3],
    > + buf[j + 4], buf[j + 5], buf[j + 6], buf[j + 7],
    > + buf[j + 8], buf[j + 9], buf[j + 10], buf[j + 11],
    > + buf[j + 12], buf[j + 13], buf[j + 14], buf[j + 15]);
    > + }
    > + printk(KERN_INFO "\n++++++++++++++++++++++++++++++++++++++++\n");
    > +}
    > diff --git a/drivers/staging/esp8089/esp_debug.h b/drivers/staging/esp8089/esp_debug.h
    > new file mode 100644
    > index 000000000000..eb9bddfe9842
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_debug.h
    > @@ -0,0 +1,69 @@
    > +/*
    > + * Copyright (c) 2011 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef _DEBUG_H_
    > +
    > +#ifdef ASSERT_PANIC
    > +#define ESSERT(v) BUG_ON(!(v))
    > +#else
    > +#define ESSERT(v) if(!(v)) printk("ESSERT:%s %d\n", __FILE__, __LINE__)
    > +#endif
    > +
    > +#include <linux/slab.h>
    > +#include <linux/debugfs.h>
    > +#include <linux/uaccess.h>
    > +
    > +enum esp_type {
    > + ESP_BOOL,
    > + ESP_U8,
    > + ESP_U16,
    > + ESP_U32,
    > + ESP_U64
    > +};
    > +
    > +struct dentry *esp_dump_var(const char *name, struct dentry *parent,
    > + void *value, enum esp_type type);
    > +
    > +struct dentry *esp_dump_array(const char *name, struct dentry *parent,
    > + struct debugfs_blob_wrapper *blob);
    > +
    > +struct dentry *esp_dump(const char *name, struct dentry *parent, void *data,
    > + int size);
    > +
    > +struct dentry *esp_debugfs_add_sub_dir(const char *name);
    > +
    > +int esp_debugfs_init(void);
    > +
    > +void esp_debugfs_exit(void);
    > +
    > +enum {
    > + ESP_DBG_ERROR = BIT(0),
    > + ESP_DBG_TRACE = BIT(1),
    > + ESP_DBG_LOG = BIT(2),
    > + ESP_DBG = BIT(3),
    > + ESP_SHOW = BIT(4),
    > + ESP_DBG_TXAMPDU = BIT(5),
    > + ESP_DBG_OP = BIT(6),
    > + ESP_DBG_PS = BIT(7),
    > + ESP_ATE = BIT(8),
    > + ESP_DBG_ALL = GENMASK(31, 0)
    > +};
    > +
    > +extern unsigned int esp_msg_level;
    > +
    > +#define esp_dbg(mask, fmt, args...) do { \
    > + if (esp_msg_level & mask) \
    > + printk(fmt, ##args); \
    > +} while (0)
    > +
    > +void show_buf(u8 *buf, u32 len);
    > +
    > +#endif /* _DEBUG_H_ */
    > diff --git a/drivers/staging/esp8089/esp_file.c b/drivers/staging/esp8089/esp_file.c
    > new file mode 100644
    > index 000000000000..7c7ef0d83693
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_file.c
    > @@ -0,0 +1,221 @@
    > +/*
    > + * Copyright (c) 2010 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#include <linux/fs.h>
    > +#include <linux/vmalloc.h>
    > +#include <linux/kernel.h>
    > +#include <linux/moduleparam.h>
    > +#include <linux/firmware.h>
    > +#include <linux/netdevice.h>
    > +#include <linux/aio.h>
    > +#include <linux/property.h>
    > +
    > +#include "esp_file.h"
    > +#include "esp_debug.h"
    > +#include "esp_sif.h"
    > +
    > +/* TODO use proper module param for each value instead of a big one */
    > +static char *modparam_init_data_conf;
    > +module_param_named(config, modparam_init_data_conf, charp, 0444);
    > +MODULE_PARM_DESC(config, "Firmware init config string (format: key=value;)");
    > +
    > +struct esp_init_table_elem esp_init_table[MAX_ATTR_NUM] = {
    > + /* Crystal type:
    > + * 0: 40MHz (default)
    > + * 1: 26MHz (ESP8266 ESP-12F)
    > + */
    > + {"crystal_26M_en", 48, 0},
    > + /* Output crystal clock to pin:
    > + * 0: None
    > + * 1: GPIO1
    > + * 2: URXD0
    > + */
    > + {"test_xtal", 49, 0},
    > + /* Host SDIO mode:
    > + * 0: Auto by pin strapping
    > + * 1: SDIO data output on negative edges (SDIO v1.1)
    > + * 2: SDIO data output on positive edges (SDIO v2.0)
    > + */
    > + {"sdio_configure", 50, 2},
    > + /* WiFi/Bluetooth co-existence with BK3515A BT chip
    > + * 0: None
    > + * 1: GPIO0->WLAN_ACTIVE, MTMS->BT_ACTIVE, MTDI->BT_PRIORITY,
    > + * U0TXD->ANT_SEL_BT, U0RXD->ANT_SEL_WIFI
    > + */
    > + {"bt_configure", 51, 0},
    > + /* Antenna selection:
    > + * 0: Antenna is for WiFi
    > + * 1: Antenna is for Bluetooth
    > + */
    > + {"bt_protocol", 52, 0},
    > + /* Dual antenna configuration mode:
    > + * 0: None
    > + * 1: U0RXD + XPD_DCDC
    > + * 2: U0RXD + GPIO0
    > + * 3: U0RXD + U0TXD
    > + */
    > + {"dual_ant_configure", 53, 0},
    > + /* Firmware debugging output pin:
    > + * 0: None
    > + * 1: UART TX on GPIO2
    > + * 2: UART TX on U0TXD
    > + */
    > + {"test_uart_configure", 54, 2},
    > + /* Whether to share crystal clock with BT (in sleep mode):
    > + * 0: no
    > + * 1: always on
    > + * 2: automatically on according to XPD_DCDC
    > + */
    > + {"share_xtal", 55, 0},
    > + /* Allow chip to be woken up during sleep on pin:
    > + * 0: None
    > + * 1: XPD_DCDC
    > + * 2: GPIO0
    > + * 3: Both XPD_DCDC and GPIO0
    > + */
    > + {"gpio_wake", 56, 0},
    > + {"no_auto_sleep", 57, 0},
    > + {"speed_suspend", 58, 0},
    > + {"attr11", -1, -1},
    > + {"attr12", -1, -1},
    > + {"attr13", -1, -1},
    > + {"attr14", -1, -1},
    > + {"attr15", -1, -1},
    > + //attr that is not send to target
    > + /* Allow chip to be reset by GPIO pin:
    > + * 0: no
    > + * 1: yes
    > + */
    > + {"ext_rst", -1, 0},
    > + {"wakeup_gpio", -1, 12},
    > + {"ate_test", -1, 0},
    > + {"attr19", -1, -1},
    > + {"attr20", -1, -1},
    > + {"attr21", -1, -1},
    > + {"attr22", -1, -1},
    > + {"attr23", -1, -1},
    > +};
    > +
    > +/* update init config table */
    > +static int set_init_config_attr(const char *attr, int attr_len, short value)
    > +{
    > + int i;
    > +
    > + for (i = 0; i < MAX_ATTR_NUM; i++)
    > + if (!memcmp(esp_init_table[i].attr, attr, attr_len)) {
    > + if (value < 0 || value > 255) {
    > + printk("%s: attribute value for %s is out of range",
    > + __func__, esp_init_table[i].attr);
    > + return -1;
    > + }
    > +
    > + esp_init_table[i].value = value;
    > + return 0;
    > + }
    > +
    > + return -1;
    > +}
    > +
    > +static int update_init_config_attr(const char *attr, int attr_len,
    > + const char *val, int val_len)
    > +{
    > + char digits[4];
    > + short value;
    > + int i;
    > +
    > + for (i = 0; i < sizeof(digits) - 1 && i < val_len; i++)
    > + digits[i] = val[i];

    I don't think we really need to memcpy() val to digits[].

    > +
    > + digits[i] = 0;
    > +
    > + if (kstrtou16(digits, 10, &value) < 0) {
    > + printk("%s: invalid attribute value: %s", __func__, digits);
    > + return -1;

    propogate the error code.

    > + }
    > +
    > + return set_init_config_attr(attr, attr_len, value);
    > +}
    > +
    > +/* export config table settings to SDIO driver */
    > +static void record_init_config(void)
    > +{
    > + int i;
    > +
    > + for (i = 0; i < MAX_ATTR_NUM; i++) {
    > + if (esp_init_table[i].value < 0)
    > + continue;
    > +
    > + if (!strcmp(esp_init_table[i].attr, "share_xtal"))
    > + sif_record_bt_config(esp_init_table[i].value);
    > + else if (!strcmp(esp_init_table[i].attr, "ext_rst"))
    > + sif_record_rst_config(esp_init_table[i].value);
    > + else if (!strcmp(esp_init_table[i].attr, "wakeup_gpio"))
    > + sif_record_wakeup_gpio_config(esp_init_table[i].value);
    > + else if (!strcmp(esp_init_table[i].attr, "ate_test"))
    > + sif_record_ate_config(esp_init_table[i].value);
    > + }
    > +}
    > +
    > +int request_init_conf(struct device *dev)
    > +{
    > + char *attr, *str, *p;
    > + int attr_len, str_len;
    > + int ret = 0;
    > + u32 val;
    > +
    > + /* Check for any parameters passed through devicetree (or acpi) */
    > + if (!device_property_read_u32(dev, "esp,crystal-26M-en", &val))
    > + set_init_config_attr("crystal_26M_en", strlen("crystal_26M_en"),
    > + val);
    > +
    > + /* parse optional parameter in the form of key1=value,key2=value,.. */
    > + attr = NULL;
    > + attr_len = 0;
    > + str_len = 0;
    > + for (p = str = modparam_init_data_conf; p && *p; p++) {
    > + if (*p == '=') {
    > + attr = str;
    > + attr_len = str_len;
    > +
    > + str = p + 1;
    > + str_len = 0;
    > + } else if (*p == ',' || *p == ';') {
    > + if (attr_len)
    > + ret |= update_init_config_attr(attr, attr_len,
    > + str, str_len);
    > +
    > + str = p + 1;
    > + attr_len = 0;
    > + str_len = 0;
    > + } else {
    > + str_len++;
    > + }
    > + }
    > +
    > + if (attr_len && str != attr)
    > + ret |= update_init_config_attr(attr, attr_len, str, str_len);
    > +
    > + record_init_config();
    > +
    > + return ret;
    > +}
    > +
    > +void fix_init_data(u8 *init_data_buf, int buf_size)
    > +{
    > + int i;
    > +
    > + for (i = 0; i < MAX_FIX_ATTR_NUM; i++) {
    > + if (esp_init_table[i].offset > -1 &&
    > + esp_init_table[i].offset < buf_size &&
    > + esp_init_table[i].value > -1)
    > + *(u8 *)(init_data_buf + esp_init_table[i].offset) = esp_init_table[i].value;
    > + }
    > +}
    > diff --git a/drivers/staging/esp8089/esp_file.h b/drivers/staging/esp8089/esp_file.h
    > new file mode 100644
    > index 000000000000..ba9946d64c32
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_file.h
    > @@ -0,0 +1,30 @@
    > +/*
    > + * Copyright (c) 2010 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef _ESP_FILE_H_
    > +#define _ESP_FILE_H_
    > +
    > +#include <linux/firmware.h>
    > +
    > +#define CONF_ATTR_LEN 24
    > +#define MAX_ATTR_NUM 24
    > +#define MAX_FIX_ATTR_NUM 16
    > +
    > +struct esp_init_table_elem {
    > + char attr[CONF_ATTR_LEN];
    > + int offset;
    > + short value;
    > +};
    > +
    > +int request_init_conf(struct device *dev);
    > +void fix_init_data(u8 *init_data_buf, int buf_size);
    > +
    > +#endif /* _ESP_FILE_H_ */
    > diff --git a/drivers/staging/esp8089/esp_init_data.h b/drivers/staging/esp8089/esp_init_data.h
    > new file mode 100644
    > index 000000000000..2494c02a10be
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_init_data.h
    > @@ -0,0 +1,17 @@
    > +/*
    > + * Copyright (c) 2009 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +static char esp_init_data[] = { 0x5, 0x0, 4, 2, 5, 5, 5, 2, 5, 0, 4, 5, 5, 4, 5, 5, 4, -2, -3, -1,
    > + -16, -16, -16, -32, -32, -32, 204, 1, 0xff, 0xff, 0, 0, 0, 0, 82, 78, 74, 68, 64, 56, 0,
    > + 0, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 10, 0x0, 0x0,
    > + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    > + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    > + 0 };
    > diff --git a/drivers/staging/esp8089/esp_io.c b/drivers/staging/esp8089/esp_io.c
    > new file mode 100644
    > index 000000000000..756bd6260b24
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_io.c
    > @@ -0,0 +1,294 @@
    > +/*
    > + * Copyright (c) 2009 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#include <linux/mmc/sdio_func.h>
    > +#include "esp_sif.h"
    > +#include "slc_host_register.h"
    > +#include "esp_debug.h"
    > +
    > +int esp_common_read(struct esp_pub *epub, u8 *buf, u32 len, int sync,
    > + bool noround)
    > +{
    > + if (sync)
    > + return sif_lldesc_read_sync(epub, buf, len);
    > +
    > + return sif_lldesc_read_raw(epub, buf, len, noround);
    > +}
    > +
    > +int esp_common_write(struct esp_pub *epub, u8 *buf, u32 len, int sync)
    > +{
    > + if (sync)
    > + return sif_lldesc_write_sync(epub, buf, len);
    > +
    > + return sif_lldesc_write_raw(epub, buf, len);
    > +}
    > +
    > +int esp_common_read_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, u32 len,
    > + int sync)
    > +{
    > + if (sync)
    > + return sif_io_sync(epub, addr, buf, len, SIF_FROM_DEVICE |
    > + SIF_SYNC | SIF_BYTE_BASIS | SIF_INC_ADDR);
    > +
    > + return sif_io_raw(epub, addr, buf, len, SIF_FROM_DEVICE |
    > + SIF_BYTE_BASIS | SIF_INC_ADDR);
    > +}
    > +
    > +int esp_common_write_with_addr(struct esp_pub *epub, u32 addr, u8 *buf,
    > + u32 len, int sync)
    > +{
    > + if (sync)
    > + return sif_io_sync(epub, addr, buf, len, SIF_TO_DEVICE |
    > + SIF_SYNC | SIF_BYTE_BASIS | SIF_INC_ADDR);
    > +
    > + return sif_io_raw(epub, addr, buf, len, SIF_TO_DEVICE | SIF_BYTE_BASIS |
    > + SIF_INC_ADDR);
    > +}
    > +
    > +int esp_common_readbyte_with_addr(struct esp_pub *epub, u32 addr, u8 *buf,
    > + int sync)
    > +{
    > + int res;
    > +
    > + if (sync)
    > + sif_lock_bus(epub);
    > +
    > + *buf = sdio_io_readb(epub, addr, &res);
    > +
    > + if (sync)
    > + sif_unlock_bus(epub);
    > +
    > + return res;
    > +}
    > +
    > +int esp_common_writebyte_with_addr(struct esp_pub *epub, u32 addr, u8 buf,
    > + int sync)
    > +{
    > + int res;
    > +
    > + if (sync)
    > + sif_lock_bus(epub);
    > +
    > + sdio_io_writeb(epub, buf, addr, &res);
    > +
    > + if (sync)
    > + sif_unlock_bus(epub);
    > +
    > + return res;
    > +}
    > +
    > +enum _SDIO_INTR_MODE {
    > + SDIO_INTR_IB = 0,
    > + SDIO_INTR_OOB_TOGGLE,
    > + SDIO_INTR_OOB_HIGH_LEVEL,
    > + SDIO_INTR_OOB_LOW_LEVEL,
    > +};
    > +
    > +#define GEN_GPIO_SEL(_gpio_num, _sel_func, _intr_mode, _offset) (((_offset) << 9) | ((_intr_mode) << 7) | ((_sel_func) << 4) | (_gpio_num))
    > +//bit[3:0] = gpio num, 2
    > +//bit[6:4] = gpio sel func, 0
    > +//bit[8:7] = gpio intr mode, SDIO_INTR_OOB_TOGGLE
    > +//bit[15:9] = register offset, 0x38
    > +
    > +u16 gpio_sel_sets[17] = {
    > + GEN_GPIO_SEL(0, 0, SDIO_INTR_OOB_TOGGLE, 0x34), //GPIO0
    > + GEN_GPIO_SEL(1, 3, SDIO_INTR_OOB_TOGGLE, 0x18), //U0TXD
    > + GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_TOGGLE, 0x38), //GPIO2
    > + GEN_GPIO_SEL(3, 3, SDIO_INTR_OOB_TOGGLE, 0x14), //U0RXD
    > + GEN_GPIO_SEL(4, 0, SDIO_INTR_OOB_TOGGLE, 0x3C), //GPIO4
    > + GEN_GPIO_SEL(5, 0, SDIO_INTR_OOB_TOGGLE, 0x40), //GPIO5
    > + GEN_GPIO_SEL(6, 3, SDIO_INTR_OOB_TOGGLE, 0x1C), //SD_CLK
    > + GEN_GPIO_SEL(7, 3, SDIO_INTR_OOB_TOGGLE, 0x20), //SD_DATA0
    > + GEN_GPIO_SEL(8, 3, SDIO_INTR_OOB_TOGGLE, 0x24), //SD_DATA1
    > + GEN_GPIO_SEL(9, 3, SDIO_INTR_OOB_TOGGLE, 0x28), //SD_DATA2
    > + GEN_GPIO_SEL(10, 3, SDIO_INTR_OOB_TOGGLE, 0x2C), //SD_DATA3
    > + GEN_GPIO_SEL(11, 3, SDIO_INTR_OOB_TOGGLE, 0x30), //SD_CMD
    > + GEN_GPIO_SEL(12, 3, SDIO_INTR_OOB_TOGGLE, 0x04), //MTDI
    > + GEN_GPIO_SEL(13, 3, SDIO_INTR_OOB_TOGGLE, 0x08), //MTCK
    > + GEN_GPIO_SEL(14, 3, SDIO_INTR_OOB_TOGGLE, 0x0C), //MTMS
    > + GEN_GPIO_SEL(15, 3, SDIO_INTR_OOB_TOGGLE, 0x10), //MTDO
    > + //pls do not change sel before, if you want to change intr mode,change the one blow
    > + //GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_TOGGLE, 0x38)
    > + GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_LOW_LEVEL, 0x38)
    > +};
    > +
    > +int sif_interrupt_target(struct esp_pub *epub, u8 index)
    > +{
    > + u8 low_byte = BIT(index);
    > + return esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W4 + 2,
    > + low_byte, ESP_SIF_NOSYNC);
    > +}
    > +
    > +void check_target_id(struct esp_pub *epub)
    > +{
    > + u32 date;
    > + int i;
    > + u16 gpio_sel;
    > + u8 byte2 = 0, byte3 = 0;
    > +
    > + if (!epub || !epub->sif)
    > + return;
    > +
    > + sif_lock_bus(epub);
    > +
    > + for (i = 0; i < 4; i++) {
    > + esp_common_readbyte_with_addr(epub, SLC_HOST_DATE + i,
    > + (u8 *)&date + i, ESP_SIF_NOSYNC);
    > + esp_common_readbyte_with_addr(epub, SLC_HOST_ID + i,
    > + (u8 *)&epub->sif->target_id + i,
    > + ESP_SIF_NOSYNC);
    > + }
    > +
    > + sif_unlock_bus(epub);
    > +
    > + switch (epub->sif->target_id) {
    > + case 0x100:
    > + epub->sif->slc_window_end_addr = 0x20000;
    > + break;
    > + case 0x600:
    > + epub->sif->slc_window_end_addr = 0x20000 - 0x800;
    > +
    > + if (sif_get_bt_config() == 1 && sif_get_rst_config() != 1) {
    > + u8 gpio_num = sif_get_wakeup_gpio_config();
    > + gpio_sel = gpio_sel_sets[gpio_num];
    > + byte2 = gpio_sel;
    > + byte3 = gpio_sel >> 8;
    > + }
    > +
    > + sif_lock_bus(epub);
    > + esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1, 0,
    > + ESP_SIF_NOSYNC);
    > + esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1 + 1, 0,
    > + ESP_SIF_NOSYNC);
    > + esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1 + 2,
    > + byte2, ESP_SIF_NOSYNC);
    > + esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1 + 3,
    > + byte3, ESP_SIF_NOSYNC);
    > + sif_unlock_bus(epub);
    > + break;
    > + default:
    > + epub->sif->slc_window_end_addr = 0x20000;
    > + break;
    > + }
    > +}
    > +
    > +u32 sif_get_blksz(struct esp_pub *epub)
    > +{
    > + if (!epub || !epub->sif)
    > + return 512;
    > +
    > + return epub->sif->slc_blk_sz;
    > +}
    > +
    > +void sif_dsr(struct sdio_func *func)
    > +{
    > + struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func);
    > + struct slc_host_regs *regs = &sctrl->slc_regs;
    > + int ret;
    > +
    > + sdio_release_host(sctrl->func);
    > +
    > + sif_lock_bus(sctrl->epub);
    > + memset(regs, 0, sizeof(struct slc_host_regs));
    > +
    > + ret = esp_common_read_with_addr(sctrl->epub, REG_SLC_HOST_BASE + 8,
    > + (u8 *)regs, sizeof(*regs),
    > + ESP_SIF_NOSYNC);
    > +
    > + if (regs->intr_raw & SLC_HOST_RX_ST && !ret)
    > + esp_dsr(sctrl->epub);
    > + else
    > + sif_unlock_bus(sctrl->epub);
    > +
    > + /* FIXME: missing unlock_bus? */

    I think the bus mostly gets unlocked in esp_dsr() but it's not clear
    how that happens on the success path. But that's the common path so
    it must happen. I don't like that we mix sif_lock_bus() and
    sdio_claim_host(). I guess I would prefer that we could get rid of
    sif_lock_bus() because we should be locking instead of saying "We have
    too many NULL pointers so let's forget about locking for now."

    > + sdio_claim_host(func);
    > + atomic_set(&sctrl->irq_handling, 0);
    > +}
    > +
    > +struct slc_host_regs *sif_get_regs(struct esp_pub *epub)
    > +{
    > + if (!epub || !epub->sif)
    > + return NULL;
    > +
    > + return &epub->sif->slc_regs;
    > +}
    > +
    > +void sif_disable_target_interrupt(struct esp_pub *epub)
    > +{
    > + if (!epub || !epub->sif || !epub->sif->func)
    > + return;
    > +
    > + sif_lock_bus(epub);
    > +#ifdef HOST_RESET_BUG
    > + mdelay(10);
    > +#endif
    > + memset(epub->sif->dma_buffer, 0, sizeof(u32));
    > + esp_common_write_with_addr(epub, SLC_HOST_INT_ENA,
    > + epub->sif->dma_buffer, sizeof(u32),
    > + ESP_SIF_NOSYNC);
    > +#ifdef HOST_RESET_BUG
    > + mdelay(10);
    > +#endif
    > +
    > + sif_unlock_bus(epub);
    > +
    > + mdelay(1);
    > +
    > + sif_lock_bus(epub);
    > + sif_interrupt_target(epub, 7);
    > + sif_unlock_bus(epub);
    > +}
    > +
    > +/* FIXME: MEH */
    > +
    > +static int bt_config;
    > +void sif_record_bt_config(int value)
    > +{
    > + bt_config = value;
    > +}
    > +
    > +int sif_get_bt_config(void)
    > +{
    > + return bt_config;
    > +}
    > +
    > +static int rst_config;
    > +void sif_record_rst_config(int value)
    > +{
    > + rst_config = value;
    > +}
    > +
    > +int sif_get_rst_config(void)
    > +{
    > + return rst_config;
    > +}
    > +
    > +static int ate_test;
    > +void sif_record_ate_config(int value)
    > +{
    > + ate_test = value;
    > +}
    > +
    > +int sif_get_ate_config(void)
    > +{
    > + return ate_test;
    > +}
    > +
    > +static int wakeup_gpio = 12;
    > +void sif_record_wakeup_gpio_config(int value)
    > +{
    > + wakeup_gpio = value;
    > +}
    > +
    > +int sif_get_wakeup_gpio_config(void)
    > +{
    > + return wakeup_gpio;
    > +}
    > diff --git a/drivers/staging/esp8089/esp_mac80211.c b/drivers/staging/esp8089/esp_mac80211.c
    > new file mode 100644
    > index 000000000000..fd5049fc1f6b
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_mac80211.c
    > @@ -0,0 +1,1496 @@
    > +/*
    > + * Copyright (c) 2011 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#include <linux/etherdevice.h>
    > +#include <linux/workqueue.h>
    > +#include <linux/nl80211.h>
    > +#include <linux/ieee80211.h>
    > +#include <linux/slab.h>
    > +#include <net/cfg80211.h>
    > +#include <net/mac80211.h>
    > +#include <net/regulatory.h>
    > +#include "esp_pub.h"
    > +#include "esp_sip.h"
    > +#include "esp_ctrl.h"
    > +#include "esp_sif.h"
    > +#include "esp_debug.h"
    > +#include "esp_wl.h"
    > +#include "esp_utils.h"
    > +
    > +static u8 esp_mac_addr[ETH_ALEN * 2];
    > +static u8 getaddr_index(u8 *addr, struct esp_pub *epub);
    > +
    > +/*Handler that 802.11 module calls for each transmitted frame.
    > +skb contains the buffer starting from the IEEE 802.11 header.
    > +The low-level driver should send the frame out based on
    > +configuration in the TX control data. This handler should,
    > +preferably, never fail and stop queues appropriately.
    > +Must be atomic.*/
    > +static void esp_op_tx(struct ieee80211_hw *hw,
    > + struct ieee80211_tx_control *control, struct sk_buff *skb)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > +
    > + sip_tx_data_pkt_enqueue(epub, skb);
    > + if (epub)
    > + ieee80211_queue_work(hw, &epub->tx_work);
    > +}
    > +
    > +/*
    > + Called before the first netdevice attached to the hardware
    > + 2934 * is enabled. This should turn on the hardware and must turn on
    > + 2935 * frame reception (for possibly enabled monitor interfaces.)
    > + 2936 * Returns negative error codes, these may be seen in userspace,
    > + 2937 * or zero.
    > + 2938 * When the device is started it should not have a MAC address
    > + 2939 * to avoid acknowledging frames before a non-monitor device
    > + 2940 * is added.
    > + 2941 * Must be implemented and can sleep.
    > +*/
    > +static int esp_op_start(struct ieee80211_hw *hw)
    > +{
    > + struct esp_pub *epub;
    > +
    > + if (!hw || !hw->priv) {
    > + return -EINVAL;
    > + }
    > +
    > + epub = (struct esp_pub *)hw->priv;
    > +
    > + /*add rfkill poll function */
    > +
    > + atomic_set(&epub->wl.off, 0);
    > + wiphy_rfkill_start_polling(hw->wiphy);
    > +
    > + return 0;
    > +}
    > +
    > +/*
    > +Called after last netdevice attached to the hardware
    > +2944 * is disabled. This should turn off the hardware (at least
    > +2945 * it must turn off frame reception.)
    > +2946 * May be called right after add_interface if that rejects
    > +2947 * an interface. If you added any work onto the mac80211 workqueue
    > +2948 * you should ensure to cancel it on this callback.
    > +2949 * Must be implemented and can sleep.
    > +*/
    > +static void esp_op_stop(struct ieee80211_hw *hw)
    > +{
    > + struct esp_pub *epub;
    > +
    > + if (!hw || !hw->priv) {
    > + return;
    > + }
    > +
    > + epub = (struct esp_pub *)hw->priv;
    > + atomic_set(&epub->wl.off, 1);
    > +
    > +#ifdef HOST_RESET_BUG
    > + mdelay(200);
    > +#endif
    > +
    > + if (epub->wl.scan_req) {
    > + hw_scan_done(epub, true);
    > + epub->wl.scan_req = NULL;
    > + //msleep(2);
    > + }
    > +
    > + /* FIXME: does this 'turn off frame reception'? */
    > + wiphy_rfkill_stop_polling(hw->wiphy);
    > + /* FIXME: flush queues? */
    > +}
    > +
    > +static int esp_set_svif_mode(struct sip_cmd_setvif *svif,
    > + enum nl80211_iftype type, bool p2p)
    > +{
    > + switch (type) {
    > + case NL80211_IFTYPE_STATION:
    > + svif->op_mode = 0;
    > + svif->is_p2p = p2p;
    > + break;
    > +
    > + case NL80211_IFTYPE_AP:
    > + svif->op_mode = 1;
    > + svif->is_p2p = p2p;
    > + break;
    > +
    > + case NL80211_IFTYPE_P2P_CLIENT:
    > + svif->op_mode = 0;
    > + svif->is_p2p = 1;
    > + break;
    > +
    > + case NL80211_IFTYPE_P2P_GO:
    > + svif->op_mode = 1;
    > + svif->is_p2p = 1;
    > + break;
    > +
    > + default:
    > + return -EOPNOTSUPP;
    > + }
    > +
    > + return 0;
    > +}
    > +
    > +/*
    > +Called when a netdevice attached to the hardware is
    > +2973 * enabled. Because it is not called for monitor mode devices, @start
    > +2974 * and @stop must be implemented.
    > +2975 * The driver should perform any initialization it needs before
    > +2976 * the device can be enabled. The initial configuration for the
    > +2977 * interface is given in the conf parameter.
    > +2978 * The callback may refuse to add an interface by returning a
    > +2979 * negative error code (which will be seen in userspace.)
    > +2980 * Must be implemented and can sleep.
    > + */
    > +static int esp_op_add_interface(struct ieee80211_hw *hw,
    > + struct ieee80211_vif *vif)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + struct esp_vif *evif = (struct esp_vif *)vif->drv_priv;
    > + struct sip_cmd_setvif svif;
    > + int ret;
    > +
    > + memcpy(svif.mac, vif->addr, ETH_ALEN);
    > + svif.index = getaddr_index(vif->addr, epub);
    > + evif->index = svif.index;
    > + evif->epub = epub;
    > + /* FIXME: why a need for evif? */
    > + epub->vif = vif;
    > + svif.set = 1;
    > +
    > + if (svif.index == ESP_PUB_MAX_VIF) {

    Move this error handling next to the getaddr_index() call.

    > + dev_err(epub->dev, "support for MAX %d interfaces\n",
    > + ESP_PUB_MAX_VIF);
    > + return -EOPNOTSUPP;
    > + }
    > +
    > + if (BIT(svif.index) & epub->vif_slot) {
    > + dev_err(epub->dev, "interface %d already used\n", svif.index);
    > + return -EOPNOTSUPP;
    > + }
    > +
    > + epub->vif_slot |= BIT(svif.index);
    > +
    > + ret = esp_set_svif_mode(&svif, vif->type, false);
    > + if (ret < 0) {
    > + dev_err(epub->dev, "no support for interface type %d\n",
    > + vif->type);
    > + return ret;
    > + }
    > +
    > + sip_cmd(epub, SIP_CMD_SETVIF, (u8 *)&svif, sizeof(svif));
    > +
    > + return 0;
    > +}
    > +
    > +/*
    > +Called when a netdevice changes type. This callback
    > +2983 * is optional, but only if it is supported can interface types be
    > +2984 * switched while the interface is UP. The callback may sleep.
    > +2985 * Note that while an interface is being switched, it will not be
    > +2986 * found by the interface iteration callbacks.
    > + */
    > +static int esp_op_change_interface(struct ieee80211_hw *hw,
    > + struct ieee80211_vif *vif,
    > + enum nl80211_iftype new_type, bool p2p)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + struct esp_vif *evif = (struct esp_vif *)vif->drv_priv;
    > + struct sip_cmd_setvif svif;
    > + int ret;
    > +
    > + memcpy(svif.mac, vif->addr, ETH_ALEN);
    > + svif.index = evif->index;
    > + svif.set = 2;
    > +
    > + ret = esp_set_svif_mode(&svif, new_type, p2p);
    > + if (ret < 0)
    > + return ret;
    > +
    > + sip_cmd(epub, SIP_CMD_SETVIF, (u8 *)&svif, sizeof(svif));
    > +
    > + return 0;
    > +}
    > +
    > +/*
    > + Notifies a driver that an interface is going down.
    > + 2989 * The @stop callback is called after this if it is the last interface
    > + 2990 * and no monitor interfaces are present.
    > + 2991 * When all interfaces are removed, the MAC address in the hardware
    > + 2992 * must be cleared so the device no longer acknowledges packets,
    > + 2993 * the mac_addr member of the conf structure is, however, set to the
    > + 2994 * MAC address of the device going away.
    > + 2995 * Hence, this callback must be implemented. It can sleep.
    > + */
    > +static void esp_op_remove_interface(struct ieee80211_hw *hw,
    > + struct ieee80211_vif *vif)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + struct esp_vif *evif = (struct esp_vif *)vif->drv_priv;
    > + struct sip_cmd_setvif svif = {0};
    > +
    > + svif.index = evif->index;
    > + epub->vif_slot &= ~BIT(svif.index);
    > +
    > + if (evif->ap_up) {
    > + evif->beacon_interval = 0;
    > + del_timer_sync(&evif->beacon_timer);
    > + evif->ap_up = false;
    > + }
    > +
    > + epub->vif = NULL;
    > + evif->epub = NULL;
    > +
    > + sip_cmd(epub, SIP_CMD_SETVIF, (u8 *)&svif, sizeof(svif));
    > + /* TODO: clean up tx/rx queue */
    > +}
    > +
    > +/* FIXME: WTF? */
    > +
    > +#define BEACON_TIM_SAVE_MAX 20
    > +u8 beacon_tim_saved[BEACON_TIM_SAVE_MAX];
    > +int beacon_tim_count;
    > +static void beacon_tim_init(void)
    > +{
    > + memset(beacon_tim_saved, 0, BEACON_TIM_SAVE_MAX);
    > + beacon_tim_count = 0;
    > +}
    > +
    > +static u8 beacon_tim_save(u8 this_tim)
    > +{
    > + u8 all_tim = 0;
    > + int i;
    > +
    > + beacon_tim_saved[beacon_tim_count] = this_tim;
    > +
    > + beacon_tim_count = (beacon_tim_count + 1) % BEACON_TIM_SAVE_MAX;
    > +
    > + for (i = 0; i < BEACON_TIM_SAVE_MAX; i++)
    > + all_tim |= beacon_tim_saved[i];
    > +
    > + return all_tim;
    > +}
    > +
    > +static bool beacon_tim_alter(struct sk_buff *beacon)
    > +{
    > + u8 *p, *tim_end;
    > + u8 tim_count;
    > + int len, remain_len;
    > + struct ieee80211_mgmt *mgmt;
    > +
    > + if (!beacon)
    > + return false;
    > +
    > + mgmt = (struct ieee80211_mgmt *)((u8 *)beacon->data);
    > +
    > + remain_len = beacon->len - ((u8 *)mgmt->u.beacon.variable -
    > + (u8 *)mgmt + 12);
    > + p = mgmt->u.beacon.variable;
    > +
    > + while (remain_len > 0) {
    > + len = *(++p);
    > +
    > + if (*p == WLAN_EID_TIM) { // tim field
    > + tim_end = p + len;
    > + tim_count = *(++p);
    > + p += 2;
    > + //multicast
    > + if (!tim_count)
    > + *p |= 0x1;
    > +
    > + if (!(*p & 0xfe) && tim_end >= p + 1) { // we only support 8 sta in this case
    > + p++;
    > + *p = beacon_tim_save(*p);
    > + }
    > +
    > + return tim_count == 0;
    > + }
    > +
    > + p += len + 1;
    > + remain_len -= 2 + len;
    > + }
    > +
    > + return false;
    > +}
    > +
    > +unsigned long init_jiffies;
    > +unsigned long cycle_beacon_count;
    > +static void drv_handle_beacon(unsigned long data)
    > +{
    > + struct ieee80211_vif *vif = (struct ieee80211_vif *)data;
    > + struct esp_vif *evif = (struct esp_vif *)vif->drv_priv;
    > + struct sk_buff *beacon;
    > + struct sk_buff *skb;
    > + bool tim_reach;
    > +
    > + if (!evif->epub)
    > + return;
    > +
    > + mdelay(2400 * (cycle_beacon_count % 25) % 10000 / 1000);
    > +
    > + beacon = ieee80211_beacon_get(evif->epub->hw, vif);
    > +
    > + tim_reach = beacon_tim_alter(beacon);
    > +
    > + if (beacon)
    > + sip_tx_data_pkt_enqueue(evif->epub, beacon);
    > +
    > + if (cycle_beacon_count++ == 100) {
    > + init_jiffies = jiffies;
    > + cycle_beacon_count -= 100;
    > + }
    > +
    > + mod_timer(&evif->beacon_timer, init_jiffies +
    > + msecs_to_jiffies(cycle_beacon_count *
    > + vif->bss_conf.beacon_int * 1024 / 1000));
    > + //FIXME:the packets must be sent at home channel
    > + //send buffer mcast frames
    > + if (tim_reach) {
    > + skb = ieee80211_get_buffered_bc(evif->epub->hw, vif);
    > + while (skb) {
    > + sip_tx_data_pkt_enqueue(evif->epub, skb);
    > + skb = ieee80211_get_buffered_bc(evif->epub->hw, vif);
    > + }
    > + }
    > +}
    > +
    > +static void init_beacon_timer(struct ieee80211_vif *vif)
    > +{
    > + struct esp_vif *evif = (struct esp_vif *)vif->drv_priv;
    > +
    > + beacon_tim_init();
    > + setup_timer(&evif->beacon_timer, drv_handle_beacon, (unsigned long)vif); //TBD, not init here...
    > + cycle_beacon_count = 1;
    > + init_jiffies = jiffies;
    > + evif->beacon_timer.expires = init_jiffies +
    > + msecs_to_jiffies(cycle_beacon_count * vif->bss_conf.beacon_int *
    > + 1024 / 1000);
    > + add_timer(&evif->beacon_timer);
    > +}
    > +
    > +/*
    > + Handler for configuration requests. IEEE 802.11 code calls this
    > + 2998 * function to change hardware configuration, e.g., channel.
    > + 2999 * This function should never fail but returns a negative error code
    > + 3000 * if it does. The callback can sleep.
    > + */
    > +static int esp_op_config(struct ieee80211_hw *hw, u32 changed)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > +
    > + if (changed & (IEEE80211_CONF_CHANGE_CHANNEL |
    > + IEEE80211_CONF_CHANGE_IDLE))
    > + sip_send_config(epub, &hw->conf);
    > +
    > + return 0;
    > +}
    > +
    > +/*
    > +Handler for configuration requests related to BSS
    > +3003 * parameters that may vary during BSS's lifespan, and may affect low
    > +3004 * level driver (e.g. assoc/disassoc status, erp parameters).
    > +3005 * This function should not be used if no BSS has been set, unless
    > +3006 * for association indication. The @changed parameter indicates which
    > +3007 * of the bss parameters has changed when a call is made. The callback
    > +3008 * can sleep.
    > + */
    > +static void esp_op_bss_info_changed(struct ieee80211_hw *hw,
    > + struct ieee80211_vif *vif,
    > + struct ieee80211_bss_conf *info,
    > + u32 changed)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + struct esp_vif *evif = (struct esp_vif *)vif->drv_priv;
    > + u8 *bssid = (u8 *)info->bssid;
    > + bool assoc = info->assoc;
    > +
    > + // ieee80211_bss_conf(include/net/mac80211.h) is included in ieee80211_sub_if_data(net/mac80211/ieee80211_i.h) , does bssid=ieee80211_if_ap's ssid ?
    > +
    > + if (vif->type == NL80211_IFTYPE_STATION) {
    > + if (changed & BSS_CHANGED_BSSID ||
    > + ((changed & BSS_CHANGED_ASSOC) && assoc)) {
    > + evif->beacon_interval = info->aid;
    > + memcpy(epub->wl.bssid, bssid, ETH_ALEN);
    > + sip_send_bss_info_update(epub, evif, bssid, assoc);
    > + } else if ((changed & BSS_CHANGED_ASSOC) && !assoc) {
    > + evif->beacon_interval = 0;
    > + memset(epub->wl.bssid, 0, ETH_ALEN);
    > + sip_send_bss_info_update(epub, evif, bssid, assoc);
    > + }
    > + } else if (vif->type == NL80211_IFTYPE_AP) {
    > + if (!(changed & BSS_CHANGED_BEACON_ENABLED) &&
    > + !(changed & BSS_CHANGED_BEACON_INT))
    > + return;
    > +
    > + if (info->enable_beacon && !evif->ap_up) {
    > + evif->beacon_interval = info->beacon_int;
    > + init_beacon_timer(vif);
    > + sip_send_bss_info_update(epub, evif, bssid, 2);
    > + evif->ap_up = true;
    > + } else if (!info->enable_beacon && evif->ap_up &&
    > + !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
    > + evif->beacon_interval = 0;
    > + del_timer_sync(&evif->beacon_timer);
    > + sip_send_bss_info_update(epub, evif, bssid, 2);
    > + evif->ap_up = false;
    > + }
    > + }
    > +}
    > +
    > +/*
    > + Configure the device's RX filter.
    > + 3015 * See the section "Frame filtering" for more information.
    > + 3016 * This callback must be implemented and can sleep.
    > + */
    > +static void esp_op_configure_filter(struct ieee80211_hw *hw,
    > + unsigned int changed_flags,
    > + unsigned int *total_flags, u64 multicast)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > +
    > + epub->rx_filter = 0;
    > +
    > + if (*total_flags & FIF_ALLMULTI)
    > + epub->rx_filter |= FIF_ALLMULTI;
    > +
    > + *total_flags = epub->rx_filter;
    > +}
    > +
    > +static bool is_cipher_suite_wep(u32 cipher)
    > +{
    > + return (cipher == WLAN_CIPHER_SUITE_WEP40) ||
    > + (cipher == WLAN_CIPHER_SUITE_WEP104);
    > +}
    > +
    > +/*
    > + See the section "Hardware crypto acceleration"
    > + 3029 * This callback is only called between add_interface and
    > + 3030 * remove_interface calls, i.e. while the given virtual interface
    > + 3031 * is enabled.
    > + 3032 * Returns a negative error code if the key can't be added.
    > + 3033 * The callback can sleep.
    > + */
    > +static int esp_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
    > + struct ieee80211_vif *vif, struct ieee80211_sta *sta,
    > + struct ieee80211_key_conf *key)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + struct esp_vif *evif = (struct esp_vif *)vif->drv_priv;
    > + struct esp_hw_idx_map *map;
    > + atomic_t *cnt1, *cnt2;
    > + u8 i, ifidx = evif->index, isvalid, index;
    > + u8 *peer_addr;
    > + int ret, counter;
    > +
    > + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
    > +
    > + if (sta && memcmp(sta->addr, epub->wl.bssid, ETH_ALEN))
    > + peer_addr = sta->addr;
    > + else
    > + peer_addr = epub->wl.bssid;
    > +
    > + isvalid = !!(cmd == SET_KEY);
    > +
    > + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE ||
    > + is_cipher_suite_wep(key->cipher))
    > + map = epub->low_map[ifidx];
    > + else
    > + map = epub->hi_map;
    > +
    > + if (isvalid) {
    > + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE ||
    > + is_cipher_suite_wep(key->cipher))
    > + counter = 2;
    > + else
    > + counter = 19;
    > +
    > + for (i = 0; i < counter; i++) {
    > + if (map[i].flag)
    > + continue;
    > +
    > + map[i].flag = 1;
    > + memcpy(map[i].mac, peer_addr, ETH_ALEN);
    > + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE ||
    > + is_cipher_suite_wep(key->cipher))
    > + key->hw_key_idx = i + 6;
    > + else
    > + key->hw_key_idx = i + ifidx * 2 + 2;
    > + break;
    > + }
    > + } else {
    > + map[index].flag = 0;
    > + memset(map[index].mac, 0, ETH_ALEN);
    > +
    > + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE ||
    > + is_cipher_suite_wep(key->cipher))
    > + index = key->hw_key_idx - 6;
    > + else
    > + index = key->hw_key_idx - 2 - ifidx * 2;
    > + }
    > +
    > + if (key->hw_key_idx >= 6) {
    > + cnt1 = &epub->wl.ptk_cnt;
    > + cnt2 = &epub->wl.gtk_cnt;
    > + } else {
    > + cnt2 = &epub->wl.ptk_cnt;
    > + cnt1 = &epub->wl.gtk_cnt;
    > + }
    > +
    > + /*send sub_scan task to target */
    > + if (isvalid)
    > + atomic_inc(cnt1);
    > + else
    > + atomic_dec(cnt1);
    > +
    > + if (is_cipher_suite_wep(key->cipher)) {
    > + if (isvalid)
    > + atomic_inc(cnt2);
    > + else
    > + atomic_dec(cnt2);
    > + }
    > +
    > + ret = sip_send_setkey(epub, ifidx, peer_addr, key, isvalid);
    > + if (ret)
    > + return ret;
    > +
    > + if (key->cipher == WLAN_CIPHER_SUITE_TKIP && !ret)
    > + atomic_set(&epub->wl.tkip_key_set, 1);
    > +
    > + return 0;
    > +}
    > +
    > +void hw_scan_done(struct esp_pub *epub, bool aborted)
    > +{
    > + struct cfg80211_scan_info info = {
    > + .aborted = aborted,
    > + };
    > +
    > + cancel_delayed_work_sync(&epub->scan_timeout_work);
    > +
    > + ESSERT(epub->wl.scan_req);
    > +
    > + ieee80211_scan_completed(epub->hw, &info);
    > +
    > + if (test_and_clear_bit(ESP_WL_FLAG_STOP_TXQ, &epub->wl.flags))
    > + sip_trigger_txq_process(epub->sip);
    > +}
    > +
    > +static void hw_scan_timeout_report(struct work_struct *work)
    > +{
    > + struct esp_pub *epub = container_of(work, struct esp_pub,
    > + scan_timeout_work.work);
    > + bool aborted;
    > + struct cfg80211_scan_info info = {};
    > +
    > + if (test_and_clear_bit(ESP_WL_FLAG_STOP_TXQ, &epub->wl.flags))
    > + sip_trigger_txq_process(epub->sip);
    > + /*check if normally complete or aborted like timeout/hw error */
    > + aborted = (epub->wl.scan_req != 0);
    > +
    > + if (aborted)
    > + epub->wl.scan_req = NULL;
    > +
    > + info.aborted = aborted;
    > +
    > + ieee80211_scan_completed(epub->hw, &info);
    > +}
    > +
    > +/*
    > + Configuration of RTS threshold (if device needs it)
    > + 3106 * The callback can sleep.
    > + */
    > +static int esp_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
    > +{
    > + return 0;
    > +}
    > +
    > +static int esp_node_attach(struct ieee80211_hw *hw, u8 ifidx,
    > + struct ieee80211_sta *sta)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + struct esp_node *node;
    > + struct esp_tx_tid *tid;
    > + u8 tidno = 0;
    > + int i;
    > +
    > + spin_lock_bh(&epub->tx_ampdu_lock);
    > +
    > + /* ffz(x) needs at least one zero or results in undefined behaviour. */
    > + if ((~epub->enodes_map) == 0)
    > + return -EINVAL;
    > +
    > + i = ffz(epub->enodes_map);
    > +
    > + if (hweight32(epub->enodes_maps[ifidx]) >= ESP_PUB_MAX_STA ||
    > + i > ESP_PUB_MAX_STA) {
    > + i = -1;
    > + goto out;
    > + }
    > +
    > + epub->enodes_map |= BIT(i);
    > + epub->enodes_maps[ifidx] |= BIT(i);
    > + node = (struct esp_node *)sta->drv_priv;
    > + epub->enodes[i] = node;
    > + node->sta = sta;
    > + node->ifidx = ifidx;
    > + node->index = i;
    > +
    > + while (tidno < WME_NUM_TID) {
    > + tid = &node->tid[tidno];
    > + tid->ssn = 0;
    > + tid->cnt = 0;
    > + tid->state = ESP_TID_STATE_INIT;
    > + tidno++;
    > + }
    > +
    > +out:
    > + spin_unlock_bh(&epub->tx_ampdu_lock);
    > +
    > + return i;
    > +}
    > +
    > +static int esp_node_detach(struct ieee80211_hw *hw, u8 ifidx,
    > + struct ieee80211_sta *sta)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + u32 map;
    > + int i;
    > +
    > + spin_lock_bh(&epub->tx_ampdu_lock);
    > +
    > + map = epub->enodes_maps[ifidx];
    > +
    > + while (map) {
    > + i = ffs(map) - 1;
    > + if (epub->enodes[i]->sta == sta) {
    > + epub->enodes[i]->sta = NULL;
    > + epub->enodes[i] = NULL;
    > + epub->enodes_map &= ~BIT(i);
    > + epub->enodes_maps[ifidx] &= ~BIT(i);
    > +
    > + goto out;
    > + }
    > +
    > + map &= ~BIT(i);
    > + }
    > +
    > + i = -1;
    > +
    > +out:
    > + spin_unlock_bh(&epub->tx_ampdu_lock);
    > +
    > + return i;
    > +}
    > +
    > +struct esp_node *esp_get_node_by_addr(struct esp_pub *epub, const u8 *addr)
    > +{
    > + struct esp_node *node = NULL;
    > + int i;
    > + u32 map;
    > +
    > + if (!addr)
    > + return NULL;
    > +
    > + spin_lock_bh(&epub->tx_ampdu_lock);
    > + map = epub->enodes_map;
    > +
    > + while (map) {
    > + i = ffs(map) - 1;
    > +
    > + if (!memcmp(epub->enodes[i]->sta->addr, addr, ETH_ALEN)) {
    > + node = epub->enodes[i];
    > + goto out;
    > + }
    > +
    > + map &= ~BIT(i);
    > + }
    > +
    > +out:
    > + spin_unlock_bh(&epub->tx_ampdu_lock);
    > +
    > + return node;
    > +}
    > +
    > +int esp_get_empty_rxampdu(struct esp_pub *epub, const u8 *addr, u8 tid)
    > +{
    > + int index;
    > +
    > + if (!addr)
    > + return -1;
    > +
    > + spin_lock_bh(&epub->rx_ampdu_lock);
    > +
    > + index = ffz(epub->rxampdu_map);
    > +
    > + if (index >= ESP_PUB_MAX_RXAMPDU) {
    > + index = -1;
    > + goto out;
    > + }
    > +
    > + epub->rxampdu_map |= BIT(index);
    > + epub->rxampdu_node[index] = esp_get_node_by_addr(epub, addr);
    > + epub->rxampdu_tid[index] = tid;
    > +
    > +out:
    > + spin_unlock_bh(&epub->rx_ampdu_lock);
    > +
    > + return index;
    > +}
    > +
    > +int esp_get_exist_rxampdu(struct esp_pub *epub, const u8 *addr, u8 tid)
    > +{
    > + u8 map;
    > + int index;
    > +
    > + if (!addr)
    > + return -1;
    > +
    > + spin_lock_bh(&epub->rx_ampdu_lock);
    > + map = epub->rxampdu_map;
    > +
    > + while (map) {
    > + index = ffs(map) - 1;
    > +
    > + if (epub->rxampdu_tid[index] == tid &&
    > + !memcmp(epub->rxampdu_node[index]->sta->addr, addr,
    > + ETH_ALEN)) {
    > + epub->rxampdu_map &= ~BIT(index);
    > + goto out;
    > + }
    > +
    > + map &= ~BIT(index);
    > + }
    > +
    > + index = -1;
    > +
    > +out:
    > + spin_unlock_bh(&epub->rx_ampdu_lock);
    > + return index;
    > +}
    > +
    > +/*
    > + Notifies low level driver about addition of an associated station,
    > + 3109 * AP, IBSS/WDS/mesh peer etc. This callback can sleep.
    > + */
    > +static int esp_op_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    > + struct ieee80211_sta *sta)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + struct esp_vif *evif = (struct esp_vif *)vif->drv_priv;
    > + int index;
    > +
    > + index = esp_node_attach(hw, evif->index, sta);
    > + if (index < 0)
    > + return index;
    > +
    > + sip_send_set_sta(epub, evif->index, 1, sta, vif, (u8)index);
    > +
    > + return 0;
    > +}
    > +
    > +/*
    > + Notifies low level driver about removal of an associated
    > + 3112 * station, AP, IBSS/WDS/mesh peer etc. Note that after the callback
    > + 3113 * returns it isn't safe to use the pointer, not even RCU protected;
    > + 3114 * no RCU grace period is guaranteed between returning here and freeing
    > + 3115 * the station. See @sta_pre_rcu_remove if needed.
    > + 3116 * This callback can sleep
    > + */
    > +static int esp_op_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    > + struct ieee80211_sta *sta)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + struct esp_vif *evif = (struct esp_vif *)vif->drv_priv;
    > + int index;
    > +
    > + //remove a connect in target
    > + index = esp_node_detach(hw, evif->index, sta);

    Why do we think "index" is not -1?

    > + sip_send_set_sta(epub, evif->index, 0, sta, vif, (u8)index);
    > +
    > + return 0;
    > +}
    > +
    > +/*
    > + Notifies low level driver about power state transition of an
    > + 3124 * associated station, AP, IBSS/WDS/mesh peer etc. For a VIF operating
    > + 3125 * in AP mode, this callback will not be called when the flag
    > + 3126 * %IEEE80211_HW_AP_LINK_PS is set. Must be atomic.
    > + */
    > +static void esp_op_sta_notify(struct ieee80211_hw *hw,
    > + struct ieee80211_vif *vif,
    > + enum sta_notify_cmd cmd,
    > + struct ieee80211_sta *sta)
    > +{
    > +}
    > +
    > +/*
    > + Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
    > + 3165 * bursting) for a hardware TX queue.
    > + 3166 * Returns a negative error code on failure.
    > + 3167 * The callback can sleep.
    > + */
    > +static int esp_op_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    > + u16 queue,
    > + const struct ieee80211_tx_queue_params *params)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > +
    > + return sip_send_wmm_params(epub, queue, params);
    > +}
    > +
    > +/*
    > + Get the current TSF timer value from firmware/hardware. Currently,
    > + 3170 * this is only used for IBSS mode BSSID merging and debugging. Is not a
    > + 3171 * required function.
    > + 3172 * The callback can sleep.
    > + */
    > +static u64 esp_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
    > +{
    > + return 0;
    > +}
    > +
    > +/*
    > + Set the TSF timer to the specified value in the firmware/hardware.
    > + 3175 * Currently, this is only used for IBSS mode debugging. Is not a
    > + 3176 * required function.
    > + 3177 * The callback can sleep.
    > + */
    > +static void esp_op_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    > + u64 tsf)
    > +{
    > +}
    > +
    > +/*
    > + Reset the TSF timer and allow firmware/hardware to synchronize
    > + 3186 * with other STAs in the IBSS. This is only used in IBSS mode. This
    > + 3187 * function is optional if the firmware/hardware takes full care of
    > + 3188 * TSF synchronization.
    > + 3189 * The callback can sleep.
    > + */
    > +static void esp_op_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
    > +{
    > +}
    > +
    > +/*
    > + Poll rfkill hardware state. If you need this, you also
    > + 3220 * need to set wiphy->rfkill_poll to %true before registration,
    > + 3221 * and need to call wiphy_rfkill_set_hw_state() in the callback.
    > + 3222 * The callback can sleep.
    > + */
    > +static void esp_op_rfkill_poll(struct ieee80211_hw *hw)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > +
    > + wiphy_rfkill_set_hw_state(hw->wiphy, test_bit(ESP_WL_FLAG_RFKILL,
    > + &epub->wl.flags));
    > +}
    > +
    > +#ifdef HW_SCAN
    > +/*
    > + Ask the hardware to service the scan request, no need to start
    > + 3051 * the scan state machine in stack. The scan must honour the channel
    > + 3052 * configuration done by the regulatory agent in the wiphy's
    > + 3053 * registered bands. The hardware (or the driver) needs to make sure
    > + 3054 * that power save is disabled.
    > + 3055 * The @req ie/ie_len members are rewritten by mac80211 to contain the
    > + 3056 * entire IEs after the SSID, so that drivers need not look at these
    > + 3057 * at all but just send them after the SSID -- mac80211 includes the
    > + 3058 * (extended) supported rates and HT information (where applicable).
    > + 3059 * When the scan finishes, ieee80211_scan_completed() must be called;
    > + 3060 * note that it also must be called when the scan cannot finish due to
    > + 3061 * any error unless this callback returned a negative error code.
    > + 3062 * The callback can sleep.
    > + */
    > +static int esp_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    > + struct cfg80211_scan_request *req)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + struct cfg80211_ssid *ssid2 = req->ssids + 1;
    > + int i, ret;
    > + bool scan_often;
    > +
    > + /* scan_request is keep allocate until scan_done,record it
    > + * to split request into multi sdio_cmd
    > + */
    > + if (atomic_read(&epub->wl.off)) {
    > + dev_err(epub->dev, "hw_scan but wl off\n");
    > + return -EPERM;
    > + }
    > +
    > + if (req->n_ssids > 1)
    > + if ((req->ssids->ssid_len > 0 && ssid2->ssid_len > 0) ||
    > + req->n_ssids > 2) {
    > + dev_err(epub->dev, "cannot scan two SSIDs\n");
    > + return -EINVAL;
    > + }
    > +
    > + epub->wl.scan_req = req;
    > +
    > + /*in connect state, suspend tx data */
    > + if (epub->sip->support_bgscan &&
    > + test_bit(ESP_WL_FLAG_CONNECT, &epub->wl.flags) && req->n_channels) {
    > + scan_often = epub->scan_permit_valid &&
    > + time_before(jiffies, epub->scan_permit);
    > + epub->scan_permit_valid = true;
    > +
    > + if (!scan_often) {
    > + /* epub->scan_permit = jiffies + msecs_to_jiffies(900);
    > + * set_bit(ESP_WL_FLAG_STOP_TXQ, &epub->wl.flags);
    > + * if (atomic_read(&epub->txq_stopped) == false) {
    > + * atomic_set(&epub->txq_stopped, true);
    > + * ieee80211_stop_queues(hw);
    > + * }
    > + */
    > + } else {
    > + dev_err(epub->dev, "scan too often\n");
    > + return -EACCES;
    > + }
    > + } else {
    > + scan_often = false;
    > + }
    > +
    > + /*send sub_scan task to target */
    > + ret = sip_send_scan(epub);
    > + if (ret) {
    > + dev_err(epub->dev, "failed to send scan_cmd: %d\n", ret);
    > + return ret;
    > + }
    > +
    > + if (scan_often)
    > + return 0;
    > +
    > + epub->scan_permit = jiffies + msecs_to_jiffies(900);
    > + set_bit(ESP_WL_FLAG_STOP_TXQ, &epub->wl.flags);
    > + if (!atomic_read(&epub->txq_stopped)) {
    > + atomic_set(&epub->txq_stopped, true);
    > + ieee80211_stop_queues(hw);
    > + }
    > +
    > + /*force scan complete in case target fail to report in time */
    > + ieee80211_queue_delayed_work(hw, &epub->scan_timeout_work,
    > + req->n_channels * HZ / 4);
    > +
    > + return 0;
    > +}
    > +
    > +/*
    > + Starts an off-channel period on the given channel, must
    > + 3255 * call back to ieee80211_ready_on_channel() when on that channel. Note
    > + 3256 * that normal channel traffic is not stopped as this is intended for hw
    > + 3257 * offload. Frames to transmit on the off-channel channel are transmitted
    > + 3258 * normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the
    > + 3259 * duration (which will always be non-zero) expires, the driver must call
    > + 3260 * ieee80211_remain_on_channel_expired().
    > + 3261 * Note that this callback may be called while the device is in IDLE and
    > + 3262 * must be accepted in this case.
    > + 3263 * This callback may sleep.
    > + */
    > +static int esp_op_remain_on_channel(struct ieee80211_hw *hw,
    > + struct ieee80211_channel *chan,
    > + enum nl80211_channel_type channel_type,
    > + int duration)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > +
    > + sip_send_roc(epub, chan->center_freq, duration);
    > +
    > + return 0;
    > +}
    > +
    > +/*
    > + 3264 * @cancel_remain_on_channel: Requests that an ongoing off-channel period is
    > + 3265 * aborted before it expires. This callback may sleep.
    > + */
    > +static int esp_op_cancel_remain_on_channel(struct ieee80211_hw *hw)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > +
    > + epub->roc_flags = 0; // to disable roc state
    > + sip_send_roc(epub, 0, 0);
    > +
    > + return 0;
    > +}
    > +#endif
    > +
    > +void esp_rocdone_process(struct ieee80211_hw *hw, struct sip_evt_roc *report)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > +
    > + if (report->is_ok != 1)
    > + return;
    > +
    > + if (report->state == 1) {
    > + epub->roc_flags = 1; //flags in roc state, to fix channel, not change
    > + ieee80211_ready_on_channel(hw);
    > + } else if (!report->state) {
    > + epub->roc_flags = 0;
    > + ieee80211_remain_on_channel_expired(hw);
    > + }
    > +}
    > +
    > +/*
    > + Set a mask of rates to be used for rate control selection
    > + 3275 * when transmitting a frame. Currently only legacy rates are handled.
    > + 3276 * The callback can sleep.
    > + */
    > +static int esp_op_set_bitrate_mask(struct ieee80211_hw *hw,
    > + struct ieee80211_vif *vif,
    > + const struct cfg80211_bitrate_mask *mask)
    > +{
    > + return 0;
    > +}
    > +
    > +/*
    > + Flush all pending frames from the hardware queue, making sure
    > + 3235 * that the hardware queues are empty. The @queues parameter is a bitmap
    > + 3236 * of queues to flush, which is useful if different virtual interfaces
    > + 3237 * use different hardware queues; it may also indicate all queues.
    > + 3238 * If the parameter @drop is set to %true, pending frames may be dropped.
    > + 3239 * Note that vif can be NULL.
    > + 3240 * The callback can sleep.
    > + */
    > +void esp_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    > + u32 queues, bool drop)
    > +{
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + unsigned long time = jiffies + msecs_to_jiffies(15);
    > +
    > + while (atomic_read(&epub->sip->tx_data_pkt_queued)) {
    > + if (!time_before(jiffies, time))
    > + break;
    > +
    > + if (!sif_get_ate_config())
    > + ieee80211_queue_work(epub->hw, &epub->tx_work);
    > + else
    > + queue_work(epub->esp_wkq, &epub->tx_work);
    > + }
    > +
    > + mdelay(10);
    > +}
    > +
    > +/*
    > + Perform a certain A-MPDU action
    > + 3198 * The RA/TID combination determines the destination and TID we want
    > + 3199 * the ampdu action to be performed for. The action is defined through
    > + 3200 * ieee80211_ampdu_mlme_action.
    > + 3201 * When the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL the driver
    > + 3202 * may neither send aggregates containing more subframes than @buf_size
    > + 3203 * nor send aggregates in a way that lost frames would exceed the
    > + 3204 * buffer size. If just limiting the aggregate size, this would be
    > + 3205 * possible with a buf_size of 8:
    > + 3206 * - TX: 1.....7
    > + 3207 * - RX: 2....7 (lost frame #1)
    > + 3208 * - TX: 8..1...
    > + 3209 * which is invalid since #1 was now re-transmitted well past the
    > + 3210 * buffer size of 8. Correct ways to retransmit #1 would be:
    > + 3211 * - TX: 1 or 18 or 81
    > + 3212 * Even "189" would be wrong since 1 could be lost again.
    > + 3213 *
    > + 3214 * Returns a negative error code on failure.
    > + 3215 * The callback can sleep.
    > + */
    > +static int esp_op_ampdu_action(struct ieee80211_hw *hw,
    > + struct ieee80211_vif *vif,
    > + struct ieee80211_ampdu_params *params)
    > +{
    > + enum ieee80211_ampdu_mlme_action action = params->action;
    > + struct ieee80211_sta *sta = params->sta;
    > + struct esp_pub *epub = (struct esp_pub *)hw->priv;
    > + struct esp_node *node = (struct esp_node *)sta->drv_priv;
    > + struct cfg80211_chan_def *chandef;
    > + u16 tid = params->tid;
    > + struct esp_tx_tid *tid_info = &node->tid[tid];
    > + u16 *ssn = &params->ssn;
    > + u8 buf_size = params->buf_size;
    > +
    > + switch (action) {
    > + case IEEE80211_AMPDU_TX_START:
    > + chandef = &epub->hw->conf.chandef;
    > + if (mod_support_no_txampdu() || !sta->ht_cap.ht_supported ||
    > + cfg80211_get_chandef_type(chandef) == NL80211_CHAN_NO_HT)
    > + return -EOPNOTSUPP;
    > +
    > + dev_dbg(epub->dev, "%s TX START, addr:%pM,tid:%u,state:%d\n",
    > + __func__, sta->addr, tid, tid_info->state);
    > +
    > + spin_lock_bh(&epub->tx_ampdu_lock);
    > +
    > + ESSERT(tid_info->state == ESP_TID_STATE_TRIGGER);
    > + *ssn = tid_info->ssn;
    > + tid_info->state = ESP_TID_STATE_PROGRESS;
    > +
    > + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
    > + spin_unlock_bh(&epub->tx_ampdu_lock);
    > +
    > + return 0;
    > +
    > + case IEEE80211_AMPDU_TX_STOP_CONT:
    > + dev_dbg(epub->dev, "%s TX STOP, addr:%pM,tid:%u,state:%d\n",
    > + __func__, sta->addr, tid, tid_info->state);
    > +
    > + spin_lock_bh(&epub->tx_ampdu_lock);
    > +
    > + case IEEE80211_AMPDU_TX_STOP_FLUSH:
    > + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
    > + if (tid_info->state == ESP_TID_STATE_WAIT_STOP)
    > + tid_info->state = ESP_TID_STATE_STOP;
    > + else
    > + tid_info->state = ESP_TID_STATE_INIT;
    > +
    > + if (action == IEEE80211_AMPDU_TX_STOP_CONT) {
    > + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
    > + spin_unlock_bh(&epub->tx_ampdu_lock);
    > + }
    > +
    > + return sip_send_ampdu_action(epub, SIP_AMPDU_TX_STOP, sta->addr,
    > + tid, node->ifidx, 0);
    > +
    > + case IEEE80211_AMPDU_TX_OPERATIONAL:
    > + dev_dbg(epub->dev,
    > + "%s TX OPERATION, addr:%pM,tid:%u,state:%d\n", __func__,
    > + sta->addr, tid, tid_info->state);
    > +
    > + spin_lock_bh(&epub->tx_ampdu_lock);
    > +
    > + if (tid_info->state != ESP_TID_STATE_PROGRESS) {
    > + if (tid_info->state == ESP_TID_STATE_INIT) {
    > + printk(KERN_ERR "%s WIFI RESET, IGNORE\n",
    > + __func__);
    > + spin_unlock_bh(&epub->tx_ampdu_lock);
    > + return -ENETRESET;
    > + }
    > +
    > + ESSERT(0);
    > + }
    > +
    > + tid_info->state = ESP_TID_STATE_OPERATIONAL;
    > + spin_unlock_bh(&epub->tx_ampdu_lock);
    > +
    > + return sip_send_ampdu_action(epub, SIP_AMPDU_TX_OPERATIONAL,
    > + sta->addr, tid, node->ifidx,
    > + buf_size);
    > +
    > + case IEEE80211_AMPDU_RX_START:
    > + chandef = &epub->hw->conf.chandef;
    > + if (mod_support_no_rxampdu() || !sta->ht_cap.ht_supported ||
    > + cfg80211_get_chandef_type(chandef) == NL80211_CHAN_NO_HT)
    > + return -EOPNOTSUPP;
    > +
    > + dev_dbg(epub->dev, "%s RX START %pM tid %u %u\n", __func__,
    > + sta->addr, tid, *ssn);
    > +
    > + return sip_send_ampdu_action(epub, SIP_AMPDU_RX_START, sta->addr,
    > + tid, *ssn, 64);
    > +
    > + case IEEE80211_AMPDU_RX_STOP:
    > + dev_dbg(epub->dev, "%s RX STOP %pM tid %u\n", __func__,
    > + sta->addr, tid);
    > +
    > + return sip_send_ampdu_action(epub, SIP_AMPDU_RX_STOP, sta->addr,
    > + tid, 0, 0);
    > +
    > + default:
    > + return -EINVAL;
    > + }
    > +}
    > +
    > +static void esp_tx_work(struct work_struct *work)
    > +{
    > + struct esp_pub *epub = container_of(work, struct esp_pub, tx_work);
    > +
    > + mutex_lock(&epub->tx_mtx);
    > + sip_txq_process(epub);
    > + mutex_unlock(&epub->tx_mtx);
    > +}
    > +
    > +static const struct ieee80211_ops esp_mac80211_ops = {
    > + .tx = esp_op_tx,
    > + .start = esp_op_start,
    > + .stop = esp_op_stop,
    > + .add_interface = esp_op_add_interface,
    > + .remove_interface = esp_op_remove_interface,
    > + .config = esp_op_config,
    > +
    > + .bss_info_changed = esp_op_bss_info_changed,
    > + .configure_filter = esp_op_configure_filter,
    > + .set_key = esp_op_set_key,
    > + .set_rts_threshold = esp_op_set_rts_threshold,
    > + .sta_notify = esp_op_sta_notify,
    > + .conf_tx = esp_op_conf_tx,
    > + .change_interface = esp_op_change_interface,
    > + .get_tsf = esp_op_get_tsf,
    > + .set_tsf = esp_op_set_tsf,
    > + .reset_tsf = esp_op_reset_tsf,
    > + .rfkill_poll = esp_op_rfkill_poll,
    > +#ifdef HW_SCAN
    > + .hw_scan = esp_op_hw_scan,
    > + .remain_on_channel = esp_op_remain_on_channel,
    > + .cancel_remain_on_channel = esp_op_cancel_remain_on_channel,
    > +#endif
    > + .ampdu_action = esp_op_ampdu_action,
    > + .sta_add = esp_op_sta_add,
    > + .sta_remove = esp_op_sta_remove,
    > + .set_bitrate_mask = esp_op_set_bitrate_mask,
    > + .flush = esp_op_flush,
    > +};
    > +
    > +struct esp_pub *esp_pub_alloc_mac80211(struct device *dev)
    > +{
    > + struct ieee80211_hw *hw;
    > + struct esp_pub *epub;
    > +
    > + hw = ieee80211_alloc_hw(sizeof(struct esp_pub), &esp_mac80211_ops);
    > + if (!hw)
    > + return ERR_PTR(-ENOMEM);

    The caller expects a NULL return.

    > +
    > + /* FIXME: useless if hw_scan is defined, incorrect if hw_scan is undefined*/
    > +#ifdef HW_SCAN
    > + hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
    > +#endif
    > +
    > + epub = hw->priv;
    > + memset(epub, 0, sizeof(*epub));
    > +
    > + epub->hw = hw;
    > + SET_IEEE80211_DEV(hw, dev);
    > + epub->dev = dev;
    > +
    > + skb_queue_head_init(&epub->txq);
    > + skb_queue_head_init(&epub->txdoneq);
    > + skb_queue_head_init(&epub->rxq);
    > +
    > + spin_lock_init(&epub->tx_ampdu_lock);
    > + spin_lock_init(&epub->rx_ampdu_lock);
    > + spin_lock_init(&epub->tx_lock);
    > + mutex_init(&epub->tx_mtx);
    > + spin_lock_init(&epub->rx_lock);
    > +
    > + INIT_WORK(&epub->tx_work, esp_tx_work);
    > +
    > + epub->esp_wkq = create_singlethread_workqueue("esp_wkq");
    > +
    > + if (!epub->esp_wkq)
    > + return ERR_PTR(-ENOMEM);

    goto free_hw;

    > +
    > + epub->scan_permit_valid = false;
    > + INIT_DELAYED_WORK(&epub->scan_timeout_work, hw_scan_timeout_report);
    > +
    > + return epub;
    > +}
    > +
    > +int esp_pub_dealloc_mac80211(struct esp_pub *epub)
    > +{
    > + set_bit(ESP_WL_FLAG_RFKILL, &epub->wl.flags);
    > +
    > + destroy_workqueue(epub->esp_wkq);
    > + mutex_destroy(&epub->tx_mtx);
    > +
    > + if (epub->hw)
    > + ieee80211_free_hw(epub->hw);
    > +
    > + return 0;
    > +}
    > +
    > +/* 2G band channels */
    > +static struct ieee80211_channel esp_channels_2ghz[] = {
    > + {.hw_value = 1, .center_freq = 2412, .max_power = 25},
    > + {.hw_value = 2, .center_freq = 2417, .max_power = 25},
    > + {.hw_value = 3, .center_freq = 2422, .max_power = 25},
    > + {.hw_value = 4, .center_freq = 2427, .max_power = 25},
    > + {.hw_value = 5, .center_freq = 2432, .max_power = 25},
    > + {.hw_value = 6, .center_freq = 2437, .max_power = 25},
    > + {.hw_value = 7, .center_freq = 2442, .max_power = 25},
    > + {.hw_value = 8, .center_freq = 2447, .max_power = 25},
    > + {.hw_value = 9, .center_freq = 2452, .max_power = 25},
    > + {.hw_value = 10, .center_freq = 2457, .max_power = 25},
    > + {.hw_value = 11, .center_freq = 2462, .max_power = 25},
    > + {.hw_value = 12, .center_freq = 2467, .max_power = 25},
    > + {.hw_value = 13, .center_freq = 2472, .max_power = 25},
    > +};
    > +
    > +/* 11G rate */
    > +static struct ieee80211_rate esp_rates_2ghz[] = {
    > + {
    > + .bitrate = 10,
    > + .hw_value = CONF_HW_BIT_RATE_1MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_1MBPS,
    > + },
    > + {
    > + .bitrate = 20,
    > + .hw_value = CONF_HW_BIT_RATE_2MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
    > + .flags = IEEE80211_RATE_SHORT_PREAMBLE},
    > + {
    > + .bitrate = 55,
    > + .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
    > + .flags = IEEE80211_RATE_SHORT_PREAMBLE},
    > + {
    > + .bitrate = 110,
    > + .hw_value = CONF_HW_BIT_RATE_11MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
    > + .flags = IEEE80211_RATE_SHORT_PREAMBLE},
    > + {
    > + .bitrate = 60,
    > + .hw_value = CONF_HW_BIT_RATE_6MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_6MBPS,
    > + },
    > + {
    > + .bitrate = 90,
    > + .hw_value = CONF_HW_BIT_RATE_9MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_9MBPS,
    > + },
    > + {
    > + .bitrate = 120,
    > + .hw_value = CONF_HW_BIT_RATE_12MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_12MBPS,
    > + },
    > + {
    > + .bitrate = 180,
    > + .hw_value = CONF_HW_BIT_RATE_18MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_18MBPS,
    > + },
    > + {
    > + .bitrate = 240,
    > + .hw_value = CONF_HW_BIT_RATE_24MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_24MBPS,
    > + },
    > + {
    > + .bitrate = 360,
    > + .hw_value = CONF_HW_BIT_RATE_36MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_36MBPS,
    > + },
    > + {
    > + .bitrate = 480,
    > + .hw_value = CONF_HW_BIT_RATE_48MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_48MBPS,
    > + },
    > + {
    > + .bitrate = 540,
    > + .hw_value = CONF_HW_BIT_RATE_54MBPS,
    > + .hw_value_short = CONF_HW_BIT_RATE_54MBPS,
    > + },
    > +};
    > +
    > +static struct ieee80211_sta_ht_cap esp_ht_cap_2ghz = {
    > + .cap = IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_SM_PS |
    > + IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20,
    > + .ht_supported = true,
    > + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
    > + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
    > + .mcs = {
    > + .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
    > + },
    > +};
    > +
    > +static void esp_pub_init_mac80211(struct esp_pub *epub)
    > +{
    > + struct ieee80211_hw *hw = epub->hw;
    > + struct ieee80211_supported_band *sbands =
    > + &epub->wl.sbands[NL80211_BAND_2GHZ];
    > +
    > + static const u32 cipher_suites[] = {
    > + WLAN_CIPHER_SUITE_WEP40,
    > + WLAN_CIPHER_SUITE_WEP104,
    > + WLAN_CIPHER_SUITE_TKIP,
    > + WLAN_CIPHER_SUITE_CCMP,
    > + };
    > +
    > + hw->max_listen_interval = 10;
    > +
    > + ieee80211_hw_set(hw, SIGNAL_DBM);
    > + ieee80211_hw_set(hw, HAS_RATE_CONTROL);
    > + ieee80211_hw_set(hw, SUPPORTS_PS);
    > + ieee80211_hw_set(hw, AMPDU_AGGREGATION);
    > + ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
    > + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
    > + hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
    > +
    > + hw->wiphy->cipher_suites = cipher_suites;
    > + hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
    > + hw->wiphy->max_scan_ie_len = epub->sip->tx_blksz -
    > + sizeof(struct sip_hdr) - sizeof(struct sip_cmd_scan);
    > +
    > + /* ONLY station for now, support P2P soon... */
    > + /* FIXME: is p2p really supported? */
    > + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_P2P_GO) |
    > + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_STATION) |
    > + BIT(NL80211_IFTYPE_AP);
    > +
    > + hw->wiphy->max_scan_ssids = 2;
    > + hw->wiphy->max_remain_on_channel_duration = 5000;
    > +
    > + atomic_set(&epub->wl.off, 1);
    > +
    > + sbands->band = NL80211_BAND_2GHZ;
    > + sbands->channels = esp_channels_2ghz;
    > + sbands->bitrates = esp_rates_2ghz;
    > + sbands->n_channels = ARRAY_SIZE(esp_channels_2ghz);
    > + sbands->n_bitrates = ARRAY_SIZE(esp_rates_2ghz);
    > + sbands->ht_cap = esp_ht_cap_2ghz;
    > +
    > + hw->wiphy->bands[NL80211_BAND_2GHZ] = sbands;
    > +
    > + /*no fragment */
    > + hw->wiphy->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
    > +
    > + /* handle AC queue in f/w */
    > + hw->queues = 4;
    > + hw->max_rates = 4;
    > +
    > + hw->vif_data_size = sizeof(struct esp_vif);
    > + hw->sta_data_size = sizeof(struct esp_node);
    > +}
    > +
    > +int esp_register_mac80211(struct esp_pub *epub)
    > +{
    > + int ret, idx;
    > + u8 *p2p_addr;
    > +
    > + esp_pub_init_mac80211(epub);
    > +
    > + /* FIXME: esp_mac_addr */
    > + epub->hw->wiphy->addresses = (struct mac_address *)esp_mac_addr;
    > +
    > + memcpy(epub->hw->wiphy->addresses[0].addr, epub->mac_addr, ETH_ALEN);
    > + memcpy(epub->hw->wiphy->addresses[1].addr, epub->mac_addr, ETH_ALEN);
    > + p2p_addr = epub->hw->wiphy->addresses[1].addr;
    > +
    > + for (idx = 0; idx < 8 * ETH_ALEN; idx++) {
    > + p2p_addr[0] = epub->mac_addr[0] | 0x02;
    > + p2p_addr[0] ^= idx << 2;
    > + if (strncmp(p2p_addr, epub->mac_addr, 6))
    > + break;
    > + }
    > +
    > + epub->hw->wiphy->n_addresses = 2;
    > +
    > + ret = ieee80211_register_hw(epub->hw);
    > + if (ret < 0) {
    > + printk("unable to register mac80211 hw: %d\n", ret);
    > + return ret;
    > + }
    > +
    > + set_bit(ESP_WL_FLAG_HW_REGISTERED, &epub->wl.flags);
    > +
    > + return ret;

    return 0;

    > +}
    > +
    > +static u8 getaddr_index(u8 *addr, struct esp_pub *epub)
    > +{
    > + int i;
    > +
    > + for (i = 0; i < ESP_PUB_MAX_VIF; i++)
    > + if (!memcmp(addr, epub->hw->wiphy->addresses[i].addr, ETH_ALEN))
    > + return i;
    > +
    > + return ESP_PUB_MAX_VIF;
    > +}
    > diff --git a/drivers/staging/esp8089/esp_mac80211.h b/drivers/staging/esp8089/esp_mac80211.h
    > new file mode 100644
    > index 000000000000..03de0b0a4223
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_mac80211.h
    > @@ -0,0 +1,33 @@
    > +/*
    > + * Copyright (c) 2011 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef _ESP_MAC80211_H_
    > +#define _ESP_MAC80211_H_
    > +
    > +struct esp_80211_wmm_ac_param {
    > + u8 aci_aifsn; /* AIFSN, ACM, ACI */
    > + u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
    > + u16 txop_limit;
    > +};
    > +
    > +struct esp_80211_wmm_param_element {
    > + /* Element ID: 221 (0xdd); length: 24 */
    > + /* required fields for WMM version 1 */
    > + u8 oui[3]; /* 00:50:f2 */
    > + u8 oui_type; /* 2 */
    > + u8 oui_subtype; /* 1 */
    > + u8 version; /* 1 for WMM version 1.0 */
    > + u8 qos_info; /* AP/STA specif QoS info */
    > + u8 reserved; /* 0 */
    > + struct esp_80211_wmm_ac_param ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
    > +};
    > +
    > +#endif /* _ESP_MAC80211_H_ */
    > diff --git a/drivers/staging/esp8089/esp_main.c b/drivers/staging/esp8089/esp_main.c
    > new file mode 100644
    > index 000000000000..c4621847926c
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_main.c
    > @@ -0,0 +1,199 @@
    > +/*
    > + * Copyright (c) 2010 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#include <linux/netdevice.h>
    > +#include <linux/etherdevice.h>
    > +#include <linux/rtnetlink.h>
    > +#include <linux/firmware.h>
    > +#include <linux/sched.h>
    > +#include <net/cfg80211.h>
    > +#include <net/mac80211.h>
    > +#include <linux/time.h>
    > +#include <linux/moduleparam.h>
    > +#include <linux/module.h>
    > +
    > +#include "esp_pub.h"
    > +#include "esp_sip.h"
    > +#include "esp_sif.h"
    > +#include "esp_debug.h"
    > +#include "esp_file.h"
    > +#include "esp_wl.h"
    > +
    > +struct completion *gl_bootup_cplx;
    > +
    > +static int esp_download_fw(struct esp_pub *epub);
    > +
    > +static int modparam_no_txampdu;
    > +static int modparam_no_rxampdu;
    > +
    > +module_param_named(no_txampdu, modparam_no_txampdu, int, 0444);
    > +MODULE_PARM_DESC(no_txampdu, "Disable tx ampdu.");
    > +
    > +module_param_named(no_rxampdu, modparam_no_rxampdu, int, 0444);
    > +MODULE_PARM_DESC(no_rxampdu, "Disable rx ampdu.");
    > +
    > +static char *modparam_eagle_path = "/lib/firmware";
    > +
    > +module_param_named(eagle_path, modparam_eagle_path, charp, 0444);
    > +MODULE_PARM_DESC(eagle_path, "eagle path");
    > +
    > +bool mod_support_no_txampdu(void)
    > +{
    > + return modparam_no_txampdu;
    > +}
    > +
    > +bool mod_support_no_rxampdu(void)
    > +{
    > + return modparam_no_rxampdu;
    > +}
    > +
    > +int esp_pub_init_all(struct esp_pub *epub)
    > +{
    > + int ret;
    > +
    > + /* completion for bootup event poll */
    > + DECLARE_COMPLETION_ONSTACK(complete);
    > +
    > + atomic_set(&epub->ps.state, ESP_PM_OFF);
    > +
    > + if (epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
    > + epub->sip = sip_attach(epub);
    > + if (!epub->sip) {
    > + printk(KERN_ERR "%s sip alloc failed\n", __func__);
    > + return -ENOMEM;
    > + }
    > + } else {
    > + atomic_set(&epub->sip->state, SIP_PREPARE_BOOT);
    > + atomic_set(&epub->sip->tx_credits, 0);
    > + }
    > +
    > + epub->sip->to_host_seq = 0;
    > +
    > + ret = esp_download_fw(epub);
    > + if (ret) {
    > + printk("download firmware failed\n");
    > + return ret;
    > + }
    > +
    > + gl_bootup_cplx = &complete;
    > + epub->wait_reset = 0;
    > + sif_enable_irq(epub);
    > +
    > + if (epub->sdio_state == ESP_SDIO_STATE_SECOND_INIT ||
    > + sif_get_ate_config() == 1) {

    Drop the == 1. We mostly treat sif_get_ate_config() as bool, so let's
    do that consistently everywhere.

    > + ret = sip_poll_bootup_event(epub->sip);
    > + } else {
    > + ret = sip_poll_resetting_event(epub->sip);
    > + if (!ret) {
    > + sif_lock_bus(epub);
    > + sif_interrupt_target(epub, 7);
    > + sif_unlock_bus(epub);
    > + }
    > + }
    > +
    > + gl_bootup_cplx = NULL;
    > +
    > + if (sif_get_ate_config() == 1)
    > + ret = -EOPNOTSUPP;
    > +
    > + return ret;
    > +}
    > +
    > +void esp_dsr(struct esp_pub *epub)

    Can this function be removed?

    > +{
    > + sip_rx(epub);
    > +}
    > +
    > +struct esp_fw_hdr {
    > + u8 magic;
    > + u8 blocks;
    > + u8 pad[2];
    > + u32 entry_addr;
    > +} __packed;
    > +
    > +struct esp_fw_blk_hdr {
    > + u32 load_addr;
    > + u32 data_len;
    > +} __packed;
    > +
    > +#define ESP_FW_NAME1 "eagle_fw_ate_config_v19.bin"
    > +#define ESP_FW_NAME2 "eagle_fw_first_init_v19.bin"
    > +#define ESP_FW_NAME3 "eagle_fw_second_init_v19.bin"
    > +
    > +static int esp_download_fw(struct esp_pub *epub)
    > +{
    > + const struct firmware *fw_entry;
    > + struct esp_fw_hdr *fhdr;
    > + struct esp_fw_blk_hdr *bhdr;
    > + struct sip_cmd_bootup bootcmd;
    > + u8 *fw_buf;
    > + u32 offset;
    > + int ret;
    > + u8 blocks;
    > + char *esp_fw_name;
    > +
    > + if (sif_get_ate_config() == 1)
    > + esp_fw_name = ESP_FW_NAME3;
    > + else
    > + esp_fw_name = epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT ? ESP_FW_NAME1 : ESP_FW_NAME2;
    > +
    > + ret = request_firmware(&fw_entry, esp_fw_name, epub->dev);
    > + if (ret)
    > + return ret;
    > +
    > + fw_buf = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
    > +
    > + release_firmware(fw_entry);
    > +
    > + if (!fw_buf)
    > + return -ENOMEM;
    > +
    > + fhdr = (struct esp_fw_hdr *)fw_buf;
    > + if (fhdr->magic != 0xE9) {
    > + printk("%s wrong firmware magic!\n", __func__);
    > + goto _err;

    Choose a label name based on what the goto does. For example, here if
    we hit the goto then we kfree(fw_buf); so "goto free_fw;" would be a
    descriptive name.

    Also don't forget to set the error code.

    > + }
    > +
    > + blocks = fhdr->blocks;
    > + offset = sizeof(struct esp_fw_hdr);
    > +
    > + while (blocks) {
    > + bhdr = (struct esp_fw_blk_hdr *)&fw_buf[offset];
    > + offset += sizeof(struct esp_fw_blk_hdr);
    > +
    > + ret = sip_write_memory(epub->sip, bhdr->load_addr,
    > + &fw_buf[offset], bhdr->data_len);
    > + if (ret) {
    > + printk("failed to write firmware: %d\n", ret);
    > + goto _err;
    > + }
    > +
    > + blocks--;
    > + offset += bhdr->data_len;
    > + }
    > +
    > + /* TODO: last byte should be the checksum and skip checksum for now */
    > +
    > + bootcmd.boot_addr = fhdr->entry_addr;
    > + ret = sip_send_cmd(epub->sip, SIP_CMD_BOOTUP,
    > + sizeof(struct sip_cmd_bootup), &bootcmd);
    > + if (ret)
    > + goto _err;
    > +
    > +_err:
    > + kfree(fw_buf);
    > +
    > + return ret;
    > +}
    > +
    > +MODULE_FIRMWARE(ESP_FW_NAME1);
    > +MODULE_FIRMWARE(ESP_FW_NAME2);
    > +MODULE_FIRMWARE(ESP_FW_NAME3);
    > diff --git a/drivers/staging/esp8089/esp_pub.h b/drivers/staging/esp8089/esp_pub.h
    > new file mode 100644
    > index 000000000000..e329fb0999e9
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_pub.h
    > @@ -0,0 +1,188 @@
    > +/*
    > + * Copyright (c) 2011 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef _ESP_PUB_H_
    > +#define _ESP_PUB_H_
    > +
    > +#include <linux/etherdevice.h>
    > +#include <linux/rtnetlink.h>
    > +#include <linux/firmware.h>
    > +#include <linux/sched.h>
    > +#include <net/mac80211.h>
    > +#include <net/cfg80211.h>
    > +#include "sip2_common.h"
    > +
    > +enum esp_sdio_state {
    > + ESP_SDIO_STATE_FIRST_INIT,
    > + ESP_SDIO_STATE_FIRST_NORMAL_EXIT,
    > + ESP_SDIO_STATE_FIRST_ERROR_EXIT,
    > + ESP_SDIO_STATE_SECOND_INIT,
    > + ESP_SDIO_STATE_SECOND_ERROR_EXIT,
    > +};
    > +
    > +enum esp_tid_state {
    > + ESP_TID_STATE_INIT,
    > + ESP_TID_STATE_TRIGGER,
    > + ESP_TID_STATE_PROGRESS,
    > + ESP_TID_STATE_OPERATIONAL,
    > + ESP_TID_STATE_WAIT_STOP,
    > + ESP_TID_STATE_STOP,
    > +};
    > +
    > +struct esp_tx_tid {
    > + u8 state;
    > + u8 cnt;
    > + u16 ssn;
    > +};
    > +
    > +#define WME_NUM_TID 16
    > +struct esp_node {
    > + struct esp_tx_tid tid[WME_NUM_TID];
    > + struct ieee80211_sta *sta;
    > + u8 ifidx;
    > + u8 index;
    > +};
    > +
    > +#define WME_AC_BE 2
    > +#define WME_AC_BK 3
    > +#define WME_AC_VI 1
    > +#define WME_AC_VO 0
    > +
    > +struct esp_vif {
    > + struct esp_pub *epub;
    > + u8 index;
    > + u32 beacon_interval;
    > + bool ap_up;
    > + struct timer_list beacon_timer;
    > +};
    > +
    > +/* WLAN related, mostly... */
    > +/*struct hw_scan_timeout {
    > + * struct delayed_work w;
    > + * struct ieee80211_hw *hw;
    > + * };
    > + */
    > +
    > +struct esp_wl {
    > + u8 bssid[ETH_ALEN];
    > + u8 req_bssid[ETH_ALEN];
    > +
    > + //struct hw_scan_timeout *hsd;
    > + struct cfg80211_scan_request *scan_req;
    > + atomic_t ptk_cnt;
    > + atomic_t gtk_cnt;
    > + atomic_t tkip_key_set;
    > +
    > + /* so far only 2G band */
    > + struct ieee80211_supported_band sbands[NUM_NL80211_BANDS];
    > +
    > + unsigned long flags;
    > + atomic_t off;
    > +};
    > +
    > +struct esp_hw_idx_map {
    > + u8 mac[ETH_ALEN];
    > + u8 flag;
    > +};
    > +
    > +#define ESP_WL_FLAG_RFKILL BIT(0)
    > +#define ESP_WL_FLAG_HW_REGISTERED BIT(1)
    > +#define ESP_WL_FLAG_CONNECT BIT(2)
    > +#define ESP_WL_FLAG_STOP_TXQ BIT(3)
    > +
    > +#define ESP_PUB_MAX_VIF 2
    > +#define ESP_PUB_MAX_STA 4 //for one interface
    > +#define ESP_PUB_MAX_RXAMPDU 8 //for all interfaces
    > +
    > +enum {
    > + ESP_PM_OFF = 0,
    > + ESP_PM_TURNING_ON,
    > + ESP_PM_ON,
    > + ESP_PM_TURNING_OFF, /* Do NOT change the order */
    > +};
    > +
    > +struct esp_ps {
    > + u32 dtim_period;
    > + u32 max_sleep_period;
    > + unsigned long last_config_time;
    > + atomic_t state;
    > + bool nulldata_pm_on;
    > +};
    > +
    > +struct esp_mac_prefix {
    > + u8 mac_index;
    > + u8 mac_addr_prefix[3];
    > +};
    > +
    > +struct esp_pub {
    > + struct device *dev;
    > + struct ieee80211_hw *hw;
    > + struct ieee80211_vif *vif;
    > + u8 vif_slot;
    > +
    > + struct esp_sdio_ctrl *sif; /* serial interface control block, e.g. sdio */
    > + enum esp_sdio_state sdio_state;
    > + struct esp_sip *sip;
    > + struct esp_wl wl;
    > + struct esp_hw_idx_map hi_map[19];
    > + struct esp_hw_idx_map low_map[ESP_PUB_MAX_VIF][2];
    > + //u32 flags; //flags to represent rfkill switch,start
    > + u8 roc_flags; //0: not in remain on channel state, 1: in roc state
    > +
    > + struct work_struct tx_work; /* attach to ieee80211 workqueue */
    > + /* latest mac80211 has multiple tx queue, but we stick with single queue now */
    > + spinlock_t rx_lock;
    > + spinlock_t tx_ampdu_lock;
    > + spinlock_t rx_ampdu_lock;
    > + spinlock_t tx_lock;
    > + struct mutex tx_mtx;
    > + struct sk_buff_head txq;
    > + atomic_t txq_stopped;
    > +
    > + struct work_struct sendup_work; /* attach to ieee80211 workqueue */
    > + struct sk_buff_head txdoneq;
    > + struct sk_buff_head rxq;
    > +
    > + struct workqueue_struct *esp_wkq;
    > +
    > + //u8 bssid[ETH_ALEN];
    > + u8 mac_addr[ETH_ALEN];
    > +
    > + u32 rx_filter;
    > + unsigned long scan_permit;
    > + bool scan_permit_valid;
    > + struct delayed_work scan_timeout_work;
    > + u32 enodes_map;
    > + u8 rxampdu_map;
    > + u32 enodes_maps[ESP_PUB_MAX_VIF];
    > + struct esp_node *enodes[ESP_PUB_MAX_STA + 1];
    > + struct esp_node *rxampdu_node[ESP_PUB_MAX_RXAMPDU];
    > + u8 rxampdu_tid[ESP_PUB_MAX_RXAMPDU];
    > + struct esp_ps ps;
    > + int enable_int;
    > + int wait_reset;
    > +};
    > +
    > +struct esp_pub *esp_pub_alloc_mac80211(struct device *dev);
    > +int esp_pub_dealloc_mac80211(struct esp_pub *epub);
    > +int esp_register_mac80211(struct esp_pub *epub);
    > +
    > +int esp_pub_init_all(struct esp_pub *epub);
    > +
    > +void esp_dsr(struct esp_pub *epub);
    > +void hw_scan_done(struct esp_pub *epub, bool aborted);
    > +void esp_rocdone_process(struct ieee80211_hw *hw, struct sip_evt_roc *report);
    > +
    > +struct esp_node *esp_get_node_by_addr(struct esp_pub *epub, const u8 *addr);
    > +int esp_get_empty_rxampdu(struct esp_pub *epub, const u8 *addr, u8 tid);
    > +int esp_get_exist_rxampdu(struct esp_pub *epub, const u8 *addr, u8 tid);
    > +
    > +#endif /* _ESP_PUB_H_ */
    > diff --git a/drivers/staging/esp8089/esp_sif.h b/drivers/staging/esp8089/esp_sif.h
    > new file mode 100644
    > index 000000000000..293640b11b0c
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_sif.h
    > @@ -0,0 +1,131 @@
    > +/*
    > + * Copyright (c) 2011 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef _ESP_SIF_H_
    > +#define _ESP_SIF_H_
    > +
    > +#include "esp_pub.h"
    > +#include <linux/mmc/host.h>
    > +#include <linux/spi/spi.h>
    > +
    > +/* H/W SLC module definitions */
    > +
    > +#define SIF_SLC_BLOCK_SIZE 512
    > +
    > +/* S/W struct mapping to slc registers */
    > +struct slc_host_regs {
    > + /* do NOT read token_rdata
    > + *
    > + * u32 pf_data;
    > + * u32 token_rdata;
    > + */
    > + u32 intr_raw;
    > + u32 state_w0;
    > + u32 state_w1;
    > + u32 config_w0;
    > + u32 config_w1;
    > + u32 intr_status;
    > + u32 config_w2;
    > + u32 config_w3;
    > + u32 config_w4;
    > + u32 token_wdata;
    > + u32 intr_clear;
    > + u32 intr_enable;
    > +};
    > +
    > +enum io_sync_type {
    > + ESP_SIF_NOSYNC = 0,
    > + ESP_SIF_SYNC,
    > +};
    > +
    > +struct esp_sdio_ctrl {
    > + struct sdio_func *func;
    > + struct esp_pub *epub;
    > +
    > + struct list_head free_req;
    > +
    > + u8 *dma_buffer;
    > +
    > + spinlock_t scat_lock;
    > + struct list_head scat_req;
    > +
    > + bool off;
    > + atomic_t irq_handling;
    > + const struct sdio_device_id *id;
    > + u32 slc_blk_sz;
    > + u32 target_id;
    > + u32 slc_window_end_addr;
    > +
    > + struct slc_host_regs slc_regs;
    > + atomic_t irq_installed;
    > +
    > +};
    > +
    > +#define SIF_TO_DEVICE 0x1
    > +#define SIF_FROM_DEVICE 0x2
    > +
    > +#define SIF_SYNC 0x00000010
    > +#define SIF_ASYNC 0x00000020
    > +
    > +#define SIF_BYTE_BASIS 0x00000040
    > +#define SIF_BLOCK_BASIS 0x00000080
    > +
    > +#define SIF_FIXED_ADDR 0x00000100
    > +#define SIF_INC_ADDR 0x00000200
    > +
    > +void sdio_io_writeb(struct esp_pub *epub, u8 value, int addr, int *res);
    > +u8 sdio_io_readb(struct esp_pub *epub, int addr, int *res);
    > +
    > +void sif_enable_irq(struct esp_pub *epub);
    > +void sif_disable_irq(struct esp_pub *epub);
    > +void sif_disable_target_interrupt(struct esp_pub *epub);
    > +
    > +u32 sif_get_blksz(struct esp_pub *epub);
    > +
    > +void sif_dsr(struct sdio_func *func);
    > +int sif_io_raw(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag);
    > +int sif_io_sync(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag);
    > +int sif_lldesc_read_sync(struct esp_pub *epub, u8 *buf, u32 len);
    > +int sif_lldesc_write_sync(struct esp_pub *epub, u8 *buf, u32 len);
    > +int sif_lldesc_read_raw(struct esp_pub *epub, u8 *buf, u32 len, bool noround);
    > +int sif_lldesc_write_raw(struct esp_pub *epub, u8 *buf, u32 len);
    > +
    > +int esp_common_read(struct esp_pub *epub, u8 *buf, u32 len, int sync,
    > + bool noround);
    > +int esp_common_write(struct esp_pub *epub, u8 *buf, u32 len, int sync);
    > +int esp_common_read_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, u32 len,
    > + int sync);
    > +int esp_common_write_with_addr(struct esp_pub *epub, u32 addr, u8 *buf,
    > + u32 len, int sync);
    > +
    > +int esp_common_readbyte_with_addr(struct esp_pub *epub, u32 addr, u8 *buf,
    > + int sync);
    > +int esp_common_writebyte_with_addr(struct esp_pub *epub, u32 addr, u8 buf,
    > + int sync);
    > +
    > +struct slc_host_regs *sif_get_regs(struct esp_pub *epub);
    > +
    > +void sif_lock_bus(struct esp_pub *epub);
    > +void sif_unlock_bus(struct esp_pub *epub);
    > +
    > +int sif_interrupt_target(struct esp_pub *epub, u8 index);
    > +
    > +void check_target_id(struct esp_pub *epub);
    > +
    > +void sif_record_bt_config(int value);
    > +int sif_get_bt_config(void);
    > +void sif_record_rst_config(int value);
    > +int sif_get_rst_config(void);
    > +void sif_record_ate_config(int value);
    > +int sif_get_ate_config(void);
    > +void sif_record_wakeup_gpio_config(int value);
    > +int sif_get_wakeup_gpio_config(void);
    > +#endif /* _ESP_SIF_H_ */
    > diff --git a/drivers/staging/esp8089/esp_sip.c b/drivers/staging/esp8089/esp_sip.c
    > new file mode 100644
    > index 000000000000..91fb64c9b794
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_sip.c
    > @@ -0,0 +1,1718 @@
    > +/*
    > + * Copyright (c) 2009 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#include <linux/ieee80211.h>
    > +#include <net/mac80211.h>
    > +#include <net/cfg80211.h>
    > +#include <linux/skbuff.h>
    > +#include <linux/bitops.h>
    > +#include <linux/mmc/card.h>
    > +#include <linux/mmc/mmc.h>
    > +#include <linux/mmc/host.h>
    > +#include <linux/mmc/sdio_func.h>
    > +#include <linux/mmc/sdio_ids.h>
    > +#include <linux/mmc/sdio.h>
    > +#include <linux/mmc/sd.h>
    > +#include <linux/completion.h>
    > +
    > +#include "esp_mac80211.h"
    > +#include "esp_pub.h"
    > +#include "esp_sip.h"
    > +#include "esp_ctrl.h"
    > +#include "esp_sif.h"
    > +#include "esp_debug.h"
    > +#include "slc_host_register.h"
    > +#include "esp_wmac.h"
    > +#include "esp_utils.h"
    > +
    > +extern struct completion *gl_bootup_cplx;
    > +
    > +static int old_signal = -35;
    > +static int avg_signal;
    > +static int signal_loop;
    > +
    > +struct esp_mac_prefix esp_mac_prefix_table[] = {
    > + {0, {0x18, 0xfe, 0x34} },
    > + {1, {0xac, 0xd0, 0x74} },
    > + {255, {0x18, 0xfe, 0x34} },
    > +};
    > +
    > +#define SIGNAL_COUNT 300
    > +
    > +/* FIXME: Incomplete ternary condition */
    > +#define TID_TO_AC(_tid) (!(_tid) || (_tid) == 3 ? WME_AC_BE : ((_tid) < 3 ? WME_AC_BK : ((_tid) < 6 ? WME_AC_VI : WME_AC_VO)))
    > +
    > +#define esp_sip_dbg esp_dbg
    > +struct sip_trace {
    > + u32 tx_data;
    > + u32 tx_cmd;
    > + u32 rx_data;
    > + u32 rx_evt;
    > + u32 rx_tx_status;
    > + u32 tx_out_of_credit;
    > + u32 tx_one_shot_overflow;
    > +};
    > +
    > +static struct sip_trace str;
    > +
    > +#define STRACE_TX_DATA_INC() (str.tx_data++)
    > +#define STRACE_TX_CMD_INC() (str.tx_cmd++)
    > +#define STRACE_RX_DATA_INC() (str.rx_data++)
    > +#define STRACE_RX_EVENT_INC() (str.rx_evt++)
    > +#define STRACE_RX_TXSTATUS_INC() (str.rx_tx_status++)
    > +#define STRACE_TX_OUT_OF_CREDIT_INC() (str.tx_out_of_credit++)
    > +#define STRACE_TX_ONE_SHOT_INC() (str.tx_one_shot_overflow++)
    > +
    > +#define SIP_STOP_QUEUE_THRESHOLD 48
    > +#define SIP_RESUME_QUEUE_THRESHOLD 12
    > +
    > +#define SIP_MIN_DATA_PKT_LEN (sizeof(struct esp_mac_rx_ctrl) + 24) //24 is min 80211hdr
    > +
    > +static void sip_recalc_credit_init(struct esp_sip *sip);
    > +
    > +static int sip_recalc_credit_claim(struct esp_sip *sip, int force);
    > +
    > +static void sip_recalc_credit_release(struct esp_sip *sip);
    > +
    > +static struct sip_pkt *sip_get_ctrl_buf(struct esp_sip *sip,
    > + enum sip_buf_type bftype);
    > +
    > +static void sip_reclaim_ctrl_buf(struct esp_sip *sip, struct sip_pkt *pkt,
    > + enum sip_buf_type bftype);
    > +
    > +static void sip_free_init_ctrl_buf(struct esp_sip *sip);
    > +
    > +static int sip_pack_pkt(struct esp_sip *sip, struct sk_buff *skb,
    > + int *pm_state);
    > +
    > +static struct esp_mac_rx_ctrl *sip_parse_normal_mac_ctrl(struct sk_buff *skb,
    > + int *pkt_len_enc,
    > + int *buf_len,
    > + int *pulled_len);
    > +
    > +static struct sk_buff *sip_parse_data_rx_info(struct esp_sip *sip,
    > + struct sk_buff *skb,
    > + int pkt_len_enc, int buf_len,
    > + struct esp_mac_rx_ctrl *mac_ctrl,
    > + int *pulled_len);
    > +
    > +static inline void sip_rx_pkt_enqueue(struct esp_sip *sip, struct sk_buff *skb);
    > +
    > +static void sip_update_tx_credits(struct esp_sip *sip, u16 recycled_credits);
    > +
    > +static bool sip_rx_pkt_process(struct esp_sip *sip, struct sk_buff *skb);
    > +
    > +static void sip_tx_status_report(struct esp_sip *sip, struct sk_buff *skb,
    > + struct ieee80211_tx_info *tx_info,
    > + bool success);
    > +
    > +static bool check_ac_tid(u8 *pkt, u8 ac, u8 tid)
    > +{
    > + struct ieee80211_hdr *wh = (struct ieee80211_hdr *)pkt;
    > +
    > + if (!ieee80211_is_data_qos(wh->frame_control) &&
    > + !ieee80211_is_mgmt(wh->frame_control) &&
    > + !ieee80211_is_ctl(wh->frame_control)) {
    > + if (tid || ac != WME_AC_BE) {
    > + pr_info("444 ac:%u, tid:%u\n", ac, tid);
    > +
    > + if (tid == 7 && ac == WME_AC_VO)
    > + return false;
    > + }
    > +
    > + return true; //hack to modify non-qos null data.
    > + }
    > +
    > + return false;
    > +}
    > +
    > +static void sip_recalc_credit_timeout(unsigned long data)
    > +{
    > + struct esp_sip *sip = (struct esp_sip *)data;
    > +
    > + sip_recalc_credit_claim(sip, 1); /* recalc again */
    > +}
    > +
    > +static void sip_recalc_credit_init(struct esp_sip *sip)
    > +{
    > + atomic_set(&sip->credit_status, RECALC_CREDIT_DISABLE); //set it disable
    > +
    > + setup_timer(&sip->credit_timer, sip_recalc_credit_timeout,
    > + (unsigned long)sip);
    > +}
    > +
    > +static int sip_recalc_credit_claim(struct esp_sip *sip, int force)
    > +{
    > + int ret;
    > +
    > + if (atomic_read(&sip->credit_status) == RECALC_CREDIT_ENABLE && !force)
    > + return 1;

    Put a comment to describe what why we are returning a mix of 1, zero and
    negative error codes. It's impossible to tell from the context because
    none of the callers check.

    > +
    > + atomic_set(&sip->credit_status, RECALC_CREDIT_ENABLE);
    > + ret = sip_send_recalc_credit(sip->epub);
    > + if (ret) {
    > + dev_err(sip->epub->dev, "sending recalc credit failed: %d",
    > + ret);
    > + return ret;
    > + }
    > +
    > + /*setup a timer for handle the abs_credit not receive */
    > + mod_timer(&sip->credit_timer, jiffies + msecs_to_jiffies(2000));
    > +
    > + return ret;

    return 0;

    > +}
    > +
    > +static void sip_recalc_credit_release(struct esp_sip *sip)
    > +{
    > + if (atomic_read(&sip->credit_status) == RECALC_CREDIT_ENABLE) {
    > + atomic_set(&sip->credit_status, RECALC_CREDIT_DISABLE);
    > + del_timer_sync(&sip->credit_timer);
    > + } else {
    > + dev_dbg(sip->epub->dev, "maybe bogus credit");
    > + }
    > +}
    > +
    > +static void sip_update_tx_credits(struct esp_sip *sip, u16 recycled_credits)
    > +{
    > + if (recycled_credits & 0x800) {
    > + atomic_set(&sip->tx_credits, (recycled_credits & 0x7ff));
    > + sip_recalc_credit_release(sip);
    > + } else {
    > + atomic_add(recycled_credits, &sip->tx_credits);
    > + }
    > +}
    > +
    > +void sip_trigger_txq_process(struct esp_sip *sip)
    > +{
    > + if (atomic_read(&sip->tx_credits) <= sip->credit_to_reserve + SIP_CTRL_CREDIT_RESERVE ||
    > + atomic_read(&sip->credit_status) == RECALC_CREDIT_ENABLE)
    > + return;
    > +
    > + if (sip_queue_may_resume(sip)) {
    > + /* wakeup upper queue only if we have sufficient credits */
    > + atomic_set(&sip->epub->txq_stopped, false);
    > + ieee80211_wake_queues(sip->epub->hw);
    > + } else if (atomic_read(&sip->epub->txq_stopped)) {
    > + dev_err(sip->epub->dev, "%s can't wake txq, credits: %d\n",
    > + __func__, atomic_read(&sip->tx_credits));
    > + }
    > +
    > + if (!skb_queue_empty(&sip->epub->txq)) {
    > + /* try to send out pkt already in sip queue once we have credits */
    > +#if !defined(FPGA_TXDATA)
    > + if (!sif_get_ate_config())
    > + ieee80211_queue_work(sip->epub->hw,
    > + &sip->epub->tx_work);
    > + else
    > + queue_work(sip->epub->esp_wkq, &sip->epub->tx_work);
    > +#else
    > + queue_work(sip->epub->esp_wkq, &sip->epub->tx_work);
    > +#endif
    > + }
    > +}
    > +
    > +static bool sip_ampdu_occupy_buf(struct esp_sip *sip,
    > + struct esp_rx_ampdu_len *ampdu_len)
    > +{
    > + return (!ampdu_len->substate ||
    > + esp_wmac_rxsec_error(ampdu_len->substate) ||
    > + (sip->dump_rpbm_err && ampdu_len->substate == RX_RPBM_ERR));
    > +}
    > +
    > +/* TODO: HARDCORE CLEANUP */
    > +
    > +static bool sip_rx_pkt_process(struct esp_sip *sip, struct sk_buff *skb)
    > +{
    > + struct sip_hdr *hdr;
    > + struct sk_buff *rskb;
    > + struct esp_mac_rx_ctrl *mac_ctrl, new_mac_ctrl;
    > + int remains_len, first_pkt_len, ret = 0, pkt_len_enc = 0, buf_len = 0,
    > + pulled_len = 0, pkt_num;
    > + u8 *bufptr;
    > + bool trigger_rxq = false, have_rxabort = false, have_goodpkt = false;
    > + struct esp_rx_ampdu_len *ampdu_len;
    > + static int pkt_dropped, pkt_total;
    > + static u8 frame_head[16];
    > + static u8 frame_buf_ttl;
    > +
    > + if (!skb)
    > + return trigger_rxq;
    > +
    > + hdr = (struct sip_hdr *)skb->data;
    > + bufptr = skb->data;
    > +
    > + if (hdr->h_credits & SIP_CREDITS_MASK)
    > + sip_update_tx_credits(sip, hdr->h_credits & SIP_CREDITS_MASK);
    > +
    > + hdr->h_credits &= ~SIP_CREDITS_MASK; /* clean credits in sip_hdr, prevent over-add */
    > +
    > + /* first pkt's length is stored in recycled_credits first 20 bits
    > + * config w3 [31:12]
    > + * repair hdr->len of first pkt
    > + */
    > + remains_len = hdr->len;
    > + first_pkt_len = hdr->h_credits >> 12;
    > + hdr->len = first_pkt_len;
    > +
    > + if (first_pkt_len > remains_len) {
    > + sip_recalc_credit_claim(sip, 0);
    > + show_buf((u8 *)hdr, first_pkt_len);

    This feels like an info leak. first_pkt_len comes from the network.

    > + ESSERT(0);
    > + goto _exit;
    > + }
    > +
    > + /* pkts handling, including the first pkt, should alloc new skb for each data pkt.
    > + * free the original whole skb after parsing is done.
    > + */
    > + while (remains_len) {
    > + if (remains_len < sizeof(struct sip_hdr)) {
    > + sip_recalc_credit_claim(sip, 0);
    > + ESSERT(0);
    > + show_buf((u8 *)hdr, 512);
    > + goto _exit;
    > + }
    > +
    > + hdr = (struct sip_hdr *)bufptr;
    > + if (hdr->len <= 0 || hdr->len & 3) {
    > + sip_recalc_credit_claim(sip, 0);
    > + show_buf((u8 *)hdr, 512);
    > + ESSERT(0);
    > + goto _exit;
    > + }
    > +
    > + if (unlikely(hdr->seq != sip->rxseq++)) {
    > + sip_recalc_credit_claim(sip, 0);
    > + dev_dbg(sip->epub->dev,
    > + "%s seq mismatch! got %u, expect %u\n",
    > + __func__, hdr->seq, sip->rxseq - 1);
    > + sip->rxseq = hdr->seq + 1;
    > + show_buf(bufptr, 32);
    > + ESSERT(0);
    > + }
    > +
    > + if (SIP_HDR_IS_CTRL(hdr)) {
    > + STRACE_RX_EVENT_INC();
    > +
    > + ret = sip_parse_events(sip, bufptr);
    > + skb_pull(skb, hdr->len);
    > + } else if (SIP_HDR_IS_DATA(hdr)) {
    > + STRACE_RX_DATA_INC();
    > + mac_ctrl = sip_parse_normal_mac_ctrl(skb, &pkt_len_enc,
    > + &buf_len,
    > + &pulled_len);
    > + rskb = sip_parse_data_rx_info(sip, skb, pkt_len_enc,
    > + buf_len, mac_ctrl,
    > + &pulled_len);
    > +
    > + if (!rskb)
    > + goto _move_on;
    > +
    > + if (likely(atomic_read(&sip->epub->wl.off) == 0)) {
    > + local_bh_disable();
    > + ieee80211_rx(sip->epub->hw, rskb);
    > + local_bh_enable();
    > + } else {
    > + /* still need go thro parsing as skb_pull should invoke */
    > + kfree_skb(rskb);
    > + }
    > + } else if (SIP_HDR_IS_AMPDU(hdr)) {
    > + ampdu_len = (struct esp_rx_ampdu_len *)(skb->data + hdr->len / sip->rx_blksz * sip->rx_blksz);
    > + dev_dbg(sip->epub->dev, "%s rx ampdu total len %u\n",
    > + __func__, hdr->len);
    > + if (skb->data != (u8 *)hdr) {
    > + printk("%p %p\n", skb->data, hdr);
    > + show_buf(skb->data, 512);
    > + show_buf((u8 *)hdr, 512);
    > + ESSERT(0);
    > + goto _exit;
    > + }
    > + mac_ctrl = sip_parse_normal_mac_ctrl(skb, NULL, NULL,
    > + &pulled_len);
    > + memcpy(&new_mac_ctrl, mac_ctrl,
    > + sizeof(struct esp_mac_rx_ctrl));
    > + mac_ctrl = &new_mac_ctrl;
    > + pkt_num = mac_ctrl->ampdu_cnt;
    > + dev_dbg(sip->epub->dev,
    > + "%s %d rx ampdu %u pkts, %d pkts dumped, first len %u\n",
    > + __func__, __LINE__,
    > + (unsigned int)((hdr->len % sip->rx_blksz) /
    > + sizeof(struct esp_rx_ampdu_len)),
    > + pkt_num, (unsigned int)ampdu_len->sublen);
    > +
    > + pkt_total += mac_ctrl->ampdu_cnt;
    > + while (pkt_num > 0) {
    > + dev_dbg(sip->epub->dev,
    > + "%s %d ampdu sub state %02x,\n",
    > + __func__, __LINE__,
    > + ampdu_len->substate);
    > +
    > + if (sip_ampdu_occupy_buf(sip, ampdu_len)) { //pkt is dumped
    > + rskb = sip_parse_data_rx_info(sip, skb,
    > + ampdu_len->sublen - FCS_LEN,
    > + 0,
    > + mac_ctrl,
    > + &pulled_len);
    > + if (!rskb) {
    > + ESSERT(0);
    > + goto _exit;
    > + }
    > +
    > + if (likely(atomic_read(&sip->epub->wl.off) == 0) &&
    > + (ampdu_len->substate == 0 ||
    > + ampdu_len->substate == RX_TKIPMIC_ERR ||
    > + (sip->sendup_rpbm_pkt &&
    > + ampdu_len->substate == RX_RPBM_ERR)) &&
    > + (sip->rxabort_fixed ||
    > + !have_rxabort)) {
    > + if (!have_goodpkt) {
    > + have_goodpkt = true;
    > + memcpy(frame_head,
    > + rskb->data,
    > + 16);
    > + frame_head[1] &= ~0x80;
    > + frame_buf_ttl = 3;
    > + }
    > + local_bh_disable();
    > + ieee80211_rx(sip->epub->hw,
    > + rskb);
    > + local_bh_enable();
    > + } else {
    > + kfree_skb(rskb);
    > + }
    > + } else {
    > + if (ampdu_len->substate == RX_ABORT) {
    > + u8 *a;
    > + have_rxabort = true;
    > + dev_dbg(sip->epub->dev,
    > + "rx abort %d %d\n",
    > + frame_buf_ttl, pkt_num);
    > + if (frame_buf_ttl &&
    > + !sip->rxabort_fixed) {
    > + struct esp_rx_ampdu_len *next_good_ampdu_len = ampdu_len + 1;
    > + a = frame_head;
    > + while (!sip_ampdu_occupy_buf(sip, next_good_ampdu_len)) {
    > + if (next_good_ampdu_len > ampdu_len + pkt_num - 1)
    > + break;
    > + next_good_ampdu_len++;
    > + }
    > + if (next_good_ampdu_len <= ampdu_len + pkt_num - 1) {
    > + bool b0, b10, b11;
    > + a = skb->data;
    > + b0 = memcmp(frame_head + 4, skb->data + 4, 12) == 0;
    > + b10 = memcmp(frame_head + 10, skb->data, 6) == 0;
    > + b11 = memcpy(frame_head + 11, skb->data, 5) == 0;
    > + if (b0 && !b10 &&
    > + !b11) {
    > + have_rxabort = false;
    > + } else if (!b0 &&
    > + b10 &&
    > + !b11) {
    > + skb_push(skb, 10);
    > + memcpy(skb->data,
    > + frame_head,
    > + 10);
    > + have_rxabort = false;
    > + pulled_len -= 10;
    > + } else if (!b0 && !b10 && b11) {
    > + skb_push(skb, 11);
    > + memcpy(skb->data,
    > + frame_head,
    > + 11);
    > + have_rxabort = false;
    > + pulled_len -= 11;
    > + }
    > + }
    > + }
    > + }
    > + pkt_dropped++;
    > + dev_dbg(sip->epub->dev,
    > + "%s ampdu dropped %d/%d\n",
    > + __func__, pkt_dropped,
    > + pkt_total);
    > + }
    > + pkt_num--;
    > + ampdu_len++;
    > + }
    > + if (frame_buf_ttl)
    > + frame_buf_ttl--;
    > + skb_pull(skb, hdr->len - pulled_len);
    > + } else {
    > + dev_err(sip->epub->dev, "unknown SIP HDR type\n");
    > + }
    > +
    > +_move_on:
    > + if (hdr->len < remains_len)
    > + remains_len -= hdr->len;
    > + else
    > + break;
    > + bufptr += hdr->len;
    > + }
    > +
    > +_exit:
    > + kfree_skb(skb);
    > +
    > + return trigger_rxq;
    > +}
    > +
    > +static void _sip_rxq_process(struct esp_sip *sip)
    > +{
    > + struct sk_buff *skb;
    > + bool sendup = false;
    > +
    > + while ((skb = skb_dequeue(&sip->rxq)))
    > + if (sip_rx_pkt_process(sip, skb))
    > + sendup = true;
    > +
    > + if (sendup)
    > + queue_work(sip->epub->esp_wkq, &sip->epub->sendup_work);
    > +
    > + /* probably tx_credit is updated, try txq */
    > + sip_trigger_txq_process(sip);
    > +}
    > +
    > +void sip_rxq_process(struct work_struct *work)
    > +{
    > + struct esp_sip *sip = container_of(work, struct esp_sip,
    > + rx_process_work);
    > +
    > + if (!sip) {
    > + ESSERT(0);
    > + return;
    > + }
    > +
    > + if (unlikely(atomic_read(&sip->state) == SIP_SEND_INIT)) {
    > + sip_send_chip_init(sip);
    > + atomic_set(&sip->state, SIP_WAIT_BOOTUP);
    > + return;
    > + }
    > +
    > + mutex_lock(&sip->rx_mtx);
    > + _sip_rxq_process(sip);
    > + mutex_unlock(&sip->rx_mtx);
    > +}
    > +
    > +static inline void sip_rx_pkt_enqueue(struct esp_sip *sip, struct sk_buff *skb)
    > +{
    > + skb_queue_tail(&sip->rxq, skb);
    > +}
    > +
    > +static u32 sip_rx_count;
    > +
    > +int sip_rx(struct esp_pub *epub)
    > +{
    > + struct sip_hdr *shdr;
    > + struct esp_sip *sip = epub->sip;
    > + struct sk_buff *first_skb, *rx_skb;
    > + u8 *rx_buf;
    > + u32 rx_blksz, first_sz;
    > + int err;
    > + u8 raw_seq;
    > +
    > + if (likely(sif_get_ate_config() != 1)) {
    > + raw_seq = sif_get_regs(epub)->intr_raw & 0xff;
    > +
    > + if (raw_seq != sip->to_host_seq) {
    > + if (raw_seq == sip->to_host_seq + 1) { /* when last read pkt crc err, this situation may occur, but raw_seq mustn't < to_host_Seq */
    > + sip->to_host_seq = raw_seq;
    > + dev_dbg(epub->dev,
    > + "warn: to_host_seq reg 0x%02x, seq 0x%02x",
    > + raw_seq, sip->to_host_seq);
    > + } else {
    > + dev_err(epub->dev,
    > + "err: to_host_seq reg 0x%02x, seq 0x%02x",
    > + raw_seq, sip->to_host_seq);
    > + err = 0;
    > + goto _err;

    This function uses a mix of direct returns and goto _err. Just use
    direct returns unless there is a good reason in the present (not future)
    for the goto. It just hurts readability to have to scroll 2 pages down
    to see what the goto does. "return 0;" is much quicker.

    > + }
    > + }
    > + }
    > +
    > + /* first read one block out, if we luck enough, that's it
    > + *
    > + * To make design as simple as possible, we allocate skb(s)
    > + * separately for each sif read operation to avoid global
    > + * read_buf_pointe access. It coule be optimized late.
    > + */
    > +
    > + first_sz = sif_get_regs(epub)->config_w0;
    > + rx_blksz = sif_get_blksz(epub);
    > + first_skb = __dev_alloc_skb(roundup(first_sz, rx_blksz), GFP_KERNEL);
    > +
    > + if (!first_skb) {
    > + sif_unlock_bus(epub);
    > + err = 0;
    > + goto _err;
    > + }
    > +
    > + rx_buf = skb_put(first_skb, first_sz);
    > +
    > + err = esp_common_read(epub, rx_buf, first_sz, ESP_SIF_NOSYNC, false);
    > + sip_rx_count++;
    > + if (unlikely(err)) {
    > + dev_err(epub->dev, " first read err %d %d\n", err,
    > + sif_get_regs(epub)->config_w0);
    > + kfree_skb(first_skb);
    > + sif_unlock_bus(epub);
    > + goto _err;


    I feel like we should create a error goto the unlocks and frees
    first_skb.

    > + }
    > +
    > + shdr = (struct sip_hdr *)rx_buf;
    > + if (SIP_HDR_IS_CTRL(shdr) && shdr->c_evtid == SIP_EVT_SLEEP) {
    > + atomic_set(&sip->epub->ps.state, ESP_PM_ON);
    > + }
    > +
    > + if (likely(sif_get_ate_config() != 1))
    > + sip->to_host_seq++;
    > +
    > + if (shdr->len & 3) {
    > + dev_err(epub->dev, "shdr->len[%d] error\n", shdr->len);
    > + kfree_skb(first_skb);
    > + sif_unlock_bus(epub);
    > + err = -EIO;
    > + goto _err;
    > + }
    > +
    > + if (shdr->len != first_sz) {
    > + dev_err(epub->dev, "shdr->len[%d] first_size[%d] error\n",
    > + shdr->len, first_sz);
    > + kfree_skb(first_skb);
    > + sif_unlock_bus(epub);
    > + err = -EIO;
    > + goto _err;
    > + } else {
    > + sif_unlock_bus(epub);
    > + skb_trim(first_skb, shdr->len);
    > + dev_dbg(epub->dev, "first_skb only\n");
    > +
    > + rx_skb = first_skb;
    > + }
    > +
    > + if (atomic_read(&sip->state) == SIP_STOP) {
    > + kfree_skb(rx_skb);
    > + dev_err(epub->dev, "rx packet while sip stopped\n");

    We don't unlock on this path?

    > + return 0;
    > + }
    > +
    > + sip_rx_pkt_enqueue(sip, rx_skb);
    > + queue_work(sip->epub->esp_wkq, &sip->rx_process_work);
    > +
    > +_err:
    > + return err;
    > +}
    > +
    > +int sip_post_init(struct esp_sip *sip, struct sip_evt_bootup2 *bevt)
    > +{
    > + struct esp_pub *epub;
    > + u8 mac_id = bevt->mac_addr[0];
    > + int mac_index = 0, i;
    > +
    > + if (!sip) {
    > + ESSERT(0);
    > + return -EINVAL;
    > + }
    > +
    > + epub = sip->epub;
    > +
    > + sip->tx_aggr_write_ptr = sip->tx_aggr_buf;
    > + sip->tx_blksz = bevt->tx_blksz;
    > + sip->rx_blksz = bevt->rx_blksz;
    > + sip->credit_to_reserve = bevt->credit_to_reserve;
    > + sip->dump_rpbm_err = bevt->options & SIP_DUMP_RPBM_ERR;
    > + sip->rxabort_fixed = bevt->options & SIP_RXABORT_FIXED;
    > + sip->support_bgscan = bevt->options & SIP_SUPPORT_BGSCAN;
    > + sip->sendup_rpbm_pkt = 0;
    > +
    > + /* print out MAC addr... */
    > + memcpy(epub->mac_addr, bevt->mac_addr, ETH_ALEN);
    > + for (i = 0;
    > + i < sizeof(esp_mac_prefix_table) / sizeof(struct esp_mac_prefix);
    > + i++)
    > + if (esp_mac_prefix_table[i].mac_index == mac_id) {
    > + mac_index = i;
    > + break;
    > + }
    > +
    > + epub->mac_addr[0] = esp_mac_prefix_table[mac_index].mac_addr_prefix[0];
    > + epub->mac_addr[1] = esp_mac_prefix_table[mac_index].mac_addr_prefix[1];
    > + epub->mac_addr[2] = esp_mac_prefix_table[mac_index].mac_addr_prefix[2];
    > +
    > + atomic_set(&sip->noise_floor, bevt->noise_floor);
    > +
    > + sip_recalc_credit_init(sip);
    > +
    > + return 0;
    > +}
    > +
    > +/* write pkts in aggr buf to target memory */
    > +static void sip_write_pkts(struct esp_sip *sip, int pm_state)
    > +{
    > + int tx_aggr_len, err;
    > + struct sip_hdr *first_shdr;
    > +
    > + tx_aggr_len = sip->tx_aggr_write_ptr - sip->tx_aggr_buf;
    > + if (tx_aggr_len < sizeof(struct sip_hdr)) {
    > + dev_err(sip->epub->dev, "[tx_aggr_len] %d < sizeof(sip_hdr)\n",
    > + tx_aggr_len);
    > + ESSERT(0);
    > + return;
    > + }
    > +
    > + if (tx_aggr_len & 0x3) {
    > + ESSERT(0);
    > + return;
    > + }
    > +
    > + first_shdr = (struct sip_hdr *)sip->tx_aggr_buf;
    > +
    > + if (atomic_read(&sip->tx_credits) <= SIP_CREDITS_LOW_THRESHOLD)
    > + first_shdr->fc[1] |= SIP_HDR_F_NEED_CRDT_RPT;
    > +
    > + /* still use lock bus instead of sif_lldesc_write_sync since we want to protect several global varibles assignments */
    > + sif_lock_bus(sip->epub);
    > +
    > + err = esp_common_write(sip->epub, sip->tx_aggr_buf, tx_aggr_len,
    > + ESP_SIF_NOSYNC);
    > + if (err)
    > + dev_err(sip->epub->dev, "error while writing pkts: %d\n", err);
    > +
    > + sip->tx_aggr_write_ptr = sip->tx_aggr_buf;
    > + sip->tx_tot_len = 0;
    > +
    > + sif_unlock_bus(sip->epub);
    > +}
    > +
    > +/* setup sip header and tx info, copy pkt into aggr buf */
    > +static int sip_pack_pkt(struct esp_sip *sip, struct sk_buff *skb, int *pm_state)
    > +{
    > + struct ieee80211_tx_info *itx_info;
    > + struct sip_hdr *shdr;
    > + struct ieee80211_hdr *wh;
    > + struct esp_vif *evif;
    > + struct esp_node *node;
    > + u32 tx_len, offset;
    > + bool is_data = true;
    > + u8 sta_index;
    > + int alg;
    > +
    > + itx_info = IEEE80211_SKB_CB(skb);
    > + if (itx_info->flags == 0xffffffff) {
    > + shdr = (struct sip_hdr *)skb->data;
    > + is_data = false;
    > + tx_len = skb->len;
    > + } else {
    > + wh = (struct ieee80211_hdr *)skb->data;
    > + evif = (struct esp_vif *)itx_info->control.vif->drv_priv;
    > + /* update sip header */
    > + shdr = (struct sip_hdr *)sip->tx_aggr_write_ptr;
    > +
    > + shdr->fc[0] = 0;
    > + shdr->fc[1] = 0;
    > +
    > + if (itx_info->flags & IEEE80211_TX_CTL_AMPDU)
    > + SIP_HDR_SET_TYPE(shdr->fc[0], SIP_DATA_AMPDU);
    > + else
    > + SIP_HDR_SET_TYPE(shdr->fc[0], SIP_DATA);
    > +
    > + if (!evif->epub) {
    > + sip_tx_status_report(sip, skb, itx_info, false);
    > + atomic_dec(&sip->tx_data_pkt_queued);
    > + return -EINVAL;
    > + }
    > +
    > + /* make room for encrypted pkt */
    > + if (itx_info->control.hw_key) {
    > + alg = esp_cipher2alg(itx_info->control.hw_key->cipher);
    > + if (unlikely(alg == -1)) {
    > + sip_tx_status_report(sip, skb, itx_info, false);
    > + atomic_dec(&sip->tx_data_pkt_queued);
    > + return -1;
    > + }
    > +
    > + shdr->d_enc_flag = alg + 1;
    > + shdr->d_hw_kid = itx_info->control.hw_key->hw_key_idx |
    > + (evif->index << 7);
    > + } else {
    > + shdr->d_enc_flag = 0;
    > + shdr->d_hw_kid = evif->index << 7 | evif->index;
    > + }
    > +
    > + /* update sip tx info */
    > + node = esp_get_node_by_addr(sip->epub, wh->addr1);
    > + if (node)
    > + sta_index = node->index;
    > + else
    > + sta_index = ESP_PUB_MAX_STA + 1;
    > +
    > + SIP_HDR_SET_IFIDX(shdr->fc[0], evif->index << 3 | sta_index);
    > + shdr->d_p2p = itx_info->control.vif->p2p;
    > +
    > + if (evif->index == 1)
    > + shdr->d_p2p = 1;
    > +
    > + shdr->d_ac = skb_get_queue_mapping(skb);
    > + shdr->d_tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
    > +
    > + wh = (struct ieee80211_hdr *)skb->data;
    > +
    > + if (ieee80211_is_mgmt(wh->frame_control)) {
    > + /* addba/delba/bar may use different tid/ac */
    > + if (shdr->d_ac == WME_AC_VO)
    > + shdr->d_tid = 7;
    > +
    > + if (ieee80211_is_beacon(wh->frame_control)) {
    > + shdr->d_tid = 8;
    > + shdr->d_ac = 4;
    > + }
    > + }
    > +
    > + if (check_ac_tid(skb->data, shdr->d_ac, shdr->d_tid)) {
    > + shdr->d_ac = WME_AC_BE;
    > + shdr->d_tid = 0;
    > + }
    > +
    > + /* make sure data is start at 4 bytes aligned addr. */
    > + offset = roundup(sizeof(struct sip_hdr), 4);
    > +
    > + if (SIP_HDR_IS_AMPDU(shdr)) {
    > + memset(sip->tx_aggr_write_ptr + offset, 0,
    > + sizeof(struct esp_tx_ampdu_entry));
    > + offset += roundup(sizeof(struct esp_tx_ampdu_entry), 4);
    > + }
    > +
    > + tx_len = offset + skb->len;
    > + shdr->len = tx_len; /* actual len */
    > + }
    > +
    > + shdr->seq = sip->txseq++;
    > +
    > + /* copy skb to aggr buf */
    > + memcpy(sip->tx_aggr_write_ptr + offset, skb->data, skb->len);
    > +
    > + if (is_data) {
    > + spin_lock_bh(&sip->epub->tx_lock);
    > + sip->txdataseq = shdr->seq;
    > + spin_unlock_bh(&sip->epub->tx_lock);
    > +
    > + /* fake a tx_status and report to mac80211 stack to speed up tx, may affect
    > + * 1) rate control (now it's all in target, so should be OK)
    > + * 2) ps mode, mac80211 want to check ACK of ps/nulldata to see if AP is awake
    > + * 3) BAR, mac80211 do BAR by checking ACK
    > + *
    > + * XXX: need to adjust for 11n, e.g. report tx_status according to BA received in target
    > + */
    > + sip_tx_status_report(sip, skb, itx_info, true);
    > + atomic_dec(&sip->tx_data_pkt_queued);
    > +
    > + STRACE_TX_DATA_INC();
    > + } else {
    > + /* check pm state here */
    > +
    > + /* no need to hold ctrl skb */
    > + sip_free_ctrl_skbuff(sip, skb);
    > + STRACE_TX_CMD_INC();
    > + }
    > +
    > + /* TBD: roundup here or whole aggr-buf */
    > + tx_len = roundup(tx_len, sip->tx_blksz);
    > +
    > + sip->tx_aggr_write_ptr += tx_len;
    > + sip->tx_tot_len += tx_len;
    > +
    > + return 0;
    > +}
    > +
    > +static void sip_tx_status_report(struct esp_sip *sip, struct sk_buff *skb,
    > + struct ieee80211_tx_info *tx_info,
    > + bool success)
    > +{
    > + struct ieee80211_hdr *wh;
    > + struct esp_node *node;
    > + struct esp_tx_tid *tid;
    > + struct ieee80211_sta *sta;
    > + u8 tidno;
    > +
    > + if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
    > + if (likely(success))
    > + tx_info->flags |= IEEE80211_TX_STAT_ACK;
    > + else
    > + tx_info->flags &= ~IEEE80211_TX_STAT_ACK;
    > +
    > + /* manipulate rate status... */
    > + tx_info->status.rates[0].idx = 11;
    > + tx_info->status.rates[0].count = 1;
    > + tx_info->status.rates[0].flags = 0;
    > + tx_info->status.rates[1].idx = -1;
    > + } else {
    > + tx_info->flags |= IEEE80211_TX_STAT_AMPDU |
    > + IEEE80211_TX_STAT_ACK;
    > + tx_info->status.ampdu_len = 1;
    > + tx_info->status.ampdu_ack_len = 1;
    > +
    > + /* manipulate rate status... */
    > + tx_info->status.rates[0].idx = 7;
    > + tx_info->status.rates[0].count = 1;
    > + tx_info->status.rates[0].flags = IEEE80211_TX_RC_MCS |
    > + IEEE80211_TX_RC_SHORT_GI;
    > + tx_info->status.rates[1].idx = -1;
    > + }
    > +
    > + if (!mod_support_no_txampdu() &&
    > + cfg80211_get_chandef_type(&sip->epub->hw->conf.chandef) != NL80211_CHAN_NO_HT) {
    > + wh = (struct ieee80211_hdr *)skb->data;
    > +
    > + if (ieee80211_is_data_qos(wh->frame_control) &&
    > + !(IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_AMPDU)) {
    > + tidno = ieee80211_get_qos_ctl(wh)[0] &
    > + IEEE80211_QOS_CTL_TID_MASK;
    > +
    > + node = esp_get_node_by_addr(sip->epub, wh->addr1);
    > + if (!node || !node->sta)
    > + goto _exit;
    > +
    > + sta = node->sta;
    > + tid = &node->tid[tidno];
    > + if (!tid) {
    > + ESSERT(0);
    > + goto _exit;
    > + }
    > +
    > + spin_lock_bh(&sip->epub->tx_ampdu_lock);
    > +
    > + if (tid->state == ESP_TID_STATE_INIT &&
    > + TID_TO_AC(tidno) != WME_AC_VO && tid->cnt >= 10) {
    > + tid->state = ESP_TID_STATE_TRIGGER;
    > + dev_dbg(sip->epub->dev,
    > + "start tx ba session,addr:%pM,tid:%u\n",
    > + wh->addr1, tidno);
    > + spin_unlock_bh(&sip->epub->tx_ampdu_lock);
    > + ieee80211_start_tx_ba_session(sta, tidno, 0);
    > + } else {
    > + if (tid->state == ESP_TID_STATE_INIT)
    > + tid->cnt++;
    > + else
    > + tid->cnt = 0;
    > +
    > + spin_unlock_bh(&sip->epub->tx_ampdu_lock);
    > + }
    > + }
    > + }
    > +
    > +_exit:
    > + ieee80211_tx_status(sip->epub->hw, skb);
    > +}
    > +
    > +/* NB: this routine should be locked when calling
    > + */
    > +void sip_txq_process(struct esp_pub *epub)
    > +{
    > + struct sk_buff *skb;
    > + struct sip_hdr *hdr;
    > + struct esp_sip *sip = epub->sip;
    > + struct ieee80211_tx_info *itx_info;
    > + u32 pkt_len, tx_len = 0;
    > + int blknum = 0, pm_state = 0;
    > + bool queued_back = false, out_of_credits = false;
    > +
    > + while ((skb = skb_dequeue(&epub->txq))) {
    > + /* cmd skb->len does not include sip_hdr too */
    > + pkt_len = skb->len;
    > + itx_info = IEEE80211_SKB_CB(skb);
    > + if (itx_info->flags != 0xffffffff) {
    > + pkt_len += roundup(sizeof(struct sip_hdr), 4);
    > + if (itx_info->flags & IEEE80211_TX_CTL_AMPDU)
    > + pkt_len += roundup(sizeof(struct esp_tx_ampdu_entry),
    > + 4);
    > + }
    > +
    > + /* current design simply requires every sip_hdr must be at the begin of mblk, that definitely
    > + * need to be optimized, e.g. calculate remain length in the previous mblk, if it larger than
    > + * certain threshold (e.g, whole pkt or > 50% of pkt or 2 x sizeof(struct sip_hdr), append pkt
    > + * to the previous mblk. This might be done in sip_pack_pkt()
    > + */
    > + pkt_len = roundup(pkt_len, sip->tx_blksz);
    > + blknum = pkt_len / sip->tx_blksz;
    > +
    > + /*
    > + * FIXME: Empirical delay. Without this delay, the connection to
    > + * a WiFi network crashes the kernel (sometimes at the second
    > + * connection).
    > + */
    > + udelay(2000);
    > +
    > + if (unlikely(atomic_read(&sip->credit_status) == RECALC_CREDIT_ENABLE)) { /* need recalc credit */
    > + hdr = (struct sip_hdr *)skb->data;
    > + itx_info = IEEE80211_SKB_CB(skb);
    > +
    > + if (!(itx_info->flags == 0xffffffff &&
    > + SIP_HDR_GET_TYPE(hdr->fc[0]) == SIP_CTRL &&
    > + hdr->c_cmdid == SIP_CMD_RECALC_CREDIT &&
    > + blknum <= atomic_read(&sip->tx_credits) - sip->credit_to_reserve)) { /* except cmd recalc credit */
    > + dev_dbg(epub->dev, "recalc credits!\n");
    > + STRACE_TX_OUT_OF_CREDIT_INC();
    > + queued_back = true;
    > + out_of_credits = true;
    > + break;
    > + }
    > + } else {
    > + if (unlikely(blknum > (atomic_read(&sip->tx_credits) - sip->credit_to_reserve - SIP_CTRL_CREDIT_RESERVE))) {
    > + itx_info = IEEE80211_SKB_CB(skb);
    > + if (itx_info->flags == 0xffffffff) { /* priv ctrl pkt */
    > + if (blknum > atomic_read(&sip->tx_credits) - sip->credit_to_reserve) {
    > + dev_dbg(epub->dev,
    > + "%s cmd pkt out of credits!\n",
    > + __func__);
    > + STRACE_TX_OUT_OF_CREDIT_INC();
    > + queued_back = true;
    > + out_of_credits = true;
    > + break;
    > + }
    > + } else {
    > + dev_dbg(epub->dev,
    > + "%s out of credits!\n",
    > + __func__);
    > + STRACE_TX_OUT_OF_CREDIT_INC();
    > + queued_back = true;
    > + out_of_credits = true;
    > + break;
    > + }
    > + }
    > + }
    > +
    > + tx_len += pkt_len;
    > + if (tx_len >= SIP_TX_AGGR_BUF_SIZE) {
    > + /* do we need to have limitation likemax 8 pkts in a row? */
    > + dev_dbg(epub->dev, "%s too much pkts in one shot!\n",
    > + __func__);
    > + STRACE_TX_ONE_SHOT_INC();
    > + tx_len -= pkt_len;
    > + queued_back = true;
    > + break;
    > + }
    > +
    > + if (sip_pack_pkt(sip, skb, &pm_state) != 0) {
    > + /* wrong pkt, won't send to target */
    > + tx_len -= pkt_len;
    > + continue;
    > + }
    > +
    > + atomic_sub(blknum, &sip->tx_credits);
    > + /*
    > + * FIXME: Empirical delay. Without this delay, the connection to
    > + * a WiFi network crashes the kernel (sometimes at the second
    > + * connection).
    > + */
    > + udelay(2000);
    > +
    > + }
    > +
    > + if (queued_back)
    > + skb_queue_head(&epub->txq, skb);
    > +
    > + if (atomic_read(&sip->state) == SIP_STOP
    > +#ifdef HOST_RESET_BUG
    > + || atomic_read(&epub->wl.off) == 1
    > +#endif
    > + ) {
    > + queued_back = 1;
    > + tx_len = 0;
    > + }
    > +
    > + if (tx_len)
    > + sip_write_pkts(sip, pm_state);
    > +
    > + if (queued_back && !out_of_credits)
    > + /* skb pending, do async process again */
    > + sip_trigger_txq_process(sip);
    > +}
    > +
    > +#ifndef NO_WMM_DUMMY
    > +static struct esp_80211_wmm_param_element esp_wmm_param = {
    > + .oui = {0x00, 0x50, 0xf2},
    > + .oui_type = 0x02,
    > + .oui_subtype = 0x01,
    > + .version = 0x01,
    > + .qos_info = 0x00,
    > + .reserved = 0x00,
    > + .ac = {
    > + {
    > + .aci_aifsn = 0x03,
    > + .cw = 0xa4,
    > + .txop_limit = 0x0000,
    > + },
    > + {
    > + .aci_aifsn = 0x27,
    > + .cw = 0xa4,
    > + .txop_limit = 0x0000,
    > + },
    > + {
    > + .aci_aifsn = 0x42,
    > + .cw = 0x43,
    > + .txop_limit = 0x005e,
    > + },
    > + {
    > + .aci_aifsn = 0x62,
    > + .cw = 0x32,
    > + .txop_limit = 0x002f,
    > + },
    > + },
    > +};
    > +
    > +static int esp_add_wmm(struct sk_buff *skb)
    > +{
    > + u8 *p;
    > + int flag = 0;
    > + int remain_len;
    > + int base_len;
    > + int len;
    > + struct ieee80211_mgmt *mgmt;
    > + struct ieee80211_hdr *wh;
    > +
    > + if (!skb)
    > + return -1;
    > +
    > + wh = (struct ieee80211_hdr *)skb->data;
    > + mgmt = (struct ieee80211_mgmt *)((u8 *)skb->data);
    > +
    > + if (ieee80211_is_assoc_resp(wh->frame_control)) {
    > + p = mgmt->u.assoc_resp.variable;
    > + base_len = (u8 *)mgmt->u.assoc_resp.variable - (u8 *)mgmt;
    > + } else if (ieee80211_is_reassoc_resp(wh->frame_control)) {
    > + p = mgmt->u.reassoc_resp.variable;
    > + base_len = (u8 *)mgmt->u.reassoc_resp.variable - (u8 *)mgmt;
    > + } else if (ieee80211_is_probe_resp(wh->frame_control)) {
    > + p = mgmt->u.probe_resp.variable;
    > + base_len = (u8 *)mgmt->u.probe_resp.variable - (u8 *)mgmt;
    > + } else if (ieee80211_is_beacon(wh->frame_control)) {
    > + p = mgmt->u.beacon.variable;
    > + base_len = (u8 *)mgmt->u.beacon.variable - (u8 *)mgmt;
    > + } else {
    > + return 1;
    > + }
    > +
    > + remain_len = skb->len - base_len;
    > +
    > + while (remain_len > 0) {
    > + if (*p == 0xdd && *(p + 5) == 0x02) //wmm type
    > + return 0;
    > + else if (*p == 0x2d) //has ht cap
    > + flag = 1;
    > +
    > + len = *(++p);
    > + p += (len + 1);
    > + remain_len -= (len + 2);
    > + }
    > +
    > + if (remain_len < 0)
    > + return -2;

    -2 is not a valid error code.

    > +
    > + if (flag == 1) {
    > + skb_put(skb, 2 + sizeof(esp_wmm_param));
    > +
    > + memset(p, 0xdd, sizeof(u8));
    > + memset(p + 1, sizeof(esp_wmm_param), sizeof(u8));
    > + memcpy(p + 2, &esp_wmm_param, sizeof(esp_wmm_param));
    > + }
    > +
    > + return 0;
    > +}
    > +#endif /* NO_WMM_DUMMY */
    > +
    > +/* parse mac_rx_ctrl and return length */
    > +static int sip_parse_mac_rx_info(struct esp_sip *sip,
    > + struct esp_mac_rx_ctrl *mac_ctrl,
    > + struct sk_buff *skb)
    > +{
    > + struct ieee80211_rx_status *rx_status;
    > + struct ieee80211_hdr *hdr;
    > + struct ieee80211_hdr *wh;
    > +
    > + rx_status = IEEE80211_SKB_RXCB(skb);
    > + rx_status->freq = esp_ieee2mhz(mac_ctrl->channel);
    > + rx_status->signal = mac_ctrl->rssi + mac_ctrl->noise_floor; /* snr actually, need to offset noise floor e.g. -85 */
    > +
    > + hdr = (struct ieee80211_hdr *)skb->data;
    > + if (mac_ctrl->damatch0 == 1 && mac_ctrl->bssidmatch0 == 1 && /*match bssid and da, but beacon package contain other bssid */
    > + !strncmp(hdr->addr2, sip->epub->wl.bssid, ETH_ALEN)) { /* force match addr2 */
    > + if (++signal_loop >= SIGNAL_COUNT) {
    > + avg_signal += rx_status->signal;
    > + avg_signal /= SIGNAL_COUNT;
    > + rx_status->signal = avg_signal + 5;
    > + old_signal = rx_status->signal;
    > + signal_loop = 0;
    > + avg_signal = 0;
    > + } else {
    > + avg_signal += rx_status->signal;
    > + rx_status->signal = old_signal;
    > + }
    > + }
    > +
    > + rx_status->antenna = 0; /* one antenna for now */
    > + rx_status->band = NL80211_BAND_2GHZ;
    > + rx_status->flag = RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED;
    > + if (mac_ctrl->sig_mode) {
    > + rx_status->encoding |= RX_ENC_HT;
    > + rx_status->rate_idx = mac_ctrl->MCS;
    > + if (mac_ctrl->SGI)
    > + rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
    > + } else {
    > + rx_status->rate_idx = esp_wmac_rate2idx(mac_ctrl->rate);
    > + }
    > +
    > + if (mac_ctrl->rxend_state == RX_FCS_ERR)
    > + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
    > +
    > + /* Mic error frame flag */
    > + if (mac_ctrl->rxend_state == RX_TKIPMIC_ERR ||
    > + mac_ctrl->rxend_state == RX_CCMPMIC_ERR) {
    > + if (atomic_read(&sip->epub->wl.tkip_key_set) == 1) {
    > + rx_status->flag |= RX_FLAG_MMIC_ERROR;
    > + atomic_set(&sip->epub->wl.tkip_key_set, 0);
    > + printk("mic err\n");
    > + } else {
    > + printk("mic err discard\n");
    > + }
    > + }
    > +
    > + wh = (struct ieee80211_hdr *)((u8 *)skb->data);
    > +
    > +#ifndef NO_WMM_DUMMY
    > + if (ieee80211_is_mgmt(wh->frame_control))
    > + esp_add_wmm(skb);
    > +#endif
    > +
    > + /* some kernel e.g. 3.0.8 wrongly handles non-encrypted pkt like eapol */
    > + if (ieee80211_is_data(wh->frame_control)) {
    > + if (!ieee80211_has_protected(wh->frame_control))
    > + rx_status->flag |= RX_FLAG_IV_STRIPPED;
    > + else if (!atomic_read(&sip->epub->wl.ptk_cnt))
    > + rx_status->flag |= RX_FLAG_IV_STRIPPED;
    > + }
    > +
    > + return 0;
    > +}
    > +
    > +static struct esp_mac_rx_ctrl *sip_parse_normal_mac_ctrl(struct sk_buff *skb,
    > + int *pkt_len_enc,
    > + int *buf_len,
    > + int *pulled_len)
    > +{
    > + struct sip_hdr *hdr = (struct sip_hdr *)skb->data;
    > + struct esp_mac_rx_ctrl *mac_ctrl;
    > + int len_in_hdr = hdr->len;
    > +
    > + ESSERT(skb);
    > + ESSERT(skb->len > SIP_MIN_DATA_PKT_LEN);
    > +
    > + skb_pull(skb, sizeof(struct sip_hdr));
    > + *pulled_len += sizeof(struct sip_hdr);
    > + mac_ctrl = (struct esp_mac_rx_ctrl *)skb->data;
    > + if (!mac_ctrl->aggregation) {
    > + ESSERT(pkt_len_enc);
    > + ESSERT(buf_len);
    > + *pkt_len_enc = (mac_ctrl->sig_mode ? mac_ctrl->HT_length : mac_ctrl->legacy_length) - FCS_LEN;
    > + *buf_len = len_in_hdr - sizeof(struct sip_hdr) -
    > + sizeof(struct esp_mac_rx_ctrl);
    > + }
    > +
    > + skb_pull(skb, sizeof(struct esp_mac_rx_ctrl));
    > + *pulled_len += sizeof(struct esp_mac_rx_ctrl);
    > +
    > + return mac_ctrl;
    > +}
    > +
    > +/* for one MPDU (including subframe in AMPDU) */
    > +static struct sk_buff *sip_parse_data_rx_info(struct esp_sip *sip,
    > + struct sk_buff *skb,
    > + int pkt_len_enc, int buf_len,
    > + struct esp_mac_rx_ctrl *mac_ctrl,
    > + int *pulled_len)
    > +{
    > + /* | mac_rx_ctrl | real_data_payload | ampdu_entries | */
    > + struct sk_buff *rskb;
    > + struct ieee80211_hdr *wh;
    > + int pkt_len, ret;
    > +
    > + if (mac_ctrl->aggregation) {
    > + wh = (struct ieee80211_hdr *)skb->data;
    > + pkt_len = pkt_len_enc;
    > + if (ieee80211_has_protected(wh->frame_control)) //ampdu, it is CCMP enc
    > + pkt_len -= 8;
    > +
    > + buf_len = roundup(pkt_len, 4);
    > + } else {
    > + pkt_len = buf_len - 3 + ((pkt_len_enc - 1) & 0x3);
    > + }
    > +
    > +#ifndef NO_WMM_DUMMY
    > + rskb = __dev_alloc_skb(pkt_len_enc + sizeof(esp_wmm_param) + 2,
    > + GFP_ATOMIC);
    > +#else
    > + rskb = __dev_alloc_skb(pkt_len_enc, GFP_ATOMIC);
    > +#endif /* NO_WMM_DUMMY */
    > + if (unlikely(!rskb)) {

    Remove all likely/unlikely.

    > + dev_err(sip->epub->dev, "no mem for rskb\n");

    No need for this printk.

    > + return NULL;
    > + }
    > +
    > + skb_put(rskb, pkt_len_enc);
    > +
    > + memcpy(rskb->data, skb->data, pkt_len);
    > +
    > + if (pkt_len_enc > pkt_len)
    > + memset(rskb->data + pkt_len, 0, pkt_len_enc - pkt_len);
    > +
    > + /* strip out current pkt, move to the next one */
    > + skb_pull(skb, buf_len);
    > + *pulled_len += buf_len;
    > +
    > + ret = sip_parse_mac_rx_info(sip, mac_ctrl, rskb);
    > + if (ret == -1 && !mac_ctrl->aggregation) {


    sip_parse_mac_rx_info() never returns -1. Also -1 is not a the correct
    error code.

    > + kfree_skb(rskb);
    > + return NULL;
    > + }
    > +
    > + return rskb;
    > +}
    > +
    > +struct esp_sip *sip_attach(struct esp_pub *epub)
    > +{
    > + struct esp_sip *sip;
    > + struct sip_pkt *pkt;
    > + int i, po;
    > +
    > + sip = kzalloc(sizeof(*sip), GFP_KERNEL);
    > + if (!sip) {
    > + dev_dbg(epub->dev, "no mem for sip!\n");
    > + goto _err_sip;

    No need for the error message or the goto.

    > + }
    > +
    > + /* Finding the smalest available space to allocate this variavle */
    > + po = get_order(SIP_TX_AGGR_BUF_SIZE);
    > +
    > + sip->tx_aggr_buf = (u8 *)__get_free_pages(GFP_ATOMIC, po);
    > + if (!sip->tx_aggr_buf) {
    > + dev_err(epub->dev, "no mem for tx_aggr_buf!\n");
    > + goto _err_aggr;
    > + }
    > +
    > + spin_lock_init(&sip->lock);
    > +
    > + INIT_LIST_HEAD(&sip->free_ctrl_txbuf);
    > + INIT_LIST_HEAD(&sip->free_ctrl_rxbuf);
    > +
    > + for (i = 0; i < SIP_CTRL_BUF_N; i++) {
    > + pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
    > + if (!pkt)
    > + goto _err_pkt;
    > +
    > + pkt->buf_begin = kzalloc(SIP_CTRL_BUF_SZ, GFP_KERNEL);
    > + if (!pkt->buf_begin) {
    > + kfree(pkt);
    > + pkt = NULL;

    No need to set "pkt" to NULL

    > + goto _err_pkt;
    > + }
    > +
    > + pkt->buf_len = SIP_CTRL_BUF_SZ;
    > + pkt->buf = pkt->buf_begin;
    > +
    > + if (i < SIP_CTRL_TXBUF_N)
    > + list_add_tail(&pkt->list, &sip->free_ctrl_txbuf);
    > + else
    > + list_add_tail(&pkt->list, &sip->free_ctrl_rxbuf);
    > + }
    > +
    > + mutex_init(&sip->rx_mtx);
    > + skb_queue_head_init(&sip->rxq);
    > + INIT_WORK(&sip->rx_process_work, sip_rxq_process);
    > +
    > + sip->epub = epub;
    > + atomic_set(&sip->noise_floor, -96);
    > +
    > + atomic_set(&sip->state, SIP_INIT);
    > + atomic_set(&sip->tx_credits, 0);
    > +
    > + if (!sip->rawbuf) {
    > + sip->rawbuf = kzalloc(SIP_BOOT_BUF_SIZE, GFP_KERNEL);
    > + if (!sip->rawbuf) {
    > + dev_err(epub->dev, "no mem for rawbuf!\n");
    > + goto _err_pkt;
    > + }
    > + }
    > +
    > + atomic_set(&sip->state, SIP_PREPARE_BOOT);
    > +
    > + return sip;
    > +
    > +_err_pkt:
    > + sip_free_init_ctrl_buf(sip);
    > +
    > + if (sip->tx_aggr_buf) {

    No need for this test. We know it's non-NULL.

    > + po = get_order(SIP_TX_AGGR_BUF_SIZE);

    po is already set. No need to calculate it again.

    > + free_pages((unsigned long)sip->tx_aggr_buf, po);
    > + sip->tx_aggr_buf = NULL;

    No need to set this to NULL. We're just going to free "sip" on the
    next line.

    > + }
    > +
    > +_err_aggr:
    > + kfree(sip);
    > + sip = NULL;

    No need to set this to NULL

    > +
    > +_err_sip:
    > + return NULL;
    > +}
    > +
    > +static void sip_free_init_ctrl_buf(struct esp_sip *sip)
    > +{
    > + struct sip_pkt *pkt, *tpkt;
    > +
    > + list_for_each_entry_safe(pkt, tpkt, &sip->free_ctrl_txbuf, list) {
    > + list_del(&pkt->list);
    > + kfree(pkt->buf_begin);
    > + kfree(pkt);
    > + }
    > +
    > + list_for_each_entry_safe(pkt, tpkt, &sip->free_ctrl_rxbuf, list) {
    > + list_del(&pkt->list);
    > + kfree(pkt->buf_begin);
    > + kfree(pkt);
    > + }
    > +}
    > +
    > +void sip_detach(struct esp_sip *sip)
    > +{
    > + if (!sip)
    > + return;
    > +
    > + sip_free_init_ctrl_buf(sip);
    > +
    > + if (atomic_read(&sip->state) == SIP_RUN) {
    > + sif_disable_target_interrupt(sip->epub);
    > +
    > + atomic_set(&sip->state, SIP_STOP);
    > +
    > + /* disable irq here */
    > + sif_disable_irq(sip->epub);
    > + cancel_work_sync(&sip->rx_process_work);
    > +
    > + skb_queue_purge(&sip->rxq);
    > + mutex_destroy(&sip->rx_mtx);
    > + cancel_work_sync(&sip->epub->sendup_work);
    > + skb_queue_purge(&sip->epub->rxq);
    > +
    > + if (test_and_clear_bit(ESP_WL_FLAG_HW_REGISTERED,
    > + &sip->epub->wl.flags))
    > + ieee80211_unregister_hw(sip->epub->hw);
    > +
    > + /* cancel all worker/timer */
    > + cancel_work_sync(&sip->epub->tx_work);
    > + skb_queue_purge(&sip->epub->txq);
    > + skb_queue_purge(&sip->epub->txdoneq);
    > +
    > + free_pages((unsigned long)sip->tx_aggr_buf,
    > + get_order(SIP_TX_AGGR_BUF_SIZE));
    > + sip->tx_aggr_buf = NULL;
    > +
    > + atomic_set(&sip->state, SIP_INIT);
    > + } else if (atomic_read(&sip->state) >= SIP_BOOT &&
    > + atomic_read(&sip->state) <= SIP_WAIT_BOOTUP) {
    > + sif_disable_target_interrupt(sip->epub);
    > + atomic_set(&sip->state, SIP_STOP);
    > + sif_disable_irq(sip->epub);
    > + kfree(sip->rawbuf);
    > +
    > + if (atomic_read(&sip->state) == SIP_SEND_INIT) {
    > + cancel_work_sync(&sip->rx_process_work);
    > + skb_queue_purge(&sip->rxq);
    > + mutex_destroy(&sip->rx_mtx);
    > + cancel_work_sync(&sip->epub->sendup_work);
    > + skb_queue_purge(&sip->epub->rxq);
    > + }
    > +
    > + if (test_and_clear_bit(ESP_WL_FLAG_HW_REGISTERED,
    > + &sip->epub->wl.flags))
    > + ieee80211_unregister_hw(sip->epub->hw);
    > + atomic_set(&sip->state, SIP_INIT);
    > + } else {
    > + dev_err(sip->epub->dev, "wrong state (%d) for detaching sip\n",
    > + atomic_read(&sip->state));
    > + }
    > +
    > + kfree(sip);
    > +}
    > +
    > +int sip_write_memory(struct esp_sip *sip, u32 addr, u8 *buf, u16 len)
    > +{
    > + struct sip_cmd_write_memory *cmd;
    > + struct sip_hdr *chdr;
    > + u16 remains, hdrs, bufsize;
    > + u32 loadaddr;
    > + u8 *src;
    > + int err = 0;

    No need to initialize "err".

    > + u32 *t;
    > +
    > + if (!sip || !sip->rawbuf) {
    > + ESSERT(sip);
    > + ESSERT(sip->rawbuf);
    > + return -EINVAL;
    > + }
    > +
    > + memset(sip->rawbuf, 0, SIP_BOOT_BUF_SIZE);
    > +
    > + chdr = (struct sip_hdr *)sip->rawbuf;
    > + SIP_HDR_SET_TYPE(chdr->fc[0], SIP_CTRL);
    > + chdr->c_cmdid = SIP_CMD_WRITE_MEMORY;
    > +
    > + remains = len;
    > + hdrs = sizeof(struct sip_hdr) + sizeof(struct sip_cmd_write_memory);
    > +
    > + while (remains) {
    > + src = &buf[len - remains];
    > + loadaddr = addr + (len - remains);
    > +
    > + if (remains < (SIP_BOOT_BUF_SIZE - hdrs)) {
    > + /* aligned with 4 bytes */
    > + bufsize = roundup(remains, 4);
    > + memset(sip->rawbuf + hdrs, 0, bufsize);
    > + remains = 0;
    > + } else {
    > + bufsize = SIP_BOOT_BUF_SIZE - hdrs;
    > + remains -= bufsize;
    > + }
    > +
    > + chdr->len = bufsize + hdrs;
    > + chdr->seq = sip->txseq++;
    > + cmd = (struct sip_cmd_write_memory *)(sip->rawbuf + SIP_CTRL_HDR_LEN);
    > + cmd->len = bufsize;
    > + cmd->addr = loadaddr;
    > + memcpy(sip->rawbuf + hdrs, src, bufsize);
    > +
    > + t = (u32 *)sip->rawbuf;
    > + err = esp_common_write(sip->epub, sip->rawbuf, chdr->len,
    > + ESP_SIF_SYNC);
    > + if (err) {
    > + dev_err(sip->epub->dev, "send buffer failed\n");
    > + return err;
    > + }
    > + // 1ms is enough, in fact on dell-d430, need not delay at all.
    > + mdelay(1);
    > + }
    > +
    > + return err;

    return 0;

    > +}
    > +
    > +int sip_send_cmd(struct esp_sip *sip, int cid, u32 cmdlen, void *cmd)
    > +{
    > + struct sip_hdr *chdr;
    > + struct sip_pkt *pkt;
    > + int ret;
    > +
    > + pkt = sip_get_ctrl_buf(sip, SIP_TX_CTRL_BUF);
    > + if (!pkt)
    > + return -ENOMEM;
    > +
    > + chdr = (struct sip_hdr *)pkt->buf_begin;
    > + chdr->len = SIP_CTRL_HDR_LEN + cmdlen;
    > + chdr->seq = sip->txseq++;
    > + chdr->c_cmdid = cid;
    > +
    > + if (cmd) {
    > + memset(pkt->buf, 0, cmdlen);

    No need for this memset() because we memcpy() over it on the next line.

    > + memcpy(pkt->buf, (u8 *)cmd, cmdlen);
    > + }
    > +
    > + ret = esp_common_write(sip->epub, pkt->buf_begin, chdr->len,
    > + ESP_SIF_SYNC);
    > + if (ret)
    > + dev_err(sip->epub->dev, "send cmd %d failed\n", cid);
    > +
    > + sip_reclaim_ctrl_buf(sip, pkt, SIP_TX_CTRL_BUF);
    > +
    > + /* Hack here: reset tx/rx seq before target ram code is up... */
    > + if (cid == SIP_CMD_BOOTUP) {
    > + sip->rxseq = 0;
    > + sip->txseq = 0;
    > + sip->txdataseq = 0;
    > + }
    > +
    > + return ret;
    > +}
    > +
    > +struct sk_buff *sip_alloc_ctrl_skbuf(struct esp_sip *sip, u16 len, u32 cid)
    > +{
    > + struct sip_hdr *si;
    > + struct ieee80211_tx_info *ti;
    > + struct sk_buff *skb;
    > +
    > + ESSERT(len <= sip->tx_blksz);
    > +
    > + /* no need to reserve space for net stack */
    > + skb = __dev_alloc_skb(len, GFP_KERNEL);
    > + if (!skb) {
    > + dev_err(sip->epub->dev, "no skb for ctrl!\n");
    > + return NULL;
    > + }
    > +
    > + skb->len = len;
    > +
    > + ti = IEEE80211_SKB_CB(skb);
    > + /* set tx_info flags to 0xffffffff to indicate sip_ctrl pkt */
    > + ti->flags = 0xffffffff;
    > +
    > + si = (struct sip_hdr *)skb->data;
    > + memset(si, 0, sizeof(struct sip_hdr));
    > + SIP_HDR_SET_TYPE(si->fc[0], SIP_CTRL);
    > + si->len = len;
    > + si->c_cmdid = cid;
    > +
    > + return skb;
    > +}
    > +
    > +void sip_free_ctrl_skbuff(struct esp_sip *sip, struct sk_buff *skb)
    > +{
    > + memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
    > + kfree_skb(skb);
    > +}
    > +
    > +static struct sip_pkt *sip_get_ctrl_buf(struct esp_sip *sip,
    > + enum sip_buf_type bftype)
    > +{
    > + struct sip_pkt *pkt;
    > + struct list_head *bflist;
    > + struct sip_hdr *chdr;
    > +
    > + /* FIXME: Why taking spinlock to check list_empty? */
    > + bflist = (bftype == SIP_TX_CTRL_BUF) ? &sip->free_ctrl_txbuf : &sip->free_ctrl_rxbuf;
    > +
    > + spin_lock_bh(&sip->lock);
    > +
    > + if (list_empty(bflist)) {
    > + spin_unlock_bh(&sip->lock);
    > + return NULL;
    > + }
    > +
    > + pkt = list_first_entry(bflist, struct sip_pkt, list);
    > + list_del(&pkt->list);
    > + spin_unlock_bh(&sip->lock);
    > +
    > + if (bftype == SIP_TX_CTRL_BUF) {
    > + chdr = (struct sip_hdr *)pkt->buf_begin;
    > + SIP_HDR_SET_TYPE(chdr->fc[0], SIP_CTRL);
    > + pkt->buf = pkt->buf_begin + SIP_CTRL_HDR_LEN;
    > + } else {
    > + pkt->buf = pkt->buf_begin;
    > + }
    > +
    > + return pkt;
    > +}
    > +
    > +static void sip_reclaim_ctrl_buf(struct esp_sip *sip, struct sip_pkt *pkt,
    > + enum sip_buf_type bftype)
    > +{
    > + struct list_head *bflist;
    > +
    > + if (bftype == SIP_TX_CTRL_BUF)
    > + bflist = &sip->free_ctrl_txbuf;
    > + else if (bftype == SIP_RX_CTRL_BUF)
    > + bflist = &sip->free_ctrl_rxbuf;
    > + else
    > + return;
    > +
    > + pkt->buf = pkt->buf_begin;
    > +
    > + spin_lock_bh(&sip->lock);
    > + list_add_tail(&pkt->list, bflist);
    > + spin_unlock_bh(&sip->lock);
    > +}
    > +
    > +int sip_poll_bootup_event(struct esp_sip *sip)
    > +{
    > + int ret = 0;
    > +
    > + if (gl_bootup_cplx)
    > + ret = wait_for_completion_timeout(gl_bootup_cplx, 2 * HZ);
    > +
    > + if (!ret) {
    > + dev_err(sip->epub->dev, "bootup event timeout\n");
    > + return -ETIMEDOUT;
    > + }
    > +
    > + if (!sif_get_ate_config())
    > + ret = esp_register_mac80211(sip->epub);
    > +
    > + atomic_set(&sip->state, SIP_RUN);
    > +
    > + return ret;
    > +}
    > +
    > +/* FIXME: always returning 0 ? */
    > +int sip_poll_resetting_event(struct esp_sip *sip)
    > +{
    > + unsigned int ret;
    > +
    > + if (gl_bootup_cplx)
    > + ret = wait_for_completion_timeout(gl_bootup_cplx, 10 * HZ);
    > +
    > + if (!ret) {
    > + dev_err(sip->epub->dev, "resetting event timeout\n");
    > + return -ETIMEDOUT;
    > + }
    > +
    > + return 0;
    > +}
    > +
    > +bool sip_queue_need_stop(struct esp_sip *sip)
    > +{
    > + return atomic_read(&sip->tx_data_pkt_queued) >= SIP_STOP_QUEUE_THRESHOLD ||
    > + (atomic_read(&sip->tx_credits) < 8 &&
    > + atomic_read(&sip->tx_data_pkt_queued) >= SIP_STOP_QUEUE_THRESHOLD / 4 * 3);
    > +}
    > +
    > +bool sip_queue_may_resume(struct esp_sip *sip)
    > +{
    > + return atomic_read(&sip->epub->txq_stopped) &&
    > + !test_bit(ESP_WL_FLAG_STOP_TXQ, &sip->epub->wl.flags) &&
    > + ((atomic_read(&sip->tx_credits) >= 16 &&
    > + atomic_read(&sip->tx_data_pkt_queued) < SIP_RESUME_QUEUE_THRESHOLD * 2) ||
    > + atomic_read(&sip->tx_data_pkt_queued) < SIP_RESUME_QUEUE_THRESHOLD);
    > +}
    > +
    > +int sip_cmd_enqueue(struct esp_sip *sip, struct sk_buff *skb, int prior)
    > +{
    > + if (!sip || !sip->epub || !skb) {
    > + return -EINVAL;
    > + }
    > +
    > + if (prior == ENQUEUE_PRIOR_HEAD)
    > + skb_queue_head(&sip->epub->txq, skb);
    > + else
    > + skb_queue_tail(&sip->epub->txq, skb);
    > +
    > + if (!sif_get_ate_config())
    > + ieee80211_queue_work(sip->epub->hw, &sip->epub->tx_work);
    > + else
    > + queue_work(sip->epub->esp_wkq, &sip->epub->tx_work);
    > +
    > + return 0;
    > +}
    > +
    > +void sip_tx_data_pkt_enqueue(struct esp_pub *epub, struct sk_buff *skb)
    > +{
    > + if (!epub || !epub->sip || !skb)
    > + return;
    > +
    > + skb_queue_tail(&epub->txq, skb);
    > + atomic_inc(&epub->sip->tx_data_pkt_queued);
    > +
    > + if (sip_queue_need_stop(epub->sip))
    > + if (epub->hw) {
    > + ieee80211_stop_queues(epub->hw);
    > + atomic_set(&epub->txq_stopped, true);
    > + }

    Multi-line indents get curly braces for readability.

    > +}
    > diff --git a/drivers/staging/esp8089/esp_sip.h b/drivers/staging/esp8089/esp_sip.h
    > new file mode 100644
    > index 000000000000..fe58aae4ba54
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_sip.h
    > @@ -0,0 +1,150 @@
    > +/*
    > + * Copyright (c) 2009 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef _ESP_SIP_H
    > +#define _ESP_SIP_H
    > +
    > +#include "sip2_common.h"
    > +
    > +#define SIP_CTRL_CREDIT_RESERVE 2
    > +
    > +#define SIP_PKT_MAX_LEN (1024 * 16)
    > +
    > +/* 16KB on normal X86 system, should check before porting to orhters */
    > +
    > +#define SIP_TX_AGGR_BUF_SIZE (4 * PAGE_SIZE)
    > +#define SIP_RX_AGGR_BUF_SIZE (4 * PAGE_SIZE)
    > +
    > +struct sk_buff;
    > +
    > +struct sip_pkt {
    > + struct list_head list;
    > + u8 *buf_begin;
    > + u32 buf_len;
    > + u8 *buf;
    > +};
    > +
    > +enum RECALC_CREDIT_STATE {
    > + RECALC_CREDIT_DISABLE = 0,
    > + RECALC_CREDIT_ENABLE = 1,
    > +};
    > +
    > +enum ENQUEUE_PRIOR {
    > + ENQUEUE_PRIOR_TAIL = 0,
    > + ENQUEUE_PRIOR_HEAD,
    > +};
    > +
    > +enum SIP_STATE {
    > + SIP_INIT = 0,
    > + SIP_PREPARE_BOOT,
    > + SIP_BOOT,
    > + SIP_SEND_INIT,
    > + SIP_WAIT_BOOTUP,
    > + SIP_RUN,
    > + SIP_SUSPEND,
    > + SIP_STOP
    > +};
    > +
    > +enum sip_notifier {
    > + SIP_TX_DONE = 1,
    > + SIP_RX_DONE = 2,
    > +};
    > +
    > +#define SIP_CREDITS_LOW_THRESHOLD 64 //i.e. 4k
    > +
    > +struct esp_sip {
    > + struct list_head free_ctrl_txbuf;
    > + struct list_head free_ctrl_rxbuf;
    > +
    > + u32 rxseq; /* sip pkt seq, should match target side */
    > + u32 txseq;
    > + u32 txdataseq;
    > +
    > + u8 to_host_seq;
    > +
    > + atomic_t state;
    > + spinlock_t lock;
    > + atomic_t tx_credits;
    > +
    > + atomic_t tx_ask_credit_update;
    > +
    > + u8 *rawbuf; /* used in boot stage, free once chip is fully up */
    > + u8 *tx_aggr_buf;
    > + u8 *tx_aggr_write_ptr; /* update after insertion of each pkt */
    > + u8 *tx_aggr_lastpkt_ptr;
    > +
    > + struct mutex rx_mtx;
    > + struct sk_buff_head rxq;
    > + struct work_struct rx_process_work;
    > +
    > + u16 tx_blksz;
    > + u16 rx_blksz;
    > +
    > + bool dump_rpbm_err;
    > + bool sendup_rpbm_pkt;
    > + bool rxabort_fixed;
    > + bool support_bgscan;
    > + u8 credit_to_reserve;
    > +
    > + atomic_t credit_status;
    > + struct timer_list credit_timer;
    > +
    > + atomic_t noise_floor;
    > +
    > + u32 tx_tot_len; /* total len for one transaction */
    > + u32 rx_tot_len;
    > +
    > + atomic_t rx_handling;
    > + atomic_t tx_data_pkt_queued;
    > +
    > + atomic_t data_tx_stopped;
    > + atomic_t tx_stopped;
    > +
    > + struct esp_pub *epub;
    > +};
    > +
    > +int sip_rx(struct esp_pub *epub);
    > +
    > +int sip_write_memory(struct esp_sip *sip, u32 addr, u8 *buf, u16 len);
    > +
    > +int sip_send_cmd(struct esp_sip *sip, int cid, u32 cmdlen, void *cmd);
    > +
    > +struct esp_sip *sip_attach(struct esp_pub *epub);
    > +
    > +int sip_post_init(struct esp_sip *sip, struct sip_evt_bootup2 *bevt);
    > +
    > +void sip_detach(struct esp_sip *sip);
    > +
    > +void sip_txq_process(struct esp_pub *epub);
    > +
    > +struct sk_buff *sip_alloc_ctrl_skbuf(struct esp_sip *sip, u16 len, u32 cid);
    > +
    > +void sip_free_ctrl_skbuff(struct esp_sip *sip, struct sk_buff *skb);
    > +
    > +bool sip_queue_need_stop(struct esp_sip *sip);
    > +bool sip_queue_may_resume(struct esp_sip *sip);
    > +
    > +void sip_tx_data_pkt_enqueue(struct esp_pub *epub, struct sk_buff *skb);
    > +
    > +int sip_cmd_enqueue(struct esp_sip *sip, struct sk_buff *skb, int prior);
    > +
    > +int sip_poll_bootup_event(struct esp_sip *sip);
    > +
    > +int sip_poll_resetting_event(struct esp_sip *sip);
    > +
    > +void sip_trigger_txq_process(struct esp_sip *sip);
    > +
    > +void sip_send_chip_init(struct esp_sip *sip);
    > +
    > +bool mod_support_no_txampdu(void);
    > +
    > +bool mod_support_no_rxampdu(void);
    > +#endif
    > diff --git a/drivers/staging/esp8089/esp_utils.c b/drivers/staging/esp8089/esp_utils.c
    > new file mode 100644
    > index 000000000000..b35428d70c91
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_utils.c
    > @@ -0,0 +1,133 @@
    > +/*
    > + * Copyright (c) 2009 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#include "linux/types.h"
    > +#include "linux/kernel.h"
    > +#include <linux/ieee80211.h>
    > +#include <net/mac80211.h>
    > +#include <linux/skbuff.h>
    > +
    > +#include <net/tcp.h>
    > +#include <linux/ip.h>
    > +#include <asm/checksum.h>
    > +
    > +#include "esp_pub.h"
    > +#include "esp_utils.h"
    > +#include "esp_wmac.h"
    > +#include "esp_debug.h"
    > +
    > +/* Convert IEEE channel number to MHz frequency. */
    > +u32 esp_ieee2mhz(u8 chan)
    > +{
    > + if (chan == 14)
    > + return 2484;
    > +
    > + if (chan < 14)
    > + return 2407 + chan * 5;
    > +
    > + return 2512 + ((chan - 15) * 20);
    > + //TODO, add 5GHz
    > +}
    > +
    > +enum {
    > + ESP_RATE_1_LONG = 0x0,
    > + ESP_RATE_2_LONG = 0x1,
    > + ESP_RATE_2_SHORT = 0x5,
    > + ESP_RATE_5_SHORT = 0x6,
    > + ESP_RATE_5_LONG = 0x2,
    > + ESP_RATE_11_SHORT = 0x7,
    > + ESP_RATE_11_LONG = 0x3,
    > + ESP_RATE_6 = 0xb,
    > + ESP_RATE_9 = 0xf,
    > + ESP_RATE_12 = 0xa,
    > + ESP_RATE_18 = 0xe,
    > + ESP_RATE_24 = 0x9,
    > + ESP_RATE_36 = 0xd,
    > + ESP_RATE_48 = 0x8,
    > + ESP_RATE_54 = 0xc,
    > + /* ESP_RATE_MCS0 =0x10,
    > + * ESP_RATE_MCS1 =0x11,
    > + * ESP_RATE_MCS2 =0x12,
    > + * ESP_RATE_MCS3 =0x13,
    > + * ESP_RATE_MCS4 =0x14,
    > + * ESP_RATE_MCS5 =0x15,
    > + * ESP_RATE_MCS6 =0x16,
    > + * ESP_RATE_MCS7 =0x17,
    > + */
    > +};
    > +
    > +static u8 esp_rate_table[20] = {
    > + ESP_RATE_1_LONG,
    > + ESP_RATE_2_SHORT,
    > + ESP_RATE_5_SHORT,
    > + ESP_RATE_11_SHORT,
    > + ESP_RATE_6,
    > + ESP_RATE_9,
    > + ESP_RATE_12,
    > + ESP_RATE_18,
    > + ESP_RATE_24,
    > + ESP_RATE_36,
    > + ESP_RATE_48,
    > + ESP_RATE_54,
    > + /* ESP_RATE_MCS0,
    > + * ESP_RATE_MCS1,
    > + * ESP_RATE_MCS2,
    > + * ESP_RATE_MCS3,
    > + * ESP_RATE_MCS4,
    > + * ESP_RATE_MCS5,
    > + * ESP_RATE_MCS6,
    > + * ESP_RATE_MCS7,
    > + */
    > +};
    > +
    > +s8 esp_wmac_rate2idx(u8 rate)

    Just make it return int or maybe u8.

    > +{
    > + int i;
    > +
    > + if (rate == ESP_RATE_2_LONG)
    > + return 1;
    > +
    > + if (rate == ESP_RATE_5_LONG)
    > + return 2;
    > +
    > + if (rate == ESP_RATE_11_LONG)
    > + return 3;
    > +
    > + for (i = 0; i < 20; i++)
    > + if (rate == esp_rate_table[i])
    > + return i;
    > +
    > + return 0;
    > +}
    > +
    > +bool esp_wmac_rxsec_error(u8 error)
    > +{
    > + return (error >= RX_SECOV_ERR && error <= RX_SECFIFO_TIMEOUT) ||
    > + (error >= RX_WEPICV_ERR && error <= RX_WAPIMIC_ERR);
    > +}
    > +
    > +int esp_cipher2alg(int cipher)
    > +{
    > + if (cipher == WLAN_CIPHER_SUITE_TKIP)
    > + return ALG_TKIP;
    > +
    > + if (cipher == WLAN_CIPHER_SUITE_CCMP)
    > + return ALG_CCMP;
    > +
    > + if (cipher == WLAN_CIPHER_SUITE_WEP40 ||
    > + cipher == WLAN_CIPHER_SUITE_WEP104)
    > + return ALG_WEP;
    > +
    > + if (cipher == WLAN_CIPHER_SUITE_AES_CMAC)
    > + return ALG_AES_CMAC;
    > +
    > + return -1;
    > +}
    > diff --git a/drivers/staging/esp8089/esp_utils.h b/drivers/staging/esp8089/esp_utils.h
    > new file mode 100644
    > index 000000000000..3a4d461a4e70
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_utils.h
    > @@ -0,0 +1,27 @@
    > +/*
    > + * Copyright (c) 2011 - 2012 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef _ESP_UTILS_H_
    > +#define _ESP_UTILS_H_
    > +
    > +#include "linux/types.h"
    > +
    > +u32 esp_ieee2mhz(u8 chan);
    > +
    > +enum ieee80211_key_alg {
    > + ALG_WEP,
    > + ALG_TKIP,
    > + ALG_CCMP,
    > + ALG_AES_CMAC
    > +};
    > +
    > +int esp_cipher2alg(int cipher);
    > +#endif
    > diff --git a/drivers/staging/esp8089/esp_wl.h b/drivers/staging/esp8089/esp_wl.h
    > new file mode 100644
    > index 000000000000..9eb1f6421947
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_wl.h
    > @@ -0,0 +1,35 @@
    > +/*
    > + * Copyright (c) 2009 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef _ESP_WL_H_
    > +#define _ESP_WL_H_
    > +
    > +//#define MAX_PROBED_SSID_INDEX 9
    > +
    > +enum {
    > + CONF_HW_BIT_RATE_1MBPS = BIT(0),
    > + CONF_HW_BIT_RATE_2MBPS = BIT(1),
    > + CONF_HW_BIT_RATE_5_5MBPS = BIT(2),
    > + CONF_HW_BIT_RATE_11MBPS = BIT(3),
    > + CONF_HW_BIT_RATE_6MBPS = BIT(4),
    > + CONF_HW_BIT_RATE_9MBPS = BIT(5),
    > + CONF_HW_BIT_RATE_12MBPS = BIT(6),
    > + CONF_HW_BIT_RATE_18MBPS = BIT(7),
    > + CONF_HW_BIT_RATE_22MBPS = BIT(8),
    > + CONF_HW_BIT_RATE_24MBPS = BIT(9),
    > + CONF_HW_BIT_RATE_36MBPS = BIT(10),
    > + CONF_HW_BIT_RATE_48MBPS = BIT(11),
    > + CONF_HW_BIT_RATE_54MBPS = BIT(12),
    > +};
    > +
    > +#define CONF_HW_BIT_RATE_11B_MASK (CONF_HW_BIT_RATE_1MBPS | CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | CONF_HW_BIT_RATE_11MBPS)
    > +
    > +#endif /* _ESP_WL_H_ */
    > diff --git a/drivers/staging/esp8089/esp_wmac.h b/drivers/staging/esp8089/esp_wmac.h
    > new file mode 100644
    > index 000000000000..67ea8e147c43
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/esp_wmac.h
    > @@ -0,0 +1,87 @@
    > +/*
    > + * Copyright (c) 2011 - 2012 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef _ESP_WMAC_H_
    > +#define _ESP_WMAC_H_
    > +
    > +struct esp_mac_rx_ctrl {
    > + signed rssi:8;
    > + unsigned rate:4;
    > + unsigned is_group:1;
    > + unsigned:1;
    > + unsigned sig_mode:2;
    > + unsigned legacy_length:12;
    > + unsigned damatch0:1;
    > + unsigned damatch1:1;
    > + unsigned bssidmatch0:1;
    > + unsigned bssidmatch1:1;
    > + unsigned MCS:7;
    > + unsigned CWB:1;
    > + unsigned HT_length:16;
    > + unsigned smoothing:1;
    > + unsigned not_sounding:1;
    > + unsigned:1;
    > + unsigned aggregation:1;
    > + unsigned STBC:2;
    > + unsigned FEC_CODING:1;
    > + unsigned SGI:1;
    > + unsigned rxend_state:8;
    > + unsigned ampdu_cnt:8;
    > + unsigned channel:4;
    > + unsigned:4;
    > + signed noise_floor:8;
    > +};
    > +
    > +struct esp_rx_ampdu_len {
    > + unsigned substate:8;
    > + unsigned sublen:12;
    > + unsigned:12;
    > +};
    > +
    > +struct esp_tx_ampdu_entry {
    > + u32 sub_len:12, dili_num:7, :1, null_byte:2, data:1, enc:1, seq:8;
    > +};
    > +
    > +//rxend_state flags
    > +#define RX_PYH_ERR_MIN 0x42
    > +#define RX_AGC_ERR_MIN 0x42
    > +#define RX_AGC_ERR_MAX 0x47
    > +#define RX_OFDM_ERR_MIN 0x50
    > +#define RX_OFDM_ERR_MAX 0x58
    > +#define RX_CCK_ERR_MIN 0x59
    > +#define RX_CCK_ERR_MAX 0x5F
    > +#define RX_ABORT 0x80
    > +#define RX_SF_ERR 0x40
    > +#define RX_FCS_ERR 0x41
    > +#define RX_AHBOV_ERR 0xC0
    > +#define RX_BUFOV_ERR 0xC1
    > +#define RX_BUFINV_ERR 0xC2
    > +#define RX_AMPDUSF_ERR 0xC3
    > +#define RX_AMPDUBUFOV_ERR 0xC4
    > +#define RX_MACBBFIFOOV_ERR 0xC5
    > +#define RX_RPBM_ERR 0xC6
    > +#define RX_BTFORCE_ERR 0xC7
    > +#define RX_SECOV_ERR 0xE1
    > +#define RX_SECPROT_ERR0 0xE2
    > +#define RX_SECPROT_ERR1 0xE3
    > +#define RX_SECKEY_ERR 0xE4
    > +#define RX_SECCRLEN_ERR 0xE5
    > +#define RX_SECFIFO_TIMEOUT 0xE6
    > +#define RX_WEPICV_ERR 0xF0
    > +#define RX_TKIPICV_ERR 0xF4
    > +#define RX_TKIPMIC_ERR 0xF5
    > +#define RX_CCMPMIC_ERR 0xF8
    > +#define RX_WAPIMIC_ERR 0xFC
    > +
    > +s8 esp_wmac_rate2idx(u8 rate);
    > +bool esp_wmac_rxsec_error(u8 error);
    > +
    > +#endif /* _ESP_WMAC_H_ */
    > diff --git a/drivers/staging/esp8089/sdio_sif_esp.c b/drivers/staging/esp8089/sdio_sif_esp.c
    > new file mode 100644
    > index 000000000000..d8842f5085ce
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/sdio_sif_esp.c
    > @@ -0,0 +1,552 @@
    > +/*
    > + * Copyright (c) 2010 - 2013 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#include <linux/mmc/card.h>
    > +#include <linux/mmc/mmc.h>
    > +#include <linux/mmc/core.h>
    > +#include <linux/mmc/host.h>
    > +#include <linux/mmc/sdio_func.h>
    > +#include <linux/mmc/sdio_ids.h>
    > +#include <linux/mmc/sdio.h>
    > +#include <linux/mmc/sd.h>
    > +#include <linux/module.h>
    > +#include <net/mac80211.h>
    > +#include <linux/time.h>
    > +#include <linux/pm.h>
    > +
    > +#include "esp_pub.h"
    > +#include "esp_sif.h"
    > +#include "esp_sip.h"
    > +#include "esp_debug.h"
    > +#include "slc_host_register.h"
    > +#include "esp_version.h"
    > +#include "esp_ctrl.h"
    > +#include "esp_file.h"
    > +
    > +unsigned int esp_msg_level = ESP_DBG_ERROR | ESP_SHOW;
    > +
    > +/* HdG: Note:
    > + * 1) MMC_HAS_FORCE_DETECT_CHANGE is a hack which is set by my sunxi-wip
    > + * tree. FIXME replace with a version check once mmc_force_detect_change()
    > + * is added to the mainline kernel.
    > + * 2) This version does NOT implement keep_power, the dts must mark the
    > + * regulators as regulator-always-on and not use mmc-pwrseq for this stub
    > + * to work.
    > + */
    > +#ifndef MMC_HAS_FORCE_DETECT_CHANGE
    > +void mmc_force_detect_change(struct mmc_host *host, unsigned long delay,
    > + bool keep_power)
    > +{
    > + host->caps &= ~MMC_CAP_NONREMOVABLE;
    > + host->caps |= MMC_CAP_NEEDS_POLL;
    > + mmc_detect_change(host, delay);
    > +}
    > +#endif
    > +
    > +#define ESP_DMA_IBUFSZ 2048
    > +
    > +struct esp_sdio_ctrl *sif_sctrl;
    > +
    > +static int esdio_power_off(struct esp_sdio_ctrl *sctrl);
    > +static int esdio_power_on(struct esp_sdio_ctrl *sctrl);
    > +
    > +void sif_set_clock(struct sdio_func *func, int clk);
    > +
    > +void sif_lock_bus(struct esp_pub *epub)
    > +{
    > + if (!epub || !epub->sif || !epub->sif->func)
    > + return;
    > + sdio_claim_host(epub->sif->func);
    > +}
    > +
    > +void sif_unlock_bus(struct esp_pub *epub)
    > +{
    > + if (!epub || !epub->sif || !epub->sif->func)
    > + return;
    > + sdio_release_host(epub->sif->func);
    > +}
    > +
    > +static inline bool bad_buf(u8 *buf)
    > +{
    > + return (unsigned long)buf & 0x3 || !virt_addr_valid(buf);
    > +}
    > +
    > +u8 sdio_io_readb(struct esp_pub *epub, int addr, int *res)
    > +{
    > + struct sdio_func *func = epub->sif->func;
    > +
    > + if (!func->num)
    > + return sdio_f0_readb(func, addr, res);
    > +
    > + return sdio_readb(func, addr, res);
    > +}
    > +
    > +void sdio_io_writeb(struct esp_pub *epub, u8 value, int addr, int *res)
    > +{
    > + struct sdio_func *func = epub->sif->func;
    > +
    > + if (!func->num)
    > + sdio_f0_writeb(func, value, addr, res);
    > + else
    > + sdio_writeb(func, value, addr, res);
    > +}
    > +
    > +int sif_io(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag,
    > + bool sync)
    > +{
    > + struct sdio_func *func;
    > + int err = 0;
    > + u8 *ibuf;
    > + bool need_ibuf = false;
    > +
    > + if (!epub || !buf || !epub->sif || !epub->sif->func) {
    > + ESSERT(0);
    > + return -EINVAL;
    > + }
    > +
    > + func = epub->sif->func;
    > +
    > + if (bad_buf(buf)) {
    > + need_ibuf = true;
    > + ibuf = epub->sif->dma_buffer;
    > + } else {
    > + ibuf = buf;
    > + }
    > +
    > + if (flag & SIF_TO_DEVICE) {
    > + if (need_ibuf)
    > + memcpy(ibuf, buf, len);
    > +
    > + if (sync)
    > + sdio_claim_host(func);
    > +
    > + if (flag & SIF_FIXED_ADDR)
    > + err = sdio_writesb(func, addr, ibuf, len);
    > + else if (flag & SIF_INC_ADDR)
    > + err = sdio_memcpy_toio(func, addr, ibuf, len);
    > +
    > + if (sync)
    > + sdio_release_host(func);
    > +
    > + } else if (flag & SIF_FROM_DEVICE) {
    > + if (sync)
    > + sdio_claim_host(func);
    > +
    > + if (flag & SIF_FIXED_ADDR)
    > + err = sdio_readsb(func, ibuf, addr, len);
    > + else if (flag & SIF_INC_ADDR)
    > + err = sdio_memcpy_fromio(func, ibuf, addr, len);
    > +
    > + if (sync)
    > + sdio_release_host(func);
    > +
    > + if (!err && need_ibuf)
    > + memcpy(buf, ibuf, len);
    > + }
    > +
    > + return err;
    > +}
    > +
    > +int sif_io_raw(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag)
    > +{
    > + return sif_io(epub, addr, buf, len, flag, false);
    > +}
    > +
    > +int sif_io_sync(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag)
    > +{
    > + return sif_io(epub, addr, buf, len, flag, true);
    > +}
    > +
    > +int sif_lldesc(struct esp_pub *epub, u8 *buf, u32 len, bool sync, bool read,
    > + bool noround)
    > +{
    > + u32 read_len, addr, flags;
    > +
    > + if (!epub || !buf || !epub->sif || !epub->sif->target_id) {
    > + ESSERT(0);
    > + return -EINVAL;
    > + }
    > +
    > + if (epub->sif->target_id == 0x600 && !noround)
    > + read_len = roundup(len, epub->sif->slc_blk_sz);
    > + else
    > + read_len = len;
    > +
    > + if (read) {
    > + addr = epub->sif->slc_window_end_addr - 2 - len;
    > + flags = SIF_FROM_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR;
    > + } else {
    > + addr = epub->sif->slc_window_end_addr - len;
    > + flags = SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR;
    > + }
    > +
    > + if (sync)
    > + return sif_io_sync(epub, addr, buf, read_len, flags);
    > + return sif_io_raw(epub, addr, buf, read_len, flags);
    > +}
    > +
    > +int sif_lldesc_read_sync(struct esp_pub *epub, u8 *buf, u32 len)
    > +{
    > + return sif_lldesc(epub, buf, len, true, true, false);
    > +}
    > +
    > +int sif_lldesc_write_sync(struct esp_pub *epub, u8 *buf, u32 len)
    > +{
    > + return sif_lldesc(epub, buf, len, true, false, false);
    > +}
    > +
    > +int sif_lldesc_read_raw(struct esp_pub *epub, u8 *buf, u32 len, bool noround)
    > +{
    > + return sif_lldesc(epub, buf, len, false, true, noround);
    > +}
    > +
    > +int sif_lldesc_write_raw(struct esp_pub *epub, u8 *buf, u32 len)
    > +{
    > + return sif_lldesc(epub, buf, len, false, false, false);
    > +}
    > +
    > +#define MANUFACTURER_ID_EAGLE_BASE 0x1110
    > +#define MANUFACTURER_CODE 0x6666
    > +
    > +static const struct sdio_device_id esp_sdio_devices[] = {
    > + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_EAGLE_BASE | 0x1))},
    > + {},
    > +};
    > +
    > +static int esdio_power(struct esp_sdio_ctrl *sctrl, bool power_on)
    > +{
    > + int err;
    > +
    > + if (sctrl->off != power_on)
    > + return 0;
    > +
    > + sdio_claim_host(sctrl->func);
    > +
    > + if (power_on)
    > + err = sdio_enable_func(sctrl->func);
    > + else
    > + err = sdio_disable_func(sctrl->func);
    > +
    > + sdio_release_host(sctrl->func);
    > +
    > + if (err) {
    > + dev_err(sctrl->epub->dev, "unable to enable sdio func: %d\n",
    > + err);
    > + return err;
    > + }
    > +
    > + /* ensure device is up */
    > + if (power_on)
    > + msleep(5);
    > +
    > + sctrl->off = !sctrl->off;
    > +
    > + return err;

    return 0;

    > +}
    > +
    > +static int esdio_power_on(struct esp_sdio_ctrl *sctrl)
    > +{
    > + return esdio_power(sctrl, true);
    > +}
    > +
    > +static int esdio_power_off(struct esp_sdio_ctrl *sctrl)
    > +{
    > + return esdio_power(sctrl, false);
    > +}
    > +
    > +void sif_enable_irq(struct esp_pub *epub)
    > +{
    > + sdio_claim_host(epub->sif->func);
    > +
    > + if (sdio_claim_irq(epub->sif->func, sif_dsr))
    > + dev_err(epub->dev, "sif %s failed\n", __func__);
    > +
    > + atomic_set(&epub->sip->state, SIP_BOOT);
    > + atomic_set(&epub->sif->irq_installed, 1);
    > +
    > + sdio_release_host(epub->sif->func);
    > +}
    > +
    > +void sif_disable_irq(struct esp_pub *epub)
    > +{
    > + int i = 0;
    > +
    > + if (!atomic_read(&epub->sif->irq_installed))
    > + return;
    > +
    > + sdio_claim_host(epub->sif->func);
    > +
    > + while (atomic_read(&epub->sif->irq_handling)) {
    > + sdio_release_host(epub->sif->func);
    > + schedule_timeout(HZ / 100);
    > + sdio_claim_host(epub->sif->func);
    > + if (i++ >= 400)
    > + break;
    > + }
    > +
    > + /* Ignore errors, we don't always use an irq. */
    > + sdio_release_irq(epub->sif->func);
    > +
    > + atomic_set(&epub->sif->irq_installed, 0);
    > + sdio_release_host(epub->sif->func);
    > +}
    > +
    > +void sif_set_clock(struct sdio_func *func, int clk)
    > +{
    > + struct mmc_host *host = func->card->host;
    > +
    > + sdio_claim_host(func);
    > +
    > + //currently only set clock
    > + host->ios.clock = clk * 1000000;
    > +
    > + if (host->ios.clock > host->f_max)
    > + host->ios.clock = host->f_max;
    > +
    > + host->ops->set_ios(host, &host->ios);
    > +
    > + mdelay(2);
    > +
    > + sdio_release_host(func);
    > +}
    > +
    > +static void esp_sdio_remove(struct sdio_func *func);
    > +
    > +static int esp_sdio_probe(struct sdio_func *func,
    > + const struct sdio_device_id *id)
    > +{
    > + struct esp_pub *epub;
    > + struct esp_sdio_ctrl *sctrl;
    > + struct mmc_host *host = func->card->host;
    > + int err;
    > +
    > + if (!sif_sctrl) {
    > + request_init_conf(&func->dev);
    > +
    > + sctrl = kzalloc(sizeof(*sctrl), GFP_KERNEL);
    > + if (!sctrl)
    > + return -ENOMEM;
    > +
    > + /* temp buffer reserved for un-dma-able request */
    > + sctrl->dma_buffer = kzalloc(ESP_DMA_IBUFSZ, GFP_KERNEL);
    > + if (!sctrl->dma_buffer) {
    > + err = -ENOMEM;
    > + goto _err_last;
    > + }
    > +
    > + sif_sctrl = sctrl;
    > + sctrl->slc_blk_sz = SIF_SLC_BLOCK_SIZE;
    > +
    > + epub = esp_pub_alloc_mac80211(&func->dev);
    > + if (!epub) {
    > + err = -ENOMEM;
    > + goto _err_dma;
    > + }
    > +
    > + epub->sif = sctrl;
    > + epub->sdio_state = ESP_SDIO_STATE_FIRST_INIT;
    > + sctrl->epub = epub;
    > + } else {
    > + /* FIXME: why duplicating sctrl and sif_sctrl? */
    > + sctrl = sif_sctrl;
    > + sif_sctrl = NULL;
    > + epub = sctrl->epub;
    > + epub->sdio_state = ESP_SDIO_STATE_SECOND_INIT;
    > + /* FIXME: already done in esp_pub_alloc_mac80211 which is called on first probe */
    > + SET_IEEE80211_DEV(epub->hw, &func->dev);
    > + epub->dev = &func->dev;
    > + }
    > +
    > + sctrl->func = func;
    > + sdio_set_drvdata(func, sctrl);
    > + sctrl->id = id;
    > + sctrl->off = true;
    > +
    > + /* give us some time to enable, in ms */
    > + func->enable_timeout = 100;
    > +
    > + err = esdio_power_on(sctrl);
    > + if (err) {
    > + if (epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT)
    > + goto _err_ext_gpio;
    > +
    > + goto _err_second_init;
    > + }
    > +
    > + check_target_id(epub);
    > +
    > + sdio_claim_host(func);
    > +
    > + err = sdio_set_block_size(func, sctrl->slc_blk_sz);
    > + if (err) {
    > + dev_err(epub->dev, "Set sdio block size %d failed: %d)\n",
    > + sctrl->slc_blk_sz, err);
    > +
    > + sdio_release_host(func);
    > + if (epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT)
    > + goto _err_off;
    > +
    > + goto _err_second_init;
    > + }
    > +
    > + sdio_release_host(func);
    > +
    > +#ifdef LOWER_CLK
    > + /* fix clock for dongle */
    > + sif_set_clock(func, 23);
    > +#endif //LOWER_CLK
    > +
    > + err = esp_pub_init_all(epub);
    > + if (err) {
    > + dev_err(epub->dev, "esp_init_all failed: %d\n", err);
    > + if (epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
    > + err = 0;

    Why is this success?

    > + goto _err_first_init;
    > + }
    > +
    > + if (epub->sdio_state == ESP_SDIO_STATE_SECOND_INIT)
    > + goto _err_second_init;
    > + }
    > +
    > + if (epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT) {
    > + epub->sdio_state = ESP_SDIO_STATE_FIRST_NORMAL_EXIT;
    > + /* Rescan the esp8089 after loading the initial firmware */
    > + mmc_force_detect_change(host, msecs_to_jiffies(100), true);
    > + }
    > +
    > + return err;

    return 0;

    > +
    > +_err_off:
    > + esdio_power_off(sctrl);
    > +
    > +_err_ext_gpio:
    > + esp_pub_dealloc_mac80211(epub);
    > +
    > +_err_dma:
    > + kfree(sctrl->dma_buffer);
    > +
    > +_err_last:
    > + kfree(sctrl);
    > +
    > +_err_first_init:
    > + if (epub && epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT)
    > + epub->sdio_state = ESP_SDIO_STATE_FIRST_ERROR_EXIT;
    > +
    > + return err;
    > +
    > +_err_second_init:
    > + epub->sdio_state = ESP_SDIO_STATE_SECOND_ERROR_EXIT;
    > + esp_sdio_remove(func);
    > +
    > + return err;
    > +}
    > +
    > +static void esp_sdio_remove(struct sdio_func *func)
    > +{
    > + struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func);
    > + struct esp_pub *epub;
    > +
    > + if (!sctrl) {
    > + return;
    > + }
    > +
    > + epub = sctrl->epub;
    > + if (!epub) {
    > + goto _out;
    > + }
    > +
    > + if (epub->sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT) {
    > + if (epub->sip) {
    > + sip_detach(epub->sip);
    > + epub->sip = NULL;
    > + }
    > + } else {
    > + atomic_set(&epub->sip->state, SIP_STOP);
    > + sif_disable_irq(epub);
    > + }
    > +
    > + if (epub->sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT) {
    > + esp_pub_dealloc_mac80211(epub);
    > +
    > + kfree(sctrl->dma_buffer);
    > + sctrl->dma_buffer = NULL;
    > +
    > + kfree(sctrl);
    > + }
    > +
    > +_out:
    > + sdio_set_drvdata(func, NULL);
    > +}
    > +
    > +MODULE_DEVICE_TABLE(sdio, esp_sdio_devices);
    > +
    > +static int esp_sdio_suspend(struct device *dev)
    > +{
    > + struct sdio_func *func = dev_to_sdio_func(dev);
    > + struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func);
    > + struct esp_pub *epub = sctrl->epub;
    > + u32 sdio_flags;
    > +
    > + printk("%s", __func__);
    > + atomic_set(&epub->ps.state, ESP_PM_ON);
    > +
    > + sdio_flags = sdio_get_host_pm_caps(func);
    > +
    > + if (!(sdio_flags & MMC_PM_KEEP_POWER))
    > + printk("%s can't keep power while host is suspended\n",
    > + __func__);
    > +
    > + /* keep power while host suspended */
    > + if (sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER))
    > + printk("%s error while trying to keep power\n", __func__);
    > +
    > + return 0;
    > +}
    > +
    > +static int esp_sdio_resume(struct device *dev)
    > +{
    > + return 0;
    > +}
    > +
    > +static const struct dev_pm_ops esp_sdio_pm_ops = {
    > + .suspend = esp_sdio_suspend,
    > + .resume = esp_sdio_resume,
    > +};
    > +
    > +static struct sdio_driver esp_sdio_driver = {
    > + .name = "eagle_sdio",
    > + .id_table = esp_sdio_devices,
    > + .probe = esp_sdio_probe,
    > + .remove = esp_sdio_remove,
    > + .drv = {.pm = &esp_sdio_pm_ops,},
    > +};
    > +
    > +static int /*__init*/ esp_sdio_init(void)
    > +{
    > + esp_debugfs_init();
    > + sdio_register_driver(&esp_sdio_driver);
    > +
    > + return 0;
    > +}
    > +
    > +static void /*__exit*/ esp_sdio_exit(void)
    > +{
    > + sdio_unregister_driver(&esp_sdio_driver);
    > + esp_debugfs_exit();
    > +}
    > +
    > +module_init(esp_sdio_init);
    > +module_exit(esp_sdio_exit);
    > +
    > +MODULE_AUTHOR("Espressif System");
    > +MODULE_DESCRIPTION
    > +("Driver for SDIO interconnected eagle low-power WLAN devices");
    > +MODULE_LICENSE("GPL");
    > diff --git a/drivers/staging/esp8089/sip2_common.h b/drivers/staging/esp8089/sip2_common.h
    > new file mode 100644
    > index 000000000000..5dfb8c492223
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/sip2_common.h
    > @@ -0,0 +1,388 @@
    > +/*
    > + * Copyright (c) 2010 - 2014 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef _SIP2_COMMON_H
    > +#define _SIP2_COMMON_H
    > +
    > +/* max 16 types */
    > +enum sip_type {
    > + SIP_CTRL = 0,
    > + SIP_DATA,
    > + SIP_DATA_AMPDU
    > +};
    > +
    > +enum sip_buf_type {
    > + SIP_TX_CTRL_BUF = 0, /* from host */
    > + SIP_RX_CTRL_BUF, /* to host */
    > + SIP_TX_DATA_BUF, /* from host */
    > + SIP_RX_DATA_BUF /* to host */
    > +};
    > +
    > +enum sip_cmd_id {
    > + SIP_CMD_GET_VER = 0,
    > + SIP_CMD_WRITE_MEMORY, //1 ROM code
    > + SIP_CMD_READ_MEMORY, //2
    > + SIP_CMD_WRITE_REG, //3 ROM code
    > + SIP_CMD_READ_REG, //4
    > + SIP_CMD_BOOTUP, //5 ROM code
    > + SIP_CMD_COPYBACK, //6
    > + SIP_CMD_INIT, //7
    > + SIP_CMD_SCAN, //8
    > + SIP_CMD_SETKEY, //9
    > + SIP_CMD_CONFIG, //10
    > + SIP_CMD_BSS_INFO_UPDATE, //11
    > + SIP_CMD_LOOPBACK, //12 ROM code
    > + //do not add cmd before this line
    > + SIP_CMD_SET_WMM_PARAM,
    > + SIP_CMD_AMPDU_ACTION,
    > + SIP_CMD_HB_REQ, //15
    > + SIP_CMD_RESET_MAC, //16
    > + SIP_CMD_PRE_DOWN, //17
    > + SIP_CMD_SLEEP, /* for sleep testing */
    > + SIP_CMD_WAKEUP, /* for sleep testing */
    > + SIP_CMD_DEBUG, /* for general testing */
    > + SIP_CMD_GET_FW_VER, /* get fw rev. */
    > + SIP_CMD_SETVIF,
    > + SIP_CMD_SETSTA,
    > + SIP_CMD_PS,
    > + SIP_CMD_ATE,
    > + SIP_CMD_SUSPEND,
    > + SIP_CMD_RECALC_CREDIT,
    > + SIP_CMD_MAX,
    > +};
    > +
    > +enum {
    > + SIP_EVT_TARGET_ON = 0, //
    > + SIP_EVT_BOOTUP, //1 in ROM code
    > + SIP_EVT_COPYBACK, //2
    > + SIP_EVT_SCAN_RESULT, //3
    > + SIP_EVT_TX_STATUS, //4
    > + SIP_EVT_CREDIT_RPT, //5, in ROM code
    > + SIP_EVT_ERROR, //6
    > + SIP_EVT_LOOPBACK, //7, in ROM code
    > + SIP_EVT_SNPRINTF_TO_HOST, //8 in ROM code
    > + //do not add evt before this line
    > + SIP_EVT_HB_ACK, //9
    > + SIP_EVT_RESET_MAC_ACK, //10
    > + SIP_EVT_WAKEUP, //11 /* for sleep testing */
    > + SIP_EVT_DEBUG, //12 /* for general testing */
    > + SIP_EVT_PRINT_TO_HOST, //13
    > + SIP_EVT_TRC_AMPDU, //14
    > + SIP_EVT_ROC, //15
    > + SIP_EVT_RESETTING,
    > + SIP_EVT_ATE,
    > + SIP_EVT_EP,
    > + SIP_EVT_INIT_EP,
    > + SIP_EVT_SLEEP,
    > + SIP_EVT_TXIDLE,
    > + SIP_EVT_NOISEFLOOR,
    > + SIP_EVT_MAX
    > +};
    > +
    > +#define SIP_IFIDX_MASK 0xf0
    > +#define SIP_IFIDX_S 4
    > +#define SIP_TYPE_MASK 0x0f
    > +#define SIP_TYPE_S 0
    > +
    > +#define SIP_HDR_GET_IFIDX(fc0) (((fc0) & SIP_IFIDX_MASK) >> SIP_IFIDX_S)
    > +#define SIP_HDR_SET_IFIDX(fc0, ifidx) ((fc0) = ((fc0) & ~SIP_IFIDX_MASK) | ((ifidx) << SIP_IFIDX_S & SIP_IFIDX_MASK))
    > +#define SIP_HDR_GET_TYPE(fc0) ((fc0) & SIP_TYPE_MASK)
    > +/* assume type field is cleared */
    > +#define SIP_HDR_SET_TYPE(fc0, type) ((fc0) = ((fc0) & ~SIP_TYPE_MASK) | ((type) & SIP_TYPE_MASK))
    > +
    > +/* sip 2.0, not hybrid header so far */
    > +#define SIP_HDR_IS_CTRL(hdr) (SIP_HDR_GET_TYPE((hdr)->fc[0]) == SIP_CTRL)
    > +#define SIP_HDR_IS_DATA(hdr) (SIP_HDR_GET_TYPE((hdr)->fc[0]) == SIP_DATA)
    > +#define SIP_HDR_IS_AMPDU(hdr) (SIP_HDR_GET_TYPE((hdr)->fc[0]) == SIP_DATA_AMPDU)
    > +
    > +/* fc[1] flags, only for data pkt. Ctrl pkts use fc[1] as eventID */
    > +#define SIP_HDR_SET_FLAGS(hdr, flags) ((hdr)->fc[1] |= (flags))
    > +#define SIP_HDR_F_MORE_PKT 0x1
    > +#define SIP_HDR_F_NEED_CRDT_RPT 0x2
    > +#define SIP_HDR_F_SYNC 0x4
    > +#define SIP_HDR_F_SYNC_RESET 0x8
    > +#define SIP_HDR_F_PM_TURNING_ON 0x10
    > +#define SIP_HDR_F_PM_TURNING_OFF 0x20
    > +
    > +#define SIP_HDR_NEED_CREDIT_UPDATE(hdr) ((hdr)->fc[1] & SIP_HDR_F_NEED_CRDT_RPT)
    > +#define SIP_HDR_IS_MORE_PKT(hdr) ((hdr)->fc[1] & SIP_HDR_F_MORE_PKT)
    > +#define SIP_HDR_IS_CRDT_RPT(hdr) ((hdr)->fc[1] & SIP_HDR_F_CRDT_RPT)
    > +#define SIP_HDR_IS_SYNC(hdr) ((hdr)->fc[1] & SIP_HDR_F_SYNC)
    > +#define SIP_HDR_IS_SYNC_RESET(hdr) ((hdr)->fc[1] & SIP_HDR_F_SYNC_RESET)
    > +#define SIP_HDR_IS_SYNC_PKT(hdr) (SIP_HDR_IS_SYNC(hdr) | SIP_HDR_IS_SYNC_RESET(hdr))
    > +#define SIP_HDR_SET_SYNC(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_SYNC)
    > +#define SIP_HDR_SET_SYNC_RESET(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_SYNC_RESET)
    > +#define SIP_HDR_SET_MORE_PKT(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_MORE_PKT)
    > +#define SIP_HDR_SET_PM_TURNING_ON(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_PM_TURNING_ON)
    > +#define SIP_HDR_IS_PM_TURNING_ON(hdr) ((hdr)->fc[1] & SIP_HDR_F_PM_TURNING_ON)
    > +#define SIP_HDR_SET_PM_TURNING_OFF(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_PM_TURNING_OFF)
    > +#define SIP_HDR_IS_PM_TURNING_OFF(hdr) ((hdr)->fc[1] & SIP_HDR_F_PM_TURNING_OFF)
    > +
    > +/* fc[0]: first 4bit: ifidx; last 4bit: type
    > + * fc[1]: flags
    > + *
    > + * Don't touch the header definitons
    > + */
    > +struct sip_hdr_min {
    > + u8 fc[2];
    > + __le16 len;
    > +} __packed;
    > +
    > +/* not more than 4byte long */
    > +struct sip_tx_data_info {
    > + u8 tid;
    > + u8 ac;
    > + u8 p2p:1, enc_flag:7;
    > + u8 hw_kid;
    > +} __packed;
    > +
    > +/* NB: this structure should be not more than 4byte !! */
    > +struct sip_tx_info {
    > + union {
    > + u32 cmdid;
    > + struct sip_tx_data_info dinfo;
    > + } u;
    > +} __packed;
    > +
    > +struct sip_hdr {
    > + u8 fc[2]; //fc[0]: type and ifidx ; fc[1] is eventID if the first ctrl pkt in the chain. data pkt still can use fc[1] to set flag
    > + __le16 len;
    > + union {
    > + volatile u32 recycled_credits; /* last 12bits is credits, first 20 bits is actual length of the first pkt in the chain */

    Remove the volatile.

    > + struct sip_tx_info tx_info;
    > + } u;

    If you just remove the "u" and make this an anonymous union then
    it makes everything a easier.

    > + u32 seq;
    > +} __packed;
    > +
    > +#define h_credits u.recycled_credits

    It means we can get rid of these ugly defines.

    > +#define c_evtid fc[1]
    > +#define c_cmdid u.tx_info.u.cmdid
    > +#define d_ac u.tx_info.u.dinfo.ac
    > +#define d_tid u.tx_info.u.dinfo.tid
    > +#define d_p2p u.tx_info.u.dinfo.p2p
    > +#define d_enc_flag u.tx_info.u.dinfo.enc_flag
    > +#define d_hw_kid u.tx_info.u.dinfo.hw_kid
    > +
    > +#define SIP_CREDITS_MASK 0xfff /* last 12 bits */
    > +
    > +#define SIP_HDR_MIN_LEN 4
    > +#define SIP_HDR_LEN sizeof(struct sip_hdr)
    > +#define SIP_CTRL_HDR_LEN SIP_HDR_LEN /* same as sip_hdr in sip2 design */
    > +#define SIP_BOOT_BUF_SIZE 256
    > +#define SIP_CTRL_BUF_SZ 256 /* too much?? */
    > +#define SIP_CTRL_BUF_N 6
    > +#define SIP_CTRL_TXBUF_N 2
    > +#define SIP_CTRL_RXBUF_N 4
    > +
    > +/* WAR for mblk */
    > +#define SIP_RX_ADDR_PREFIX_MASK 0xfc000000
    > +#define SIP_RX_ADDR_SHIFT 6 /* [31:5], shift 6 bits */
    > +
    > +struct sip_cmd_write_memory {
    > + u32 addr;
    > + u32 len;
    > +} __packed;
    > +
    > +struct sip_cmd_read_memory {
    > + u32 addr;
    > + u32 len;
    > +} __packed;
    > +
    > +struct sip_cmd_write_reg {
    > + u32 addr;
    > + u32 val;
    > +} __packed;
    > +
    > +struct sip_cmd_bootup {
    > + u32 boot_addr;
    > +} __packed;
    > +
    > +struct sip_cmd_loopback {
    > + u32 txlen; //host to target packet len, 0 means no txpacket
    > + u32 rxlen; //target to host packet len, 0 means no rxpacket
    > + u32 pack_id; //sequence of packet
    > +} __packed;
    > +
    > +struct sip_evt_loopback {
    > + u32 txlen; //host to target packet len, 0 means no txpacket
    > + u32 rxlen; //target to host packet len, 0 means no rxpacket
    > + u32 pack_id; //sequence of packet
    > +} __packed;
    > +
    > +struct sip_cmd_copyback {
    > + u32 addr;
    > + u32 len;
    > +} __packed;
    > +
    > +struct sip_cmd_scan {
    > + // u8 ssid[32];
    > + u8 ssid_len;
    > + // u8 hw_channel[14];
    > + u8 n_channels;
    > + u8 ie_len;
    > + u8 aborted;
    > +} __packed; // ie[] append at the end
    > +
    > +struct sip_cmd_setkey {
    > + u8 bssid_no;
    > + u8 addr[ETH_ALEN];
    > + u8 alg;
    > + u8 keyidx;
    > + u8 hw_key_idx;
    > + u8 flags;
    > + u8 keylen;
    > + u8 key[32];
    > +} __packed;
    > +
    > +struct sip_cmd_config {
    > + u16 center_freq;
    > + u16 duration;
    > +} __packed;
    > +
    > +struct sip_cmd_bss_info_update {
    > + u8 bssid[ETH_ALEN];
    > + u16 isassoc;
    > + u32 beacon_int;
    > + u8 bssid_no;
    > +} __packed;
    > +
    > +struct sip_evt_bootup {
    > + u16 tx_blksz;
    > + u8 mac_addr[ETH_ALEN];
    > + /* anything else ? */
    > +} __packed;
    > +
    > +struct sip_cmd_setvif {
    > + u8 index;
    > + u8 mac[ETH_ALEN];
    > + u8 set;
    > + u8 op_mode;
    > + u8 is_p2p;
    > +} __packed;
    > +
    > +enum esp_ieee80211_phytype {
    > + ESP_IEEE80211_T_CCK = 0,
    > + ESP_IEEE80211_T_OFDM = 1,
    > + ESP_IEEE80211_T_HT20_L = 2,
    > + ESP_IEEE80211_T_HT20_S = 3,
    > +};
    > +
    > +struct sip_cmd_setsta {
    > + u8 ifidx;
    > + u8 index;
    > + u8 set;
    > + u8 phymode;
    > + u8 mac[ETH_ALEN];
    > + u16 aid;
    > + u8 ampdu_factor;
    > + u8 ampdu_density;
    > + u16 resv;
    > +} __packed;
    > +
    > +struct sip_cmd_ps {
    > + u8 dtim_period;
    > + u8 max_sleep_period;
    > + u8 on;
    > + u8 resv;
    > +} __packed;
    > +
    > +struct sip_cmd_suspend {
    > + u8 suspend;
    > + u8 resv[3];
    > +} __packed;
    > +
    > +#define SIP_DUMP_RPBM_ERR BIT(0)
    > +#define SIP_RXABORT_FIXED BIT(1)
    > +#define SIP_SUPPORT_BGSCAN BIT(2)
    > +struct sip_evt_bootup2 {
    > + u16 tx_blksz;
    > + u8 mac_addr[ETH_ALEN];
    > + u16 rx_blksz;
    > + u8 credit_to_reserve;
    > + u8 options;
    > + s16 noise_floor;
    > + u8 resv[2];
    > + /* anything else ? */
    > +} __packed;
    > +
    > +enum trc_ampdu_state {
    > + TRC_TX_AMPDU_STOPPED = 1,
    > + TRC_TX_AMPDU_OPERATIONAL,
    > + TRC_TX_AMPDU_WAIT_STOP,
    > + TRC_TX_AMPDU_WAIT_OPERATIONAL,
    > + TRC_TX_AMPDU_START,
    > +};
    > +
    > +struct sip_evt_trc_ampdu {
    > + u8 state;
    > + u8 tid;
    > + u8 addr[ETH_ALEN];
    > +} __packed;
    > +
    > +struct sip_cmd_set_wmm_params {
    > + u8 aci;
    > + u8 aifs;
    > + u8 ecw_min;
    > + u8 ecw_max;
    > + u16 txop_us;
    > +} __packed;
    > +
    > +#define SIP_AMPDU_RX_START 0
    > +#define SIP_AMPDU_RX_STOP 1
    > +#define SIP_AMPDU_TX_OPERATIONAL 2
    > +#define SIP_AMPDU_TX_STOP 3
    > +
    > +struct sip_cmd_ampdu_action {
    > + u8 action;
    > + u8 index;
    > + u8 tid;
    > + u8 win_size;
    > + u16 ssn;
    > + u8 addr[ETH_ALEN];
    > +} __packed;
    > +
    > +#define SIP_TX_ST_OK 0
    > +#define SIP_TX_ST_NOEB 1
    > +#define SIP_TX_ST_ACKTO 2
    > +#define SIP_TX_ST_ENCERR 3
    > +
    > +//NB: sip_tx_status must be 4 bytes aligned
    > +struct sip_tx_status {
    > + u32 sip_seq;
    > + u8 errno; /* success or failure code */
    > + u8 rate_index;
    > + char ack_signal;
    > + u8 pad;
    > +} __packed;
    > +
    > +struct sip_evt_scan_report {
    > + u16 scan_id;
    > + u16 aborted;
    > +} __packed;
    > +
    > +struct sip_evt_roc {
    > + u16 state; //start:1, end :0
    > + u16 is_ok;
    > +} __packed;
    > +
    > +struct sip_evt_txidle {
    > + u32 last_seq;
    > +} __packed;
    > +
    > +struct sip_evt_noisefloor {
    > + s16 noise_floor;
    > + u16 pad;
    > +} __packed;
    > +/* for mblk direct memory access, no need for sip_hdr. tx: first 2k for contrl msg,
    > + * rest of 14k for data. rx, same.
    > + */
    > +
    > +#endif /* _SIP_COMMON_H_ */
    > diff --git a/drivers/staging/esp8089/slc_host_register.h b/drivers/staging/esp8089/slc_host_register.h
    > new file mode 100644
    > index 000000000000..8cf139c0d7bc
    > --- /dev/null
    > +++ b/drivers/staging/esp8089/slc_host_register.h
    > @@ -0,0 +1,263 @@
    > +/*
    > + * Copyright (c) 2011 Espressif System.
    > + * Copyright (c) 2017 Free Electrons
    > + * Quentin Schulz <quentin.schulz@free-electrons.com>
    > + *
    > + * 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.
    > + *
    > + */
    > +
    > +#ifndef SLC_HOST_REGISTER_H_INCLUDED
    > +#define SLC_HOST_REGISTER_H_INCLUDED
    > +
    > +/* #define REG_SLC_HOST_BASE 0x00000000 */
    > +/* skip the token1, since reading it will clean the credit */
    > +#define REG_SLC_HOST_BASE 0x00000000
    > +#define REG_SLC_BASE 0x00000000
    > +
    > +#define SLC_HOST_PF (REG_SLC_HOST_BASE + 0x0)
    > +#define SLC_HOST_TOKEN_RDATA (REG_SLC_HOST_BASE + 0x4)
    > +#define SLC_HOST_RX_PF_EOF 0x0000000F
    > +#define SLC_HOST_RX_PF_EOF_S 28
    > +#define SLC_HOST_TOKEN1 0x00000FFF
    > +#define SLC_HOST_TOKEN1_S 16
    > +#define SLC_HOST_RX_PF_VALID BIT(15)
    > +#define SLC_HOST_TOKEN0 0x00000FFF
    > +#define SLC_HOST_TOKEN0_S 0
    > +
    > +#define SLC_HOST_TOKEN0_MASK SLC_HOST_TOKEN0
    > +#define SLC_HOST_INT_RAW (REG_SLC_HOST_BASE + 0x8)
    > +#define SLC_HOST_EXT_BIT3_INT_RAW BIT(22)
    > +#define SLC_HOST_EXT_BIT2_INT_RAW BIT(21)
    > +#define SLC_HOST_EXT_BIT1_INT_RAW BIT(20)
    > +#define SLC_HOST_RXFIFO_NOT_EMPTY_INT_RAW BIT(19)
    > +#define SLC_HOST_RX_PF_VALID_INT_RAW BIT(18)
    > +#define SLC_HOST_TX_OVF_INT_RAW BIT(17)
    > +#define SLC_HOST_RX_UDF_INT_RAW BIT(16)
    > +#define SLC_HOST_TX_START_INT_RAW BIT(15)
    > +#define SLC_HOST_RX_START_INT_RAW BIT(14)
    > +#define SLC_HOST_RX_EOF_INT_RAW BIT(13)
    > +#define SLC_HOST_RX_SOF_INT_RAW BIT(12)
    > +#define SLC_HOST_TOKEN1_0TO1_INT_RAW BIT(11)
    > +#define SLC_HOST_TOKEN0_0TO1_INT_RAW BIT(10)
    > +#define SLC_HOST_TOKEN1_1TO0_INT_RAW BIT(9)
    > +#define SLC_HOST_TOKEN0_1TO0_INT_RAW BIT(8)
    > +#define SLC_HOST_TOHOST_BIT7_INT_RAW BIT(7)
    > +#define SLC_HOST_TOHOST_BIT6_INT_RAW BIT(6)
    > +#define SLC_HOST_TOHOST_BIT5_INT_RAW BIT(5)
    > +#define SLC_HOST_TOHOST_BIT4_INT_RAW BIT(4)
    > +#define SLC_HOST_TOHOST_BIT3_INT_RAW BIT(3)
    > +#define SLC_HOST_TOHOST_BIT2_INT_RAW BIT(2)
    > +#define SLC_HOST_TOHOST_BIT1_INT_RAW BIT(1)
    > +#define SLC_HOST_TOHOST_BIT0_INT_RAW BIT(0)
    > +
    > +#define SLC_HOST_STATE_W0 (REG_SLC_HOST_BASE + 0xC)
    > +#define SLC_HOST_STATE3 0x000000FF
    > +#define SLC_HOST_STATE3_S 24
    > +#define SLC_HOST_STATE2 0x000000FF
    > +#define SLC_HOST_STATE2_S 16
    > +#define SLC_HOST_STATE1 0x000000FF
    > +#define SLC_HOST_STATE1_S 8
    > +#define SLC_HOST_STATE0 0x000000FF
    > +#define SLC_HOST_STATE0_S 0
    > +
    > +#define SLC_HOST_STATE_W1 (REG_SLC_HOST_BASE + 0x10)
    > +#define SLC_HOST_STATE7 0x000000FF
    > +#define SLC_HOST_STATE7_S 24
    > +#define SLC_HOST_STATE6 0x000000FF
    > +#define SLC_HOST_STATE6_S 16
    > +#define SLC_HOST_STATE5 0x000000FF
    > +#define SLC_HOST_STATE5_S 8
    > +#define SLC_HOST_STATE4 0x000000FF
    > +#define SLC_HOST_STATE4_S 0
    > +
    > +#define SLC_HOST_CONF_W0 (REG_SLC_HOST_BASE + 0x14)
    > +#define SLC_HOST_CONF3 0x000000FF
    > +#define SLC_HOST_CONF3_S 24
    > +#define SLC_HOST_CONF2 0x000000FF
    > +#define SLC_HOST_CONF2_S 16
    > +#define SLC_HOST_CONF1 0x000000FF
    > +#define SLC_HOST_CONF1_S 8
    > +#define SLC_HOST_CONF0 0x000000FF
    > +#define SLC_HOST_CONF0_S 0
    > +
    > +#define SLC_HOST_CONF_W1 (REG_SLC_HOST_BASE + 0x18)
    > +#define SLC_HOST_CONF7 0x000000FF
    > +#define SLC_HOST_CONF7_S 24
    > +#define SLC_HOST_CONF6 0x000000FF
    > +#define SLC_HOST_CONF6_S 16
    > +#define SLC_HOST_CONF5 0x000000FF
    > +#define SLC_HOST_CONF5_S 8
    > +#define SLC_HOST_CONF4 0x000000FF
    > +#define SLC_HOST_CONF4_S 0
    > +
    > +#define SLC_HOST_INT_ST (REG_SLC_HOST_BASE + 0x1C)
    > +#define SLC_HOST_RX_ST BIT(23)
    > +#define SLC_HOST_EXT_BIT3_INT_ST BIT(22)
    > +#define SLC_HOST_EXT_BIT2_INT_ST BIT(21)
    > +#define SLC_HOST_EXT_BIT1_INT_ST BIT(20)
    > +#define SLC_HOST_RXFIFO_NOT_EMPTY_INT_ST BIT(19)
    > +#define SLC_HOST_RX_PF_VALID_INT_ST BIT(18)
    > +#define SLC_HOST_TX_OVF_INT_ST BIT(17)
    > +#define SLC_HOST_RX_UDF_INT_ST BIT(16)
    > +#define SLC_HOST_TX_START_INT_ST BIT(15)
    > +#define SLC_HOST_RX_START_INT_ST BIT(14)
    > +#define SLC_HOST_RX_EOF_INT_ST BIT(13)
    > +#define SLC_HOST_RX_SOF_INT_ST BIT(12)
    > +#define SLC_HOST_TOKEN1_0TO1_INT_ST BIT(11)
    > +#define SLC_HOST_TOKEN0_0TO1_INT_ST BIT(10)
    > +#define SLC_HOST_TOKEN1_1TO0_INT_ST BIT(9)
    > +#define SLC_HOST_TOKEN0_1TO0_INT_ST BIT(8)
    > +#define SLC_HOST_TOHOST_BIT7_INT_ST BIT(7)
    > +#define SLC_HOST_TOHOST_BIT6_INT_ST BIT(6)
    > +#define SLC_HOST_TOHOST_BIT5_INT_ST BIT(5)
    > +#define SLC_HOST_TOHOST_BIT4_INT_ST BIT(4)
    > +#define SLC_HOST_TOHOST_BIT3_INT_ST BIT(3)
    > +#define SLC_HOST_TOHOST_BIT2_INT_ST BIT(2)
    > +#define SLC_HOST_TOHOST_BIT1_INT_ST BIT(1)
    > +#define SLC_HOST_TOHOST_BIT0_INT_ST BIT(0)
    > +
    > +#define SLC_HOST_CONF_W2 (REG_SLC_HOST_BASE + 0x20)
    > +#define SLC_HOST_CONF11 0x000000FF
    > +#define SLC_HOST_CONF11_S 24
    > +#define SLC_HOST_CONF10 0x000000FF
    > +#define SLC_HOST_CONF10_S 16
    > +#define SLC_HOST_CONF9 0x000000FF
    > +#define SLC_HOST_CONF9_S 8
    > +#define SLC_HOST_CONF8 0x000000FF
    > +#define SLC_HOST_CONF8_S 0
    > +
    > +#define SLC_HOST_CONF_W3 (REG_SLC_HOST_BASE + 0x24)
    > +#define SLC_HOST_CONF15 0x000000FF
    > +#define SLC_HOST_CONF15_S 24
    > +#define SLC_HOST_CONF14 0x000000FF
    > +#define SLC_HOST_CONF14_S 16
    > +#define SLC_HOST_CONF13 0x000000FF
    > +#define SLC_HOST_CONF13_S 8
    > +#define SLC_HOST_CONF12 0x000000FF
    > +#define SLC_HOST_CONF12_S 0
    > +
    > +#define SLC_HOST_GEN_TXDONE_INT BIT(16)
    > +#define SLC_HOST_GEN_RXDONE_INT BIT(17)
    > +
    > +#define SLC_HOST_CONF_W4 (REG_SLC_HOST_BASE + 0x28)
    > +#define SLC_HOST_CONF19 0x000000FF
    > +#define SLC_HOST_CONF19_S 24
    > +#define SLC_HOST_CONF18 0x000000FF
    > +#define SLC_HOST_CONF18_S 16
    > +#define SLC_HOST_CONF17 0x000000FF
    > +#define SLC_HOST_CONF17_S 8
    > +#define SLC_HOST_CONF16 0x000000FF
    > +#define SLC_HOST_CONF16_S 0
    > +
    > +#define SLC_HOST_TOKEN_WDATA (REG_SLC_HOST_BASE + 0x2C)
    > +#define SLC_HOST_TOKEN1_WD 0x00000FFF
    > +#define SLC_HOST_TOKEN1_WD_S 16
    > +#define SLC_HOST_TOKEN0_WD 0x00000FFF
    > +#define SLC_HOST_TOKEN0_WD_S 0
    > +
    > +#define SLC_HOST_INT_CLR (REG_SLC_HOST_BASE + 0x30)
    > +#define SLC_HOST_TOKEN1_WR BIT(31)
    > +#define SLC_HOST_TOKEN0_WR BIT(30)
    > +#define SLC_HOST_TOKEN1_DEC BIT(29)
    > +#define SLC_HOST_TOKEN0_DEC BIT(28)
    > +#define SLC_HOST_EXT_BIT3_INT_CLR BIT(22)
    > +#define SLC_HOST_EXT_BIT2_INT_CLR BIT(21)
    > +#define SLC_HOST_EXT_BIT1_INT_CLR BIT(20)
    > +#define SLC_HOST_EXT_BIT0_INT_CLR BIT(19)
    > +#define SLC_HOST_RX_PF_VALID_INT_CLR BIT(18)
    > +#define SLC_HOST_TX_OVF_INT_CLR BIT(17)
    > +#define SLC_HOST_RX_UDF_INT_CLR BIT(16)
    > +#define SLC_HOST_TX_START_INT_CLR BIT(15)
    > +#define SLC_HOST_RX_START_INT_CLR BIT(14)
    > +#define SLC_HOST_RX_EOF_INT_CLR BIT(13)
    > +#define SLC_HOST_RX_SOF_INT_CLR BIT(12)
    > +#define SLC_HOST_TOKEN1_0TO1_INT_CLR BIT(11)
    > +#define SLC_HOST_TOKEN0_0TO1_INT_CLR BIT(10)
    > +#define SLC_HOST_TOKEN1_1TO0_INT_CLR BIT(9)
    > +#define SLC_HOST_TOKEN0_1TO0_INT_CLR BIT(8)
    > +#define SLC_HOST_TOHOST_BIT7_INT_CLR BIT(7)
    > +#define SLC_HOST_TOHOST_BIT6_INT_CLR BIT(6)
    > +#define SLC_HOST_TOHOST_BIT5_INT_CLR BIT(5)
    > +#define SLC_HOST_TOHOST_BIT4_INT_CLR BIT(4)
    > +#define SLC_HOST_TOHOST_BIT3_INT_CLR BIT(3)
    > +#define SLC_HOST_TOHOST_BIT2_INT_CLR BIT(2)
    > +#define SLC_HOST_TOHOST_BIT1_INT_CLR BIT(1)
    > +#define SLC_HOST_TOHOST_BIT0_INT_CLR BIT(0)
    > +
    > +#define SLC_HOST_INT_ENA (REG_SLC_HOST_BASE + 0x34)
    > +#define SLC_HOST_EXT_BIT3_INT_ENA BIT(22)
    > +#define SLC_HOST_EXT_BIT2_INT_ENA BIT(21)
    > +#define SLC_HOST_EXT_BIT1_INT_ENA BIT(20)
    > +#define SLC_HOST_EXT_BIT0_INT_ENA BIT(19)
    > +#define SLC_HOST_RX_PF_VALID_INT_ENA BIT(18)
    > +#define SLC_HOST_TX_OVF_INT_ENA BIT(17)
    > +#define SLC_HOST_RX_UDF_INT_ENA BIT(16)
    > +#define SLC_HOST_TX_START_INT_ENA BIT(15)
    > +#define SLC_HOST_RX_START_INT_ENA BIT(14)
    > +#define SLC_HOST_RX_EOF_INT_ENA BIT(13)
    > +#define SLC_HOST_RX_SOF_INT_ENA BIT(12)
    > +#define SLC_HOST_TOKEN1_0TO1_INT_ENA BIT(11)
    > +#define SLC_HOST_TOKEN0_0TO1_INT_ENA BIT(10)
    > +#define SLC_HOST_TOKEN1_1TO0_INT_ENA BIT(9)
    > +#define SLC_HOST_TOKEN0_1TO0_INT_ENA BIT(8)
    > +#define SLC_HOST_TOHOST_BIT7_INT_ENA BIT(7)
    > +#define SLC_HOST_TOHOST_BIT6_INT_ENA BIT(6)
    > +#define SLC_HOST_TOHOST_BIT5_INT_ENA BIT(5)
    > +#define SLC_HOST_TOHOST_BIT4_INT_ENA BIT(4)
    > +#define SLC_HOST_TOHOST_BIT3_INT_ENA BIT(3)
    > +#define SLC_HOST_TOHOST_BIT2_INT_ENA BIT(2)
    > +#define SLC_HOST_TOHOST_BIT1_INT_ENA BIT(1)
    > +#define SLC_HOST_TOHOST_BIT0_INT_ENA BIT(0)
    > +
    > +#define SLC_HOST_CONF_W5 (REG_SLC_HOST_BASE + 0x3C)
    > +#define SLC_HOST_CONF23 0x000000FF
    > +#define SLC_HOST_CONF23_S 24
    > +#define SLC_HOST_CONF22 0x000000FF
    > +#define SLC_HOST_CONF22_S 16
    > +#define SLC_HOST_CONF21 0x000000FF
    > +#define SLC_HOST_CONF21_S 8
    > +#define SLC_HOST_CONF20 0x000000FF
    > +#define SLC_HOST_CONF20_S 0
    > +
    > +#define SLC_HOST_WIN_CMD (REG_SLC_HOST_BASE + 0x40)
    > +
    > +#define SLC_HOST_DATE (REG_SLC_HOST_BASE + 0x78)
    > +#define SLC_HOST_ID (REG_SLC_HOST_BASE + 0x7C)
    > +
    > +#define SLC_ADDR_WINDOW_CLEAR_MASK (~(0xf << 12))
    > +#define SLC_FROM_HOST_ADDR_WINDOW BIT(12)
    > +#define SLC_TO_HOST_ADDR_WINDOW (0x3 << 12)
    > +
    > +#define SLC_SET_FROM_HOST_ADDR_WINDOW(v) do { \
    > + (v) &= 0xffff; \
    > + (v) &= SLC_ADDR_WINDOW_CLEAR_MASK; \
    > + (v) |= SLC_FROM_HOST_ADDR_WINDOW; \
    > +} while (0)
    > +
    > +#define SLC_SET_TO_HOST_ADDR_WINDOW(v) do { \
    > + (v) &= 0xffff; \
    > + (v) &= SLC_ADDR_WINDOW_CLEAR_MASK; \
    > + (v) |= SLC_TO_HOST_ADDR_WINDOW; \
    > +} while (0)
    > +
    > +#define SLC_INT_ENA (REG_SLC_BASE + 0xC)
    > +#define SLC_RX_EOF_INT_ENA BIT(17)
    > +#define SLC_FRHOST_BIT2_INT_ENA BIT(2)
    > +
    > +#define SLC_RX_LINK (REG_SLC_BASE + 0x24)
    > +#define SLC_RXLINK_START BIT(29)
    > +
    > +#define SLC_BRIDGE_CONF (REG_SLC_BASE + 0x44)
    > +#define SLC_TX_PUSH_IDLE_NUM 0xFFFF
    > +#define SLC_TX_PUSH_IDLE_NUM_S 16
    > +#define SLC_HDA_MAP_128K BIT(13)
    > +#define SLC_TX_DUMMY_MODE BIT(12)
    > +#define SLC_FIFO_MAP_ENA 0x0000000F
    > +#define SLC_FIFO_MAP_ENA_S 8
    > +#define SLC_TXEOF_ENA 0x0000003F
    > +#define SLC_TXEOF_ENA_S
    > +
    > +#endif // SLC_HOST_REGISTER_H_INCLUDED
    > --
    > 2.11.0
    >
    >
    > _______________________________________________
    > devel mailing list
    > devel@linuxdriverproject.org
    > http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

    \
     
     \ /
      Last update: 2017-07-25 12:35    [W:4.231 / U:0.072 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site