linux/drivers/staging/wfx/hif_tx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx
   4 * Split Mac (WSM) API.
   5 *
   6 * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
   7 * Copyright (c) 2010, ST-Ericsson
   8 */
   9#include <linux/skbuff.h>
  10#include <linux/etherdevice.h>
  11
  12#include "hif_tx.h"
  13#include "wfx.h"
  14#include "bh.h"
  15#include "hwio.h"
  16#include "debug.h"
  17#include "sta.h"
  18
  19void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
  20{
  21        init_completion(&hif_cmd->ready);
  22        init_completion(&hif_cmd->done);
  23        mutex_init(&hif_cmd->lock);
  24        mutex_init(&hif_cmd->key_renew_lock);
  25}
  26
  27static void wfx_fill_header(struct hif_msg *hif, int if_id, unsigned int cmd,
  28                            size_t size)
  29{
  30        if (if_id == -1)
  31                if_id = 2;
  32
  33        WARN(cmd > 0x3f, "invalid WSM command %#.2x", cmd);
  34        WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size);
  35        WARN(if_id > 0x3, "invalid interface ID %d", if_id);
  36
  37        hif->len = cpu_to_le16(size + 4);
  38        hif->id = cmd;
  39        hif->interface = if_id;
  40}
  41
  42static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif)
  43{
  44        *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL);
  45        if (*hif)
  46                return (*hif)->body;
  47        else
  48                return NULL;
  49}
  50
  51int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply,
  52                 size_t reply_len, bool async)
  53{
  54        const char *mib_name = "";
  55        const char *mib_sep = "";
  56        int cmd = request->id;
  57        int vif = request->interface;
  58        int ret;
  59
  60        WARN(wdev->hif_cmd.buf_recv && wdev->hif_cmd.async, "API usage error");
  61
  62        // Do not wait for any reply if chip is frozen
  63        if (wdev->chip_frozen)
  64                return -ETIMEDOUT;
  65
  66        if (cmd != HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS)
  67                mutex_lock(&wdev->hif_cmd.key_renew_lock);
  68
  69        mutex_lock(&wdev->hif_cmd.lock);
  70        WARN(wdev->hif_cmd.buf_send, "data locking error");
  71
  72        // Note: call to complete() below has an implicit memory barrier that
  73        // hopefully protect buf_send
  74        wdev->hif_cmd.buf_send = request;
  75        wdev->hif_cmd.buf_recv = reply;
  76        wdev->hif_cmd.len_recv = reply_len;
  77        wdev->hif_cmd.async = async;
  78        complete(&wdev->hif_cmd.ready);
  79
  80        wfx_bh_request_tx(wdev);
  81
  82        // NOTE: no timeout is catched async is enabled
  83        if (async)
  84                return 0;
  85
  86        ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ);
  87        if (!ret) {
  88                dev_err(wdev->dev, "chip is abnormally long to answer\n");
  89                reinit_completion(&wdev->hif_cmd.ready);
  90                ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ);
  91        }
  92        if (!ret) {
  93                dev_err(wdev->dev, "chip did not answer\n");
  94                wfx_pending_dump_old_frames(wdev, 3000);
  95                wdev->chip_frozen = 1;
  96                reinit_completion(&wdev->hif_cmd.done);
  97                ret = -ETIMEDOUT;
  98        } else {
  99                ret = wdev->hif_cmd.ret;
 100        }
 101
 102        wdev->hif_cmd.buf_send = NULL;
 103        mutex_unlock(&wdev->hif_cmd.lock);
 104
 105        if (ret &&
 106            (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) {
 107                mib_name = get_mib_name(((u16 *) request)[2]);
 108                mib_sep = "/";
 109        }
 110        if (ret < 0)
 111                dev_err(wdev->dev,
 112                        "WSM request %s%s%s (%#.2x) on vif %d returned error %d\n",
 113                        get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
 114        if (ret > 0)
 115                dev_warn(wdev->dev,
 116                         "WSM request %s%s%s (%#.2x) on vif %d returned status %d\n",
 117                         get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
 118
 119        if (cmd != HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS)
 120                mutex_unlock(&wdev->hif_cmd.key_renew_lock);
 121        return ret;
 122}
 123
 124// This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any
 125// request anymore. We need to slightly hack struct wfx_hif_cmd for that job. Be
 126// carefull to only call this funcion during device unregister.
 127int hif_shutdown(struct wfx_dev *wdev)
 128{
 129        int ret;
 130        struct hif_msg *hif;
 131
 132        wfx_alloc_hif(0, &hif);
 133        wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0);
 134        ret = wfx_cmd_send(wdev, hif, NULL, 0, true);
 135        // After this command, chip won't reply. Be sure to give enough time to
 136        // bh to send buffer:
 137        msleep(100);
 138        wdev->hif_cmd.buf_send = NULL;
 139        if (wdev->pdata.gpio_wakeup)
 140                gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
 141        else
 142                control_reg_write(wdev, 0);
 143        mutex_unlock(&wdev->hif_cmd.lock);
 144        kfree(hif);
 145        return ret;
 146}
 147
 148int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
 149{
 150        int ret;
 151        size_t buf_len = sizeof(struct hif_req_configuration) + len;
 152        struct hif_msg *hif;
 153        struct hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif);
 154
 155        body->length = cpu_to_le16(len);
 156        memcpy(body->pds_data, conf, len);
 157        wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len);
 158        ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
 159        kfree(hif);
 160        return ret;
 161}
 162
 163int hif_reset(struct wfx_vif *wvif, bool reset_stat)
 164{
 165        int ret;
 166        struct hif_msg *hif;
 167        struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif);
 168
 169        body->reset_flags.reset_stat = reset_stat;
 170        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body));
 171        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 172        kfree(hif);
 173        return ret;
 174}
 175
 176int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val,
 177                 size_t val_len)
 178{
 179        int ret;
 180        struct hif_msg *hif;
 181        int buf_len = sizeof(struct hif_cnf_read_mib) + val_len;
 182        struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif);
 183        struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL);
 184
 185        body->mib_id = cpu_to_le16(mib_id);
 186        wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body));
 187        ret = wfx_cmd_send(wdev, hif, reply, buf_len, false);
 188
 189        if (!ret && mib_id != reply->mib_id) {
 190                dev_warn(wdev->dev,
 191                         "%s: confirmation mismatch request\n", __func__);
 192                ret = -EIO;
 193        }
 194        if (ret == -ENOMEM)
 195                dev_err(wdev->dev,
 196                        "buffer is too small to receive %s (%zu < %d)\n",
 197                        get_mib_name(mib_id), val_len, reply->length);
 198        if (!ret)
 199                memcpy(val, &reply->mib_data, reply->length);
 200        else
 201                memset(val, 0xFF, val_len);
 202        kfree(hif);
 203        kfree(reply);
 204        return ret;
 205}
 206
 207int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val,
 208                  size_t val_len)
 209{
 210        int ret;
 211        struct hif_msg *hif;
 212        int buf_len = sizeof(struct hif_req_write_mib) + val_len;
 213        struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif);
 214
 215        body->mib_id = cpu_to_le16(mib_id);
 216        body->length = cpu_to_le16(val_len);
 217        memcpy(&body->mib_data, val, val_len);
 218        wfx_fill_header(hif, vif_id, HIF_REQ_ID_WRITE_MIB, buf_len);
 219        ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
 220        kfree(hif);
 221        return ret;
 222}
 223
 224int hif_scan(struct wfx_vif *wvif, const struct wfx_scan_params *arg)
 225{
 226        int ret, i;
 227        struct hif_msg *hif;
 228        struct hif_ssid_def *ssids;
 229        size_t buf_len = sizeof(struct hif_req_start_scan) +
 230                arg->scan_req.num_of_channels * sizeof(u8) +
 231                arg->scan_req.num_of_ssi_ds * sizeof(struct hif_ssid_def);
 232        struct hif_req_start_scan *body = wfx_alloc_hif(buf_len, &hif);
 233        u8 *ptr = (u8 *) body + sizeof(*body);
 234
 235        WARN(arg->scan_req.num_of_channels > HIF_API_MAX_NB_CHANNELS, "invalid params");
 236        WARN(arg->scan_req.num_of_ssi_ds > 2, "invalid params");
 237        WARN(arg->scan_req.band > 1, "invalid params");
 238
 239        // FIXME: This API is unnecessary complex, fixing NumOfChannels and
 240        // adding a member SsidDef at end of struct hif_req_start_scan would
 241        // simplify that a lot.
 242        memcpy(body, &arg->scan_req, sizeof(*body));
 243        cpu_to_le32s(&body->min_channel_time);
 244        cpu_to_le32s(&body->max_channel_time);
 245        cpu_to_le32s(&body->tx_power_level);
 246        memcpy(ptr, arg->ssids,
 247               arg->scan_req.num_of_ssi_ds * sizeof(struct hif_ssid_def));
 248        ssids = (struct hif_ssid_def *) ptr;
 249        for (i = 0; i < body->num_of_ssi_ds; ++i)
 250                cpu_to_le32s(&ssids[i].ssid_length);
 251        ptr += arg->scan_req.num_of_ssi_ds * sizeof(struct hif_ssid_def);
 252        memcpy(ptr, arg->ch, arg->scan_req.num_of_channels * sizeof(u8));
 253        ptr += arg->scan_req.num_of_channels * sizeof(u8);
 254        WARN(buf_len != ptr - (u8 *) body, "allocation size mismatch");
 255        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len);
 256        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 257        kfree(hif);
 258        return ret;
 259}
 260
 261int hif_stop_scan(struct wfx_vif *wvif)
 262{
 263        int ret;
 264        struct hif_msg *hif;
 265        // body associated to HIF_REQ_ID_STOP_SCAN is empty
 266        wfx_alloc_hif(0, &hif);
 267
 268        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0);
 269        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 270        kfree(hif);
 271        return ret;
 272}
 273
 274int hif_join(struct wfx_vif *wvif, const struct hif_req_join *arg)
 275{
 276        int ret;
 277        struct hif_msg *hif;
 278        struct hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif);
 279
 280        memcpy(body, arg, sizeof(struct hif_req_join));
 281        cpu_to_le16s(&body->channel_number);
 282        cpu_to_le16s(&body->atim_window);
 283        cpu_to_le32s(&body->ssid_length);
 284        cpu_to_le32s(&body->beacon_interval);
 285        cpu_to_le32s(&body->basic_rate_set);
 286        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body));
 287        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 288        kfree(hif);
 289        return ret;
 290}
 291
 292int hif_set_bss_params(struct wfx_vif *wvif,
 293                       const struct hif_req_set_bss_params *arg)
 294{
 295        int ret;
 296        struct hif_msg *hif;
 297        struct hif_req_set_bss_params *body = wfx_alloc_hif(sizeof(*body),
 298                                                            &hif);
 299
 300        memcpy(body, arg, sizeof(*body));
 301        cpu_to_le16s(&body->aid);
 302        cpu_to_le32s(&body->operational_rate_set);
 303        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS,
 304                        sizeof(*body));
 305        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 306        kfree(hif);
 307        return ret;
 308}
 309
 310int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg)
 311{
 312        int ret;
 313        struct hif_msg *hif;
 314        // FIXME: only send necessary bits
 315        struct hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif);
 316
 317        // FIXME: swap bytes as necessary in body
 318        memcpy(body, arg, sizeof(*body));
 319        if (wfx_api_older_than(wdev, 1, 5))
 320                // Legacy firmwares expect that add_key to be sent on right
 321                // interface.
 322                wfx_fill_header(hif, arg->int_id, HIF_REQ_ID_ADD_KEY,
 323                                sizeof(*body));
 324        else
 325                wfx_fill_header(hif, -1, HIF_REQ_ID_ADD_KEY, sizeof(*body));
 326        ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
 327        kfree(hif);
 328        return ret;
 329}
 330
 331int hif_remove_key(struct wfx_dev *wdev, int idx)
 332{
 333        int ret;
 334        struct hif_msg *hif;
 335        struct hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif);
 336
 337        body->entry_index = idx;
 338        wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body));
 339        ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
 340        kfree(hif);
 341        return ret;
 342}
 343
 344int hif_set_edca_queue_params(struct wfx_vif *wvif,
 345                              const struct hif_req_edca_queue_params *arg)
 346{
 347        int ret;
 348        struct hif_msg *hif;
 349        struct hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body),
 350                                                               &hif);
 351
 352        // NOTE: queues numerotation are not the same between WFx and Linux
 353        memcpy(body, arg, sizeof(*body));
 354        cpu_to_le16s(&body->cw_min);
 355        cpu_to_le16s(&body->cw_max);
 356        cpu_to_le16s(&body->tx_op_limit);
 357        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_EDCA_QUEUE_PARAMS,
 358                        sizeof(*body));
 359        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 360        kfree(hif);
 361        return ret;
 362}
 363
 364int hif_set_pm(struct wfx_vif *wvif, const struct hif_req_set_pm_mode *arg)
 365{
 366        int ret;
 367        struct hif_msg *hif;
 368        struct hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif);
 369
 370        memcpy(body, arg, sizeof(*body));
 371        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_PM_MODE, sizeof(*body));
 372        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 373        kfree(hif);
 374        return ret;
 375}
 376
 377int hif_start(struct wfx_vif *wvif, const struct hif_req_start *arg)
 378{
 379        int ret;
 380        struct hif_msg *hif;
 381        struct hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif);
 382
 383        memcpy(body, arg, sizeof(*body));
 384        cpu_to_le16s(&body->channel_number);
 385        cpu_to_le32s(&body->beacon_interval);
 386        cpu_to_le32s(&body->basic_rate_set);
 387        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body));
 388        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 389        kfree(hif);
 390        return ret;
 391}
 392
 393int hif_beacon_transmit(struct wfx_vif *wvif, bool enable_beaconing)
 394{
 395        int ret;
 396        struct hif_msg *hif;
 397        struct hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body),
 398                                                             &hif);
 399
 400        body->enable_beaconing = enable_beaconing ? 1 : 0;
 401        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT,
 402                        sizeof(*body));
 403        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 404        kfree(hif);
 405        return ret;
 406}
 407
 408int hif_map_link(struct wfx_vif *wvif, u8 *mac_addr, int flags, int sta_id)
 409{
 410        int ret;
 411        struct hif_msg *hif;
 412        struct hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif);
 413
 414        if (mac_addr)
 415                ether_addr_copy(body->mac_addr, mac_addr);
 416        body->map_link_flags = *(struct hif_map_link_flags *) &flags;
 417        body->peer_sta_id = sta_id;
 418        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body));
 419        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 420        kfree(hif);
 421        return ret;
 422}
 423
 424int hif_update_ie(struct wfx_vif *wvif, const struct hif_ie_flags *target_frame,
 425                  const u8 *ies, size_t ies_len)
 426{
 427        int ret;
 428        struct hif_msg *hif;
 429        int buf_len = sizeof(struct hif_req_update_ie) + ies_len;
 430        struct hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif);
 431
 432        memcpy(&body->ie_flags, target_frame, sizeof(struct hif_ie_flags));
 433        body->num_i_es = cpu_to_le16(1);
 434        memcpy(body->ie, ies, ies_len);
 435        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_UPDATE_IE, buf_len);
 436        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
 437        kfree(hif);
 438        return ret;
 439}
 440
 441int hif_sl_send_pub_keys(struct wfx_dev *wdev, const uint8_t *pubkey,
 442                         const uint8_t *pubkey_hmac)
 443{
 444        int ret;
 445        struct hif_msg *hif;
 446        struct hif_req_sl_exchange_pub_keys *body = wfx_alloc_hif(sizeof(*body),
 447                                                                  &hif);
 448
 449        body->algorithm = HIF_SL_CURVE25519;
 450        memcpy(body->host_pub_key, pubkey, sizeof(body->host_pub_key));
 451        memcpy(body->host_pub_key_mac, pubkey_hmac,
 452               sizeof(body->host_pub_key_mac));
 453        wfx_fill_header(hif, -1, HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS,
 454                        sizeof(*body));
 455        ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
 456        kfree(hif);
 457        // Compatibility with legacy secure link
 458        if (ret == SL_PUB_KEY_EXCHANGE_STATUS_SUCCESS)
 459                ret = 0;
 460        return ret;
 461}
 462
 463int hif_sl_config(struct wfx_dev *wdev, const unsigned long *bitmap)
 464{
 465        int ret;
 466        struct hif_msg *hif;
 467        struct hif_req_sl_configure *body = wfx_alloc_hif(sizeof(*body), &hif);
 468
 469        memcpy(body->encr_bmp, bitmap, sizeof(body->encr_bmp));
 470        wfx_fill_header(hif, -1, HIF_REQ_ID_SL_CONFIGURE, sizeof(*body));
 471        ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
 472        kfree(hif);
 473        return ret;
 474}
 475
 476int hif_sl_set_mac_key(struct wfx_dev *wdev, const u8 *slk_key,
 477                       int destination)
 478{
 479        int ret;
 480        struct hif_msg *hif;
 481        struct hif_req_set_sl_mac_key *body = wfx_alloc_hif(sizeof(*body),
 482                                                            &hif);
 483
 484        memcpy(body->key_value, slk_key, sizeof(body->key_value));
 485        body->otp_or_ram = destination;
 486        wfx_fill_header(hif, -1, HIF_REQ_ID_SET_SL_MAC_KEY, sizeof(*body));
 487        ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
 488        kfree(hif);
 489        // Compatibility with legacy secure link
 490        if (ret == SL_MAC_KEY_STATUS_SUCCESS)
 491                ret = 0;
 492        return ret;
 493}
 494