linux/drivers/net/wireless/st/cw1200/bh.c
<<
>>
Prefs
   1/*
   2 * Device handling thread implementation for mac80211 ST-Ericsson CW1200 drivers
   3 *
   4 * Copyright (c) 2010, ST-Ericsson
   5 * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
   6 *
   7 * Based on:
   8 * ST-Ericsson UMAC CW1200 driver, which is
   9 * Copyright (c) 2010, ST-Ericsson
  10 * Author: Ajitpal Singh <ajitpal.singh@stericsson.com>
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 */
  16
  17#include <linux/module.h>
  18#include <net/mac80211.h>
  19#include <linux/kthread.h>
  20#include <linux/timer.h>
  21
  22#include "cw1200.h"
  23#include "bh.h"
  24#include "hwio.h"
  25#include "wsm.h"
  26#include "hwbus.h"
  27#include "debug.h"
  28#include "fwio.h"
  29
  30static int cw1200_bh(void *arg);
  31
  32#define DOWNLOAD_BLOCK_SIZE_WR  (0x1000 - 4)
  33/* an SPI message cannot be bigger than (2"12-1)*2 bytes
  34 * "*2" to cvt to bytes
  35 */
  36#define MAX_SZ_RD_WR_BUFFERS    (DOWNLOAD_BLOCK_SIZE_WR*2)
  37#define PIGGYBACK_CTRL_REG      (2)
  38#define EFFECTIVE_BUF_SIZE      (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG)
  39
  40/* Suspend state privates */
  41enum cw1200_bh_pm_state {
  42        CW1200_BH_RESUMED = 0,
  43        CW1200_BH_SUSPEND,
  44        CW1200_BH_SUSPENDED,
  45        CW1200_BH_RESUME,
  46};
  47
  48typedef int (*cw1200_wsm_handler)(struct cw1200_common *priv,
  49        u8 *data, size_t size);
  50
  51static void cw1200_bh_work(struct work_struct *work)
  52{
  53        struct cw1200_common *priv =
  54        container_of(work, struct cw1200_common, bh_work);
  55        cw1200_bh(priv);
  56}
  57
  58int cw1200_register_bh(struct cw1200_common *priv)
  59{
  60        int err = 0;
  61        /* Realtime workqueue */
  62        priv->bh_workqueue = alloc_workqueue("cw1200_bh",
  63                                WQ_MEM_RECLAIM | WQ_HIGHPRI
  64                                | WQ_CPU_INTENSIVE, 1);
  65
  66        if (!priv->bh_workqueue)
  67                return -ENOMEM;
  68
  69        INIT_WORK(&priv->bh_work, cw1200_bh_work);
  70
  71        pr_debug("[BH] register.\n");
  72
  73        atomic_set(&priv->bh_rx, 0);
  74        atomic_set(&priv->bh_tx, 0);
  75        atomic_set(&priv->bh_term, 0);
  76        atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED);
  77        priv->bh_error = 0;
  78        priv->hw_bufs_used = 0;
  79        priv->buf_id_tx = 0;
  80        priv->buf_id_rx = 0;
  81        init_waitqueue_head(&priv->bh_wq);
  82        init_waitqueue_head(&priv->bh_evt_wq);
  83
  84        err = !queue_work(priv->bh_workqueue, &priv->bh_work);
  85        WARN_ON(err);
  86        return err;
  87}
  88
  89void cw1200_unregister_bh(struct cw1200_common *priv)
  90{
  91        atomic_add(1, &priv->bh_term);
  92        wake_up(&priv->bh_wq);
  93
  94        flush_workqueue(priv->bh_workqueue);
  95
  96        destroy_workqueue(priv->bh_workqueue);
  97        priv->bh_workqueue = NULL;
  98
  99        pr_debug("[BH] unregistered.\n");
 100}
 101
 102void cw1200_irq_handler(struct cw1200_common *priv)
 103{
 104        pr_debug("[BH] irq.\n");
 105
 106        /* Disable Interrupts! */
 107        /* NOTE:  hwbus_ops->lock already held */
 108        __cw1200_irq_enable(priv, 0);
 109
 110        if (/* WARN_ON */(priv->bh_error))
 111                return;
 112
 113        if (atomic_add_return(1, &priv->bh_rx) == 1)
 114                wake_up(&priv->bh_wq);
 115}
 116EXPORT_SYMBOL_GPL(cw1200_irq_handler);
 117
 118void cw1200_bh_wakeup(struct cw1200_common *priv)
 119{
 120        pr_debug("[BH] wakeup.\n");
 121        if (priv->bh_error) {
 122                pr_err("[BH] wakeup failed (BH error)\n");
 123                return;
 124        }
 125
 126        if (atomic_add_return(1, &priv->bh_tx) == 1)
 127                wake_up(&priv->bh_wq);
 128}
 129
 130int cw1200_bh_suspend(struct cw1200_common *priv)
 131{
 132        pr_debug("[BH] suspend.\n");
 133        if (priv->bh_error) {
 134                wiphy_warn(priv->hw->wiphy, "BH error -- can't suspend\n");
 135                return -EINVAL;
 136        }
 137
 138        atomic_set(&priv->bh_suspend, CW1200_BH_SUSPEND);
 139        wake_up(&priv->bh_wq);
 140        return wait_event_timeout(priv->bh_evt_wq, priv->bh_error ||
 141                (CW1200_BH_SUSPENDED == atomic_read(&priv->bh_suspend)),
 142                 1 * HZ) ? 0 : -ETIMEDOUT;
 143}
 144
 145int cw1200_bh_resume(struct cw1200_common *priv)
 146{
 147        pr_debug("[BH] resume.\n");
 148        if (priv->bh_error) {
 149                wiphy_warn(priv->hw->wiphy, "BH error -- can't resume\n");
 150                return -EINVAL;
 151        }
 152
 153        atomic_set(&priv->bh_suspend, CW1200_BH_RESUME);
 154        wake_up(&priv->bh_wq);
 155        return wait_event_timeout(priv->bh_evt_wq, priv->bh_error ||
 156                (CW1200_BH_RESUMED == atomic_read(&priv->bh_suspend)),
 157                1 * HZ) ? 0 : -ETIMEDOUT;
 158}
 159
 160static inline void wsm_alloc_tx_buffer(struct cw1200_common *priv)
 161{
 162        ++priv->hw_bufs_used;
 163}
 164
 165int wsm_release_tx_buffer(struct cw1200_common *priv, int count)
 166{
 167        int ret = 0;
 168        int hw_bufs_used = priv->hw_bufs_used;
 169
 170        priv->hw_bufs_used -= count;
 171        if (WARN_ON(priv->hw_bufs_used < 0))
 172                ret = -1;
 173        else if (hw_bufs_used >= priv->wsm_caps.input_buffers)
 174                ret = 1;
 175        if (!priv->hw_bufs_used)
 176                wake_up(&priv->bh_evt_wq);
 177        return ret;
 178}
 179
 180static int cw1200_bh_read_ctrl_reg(struct cw1200_common *priv,
 181                                          u16 *ctrl_reg)
 182{
 183        int ret;
 184
 185        ret = cw1200_reg_read_16(priv,
 186                        ST90TDS_CONTROL_REG_ID, ctrl_reg);
 187        if (ret) {
 188                ret = cw1200_reg_read_16(priv,
 189                                ST90TDS_CONTROL_REG_ID, ctrl_reg);
 190                if (ret)
 191                        pr_err("[BH] Failed to read control register.\n");
 192        }
 193
 194        return ret;
 195}
 196
 197static int cw1200_device_wakeup(struct cw1200_common *priv)
 198{
 199        u16 ctrl_reg;
 200        int ret;
 201
 202        pr_debug("[BH] Device wakeup.\n");
 203
 204        /* First, set the dpll register */
 205        ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID,
 206                                  cw1200_dpll_from_clk(priv->hw_refclk));
 207        if (WARN_ON(ret))
 208                return ret;
 209
 210        /* To force the device to be always-on, the host sets WLAN_UP to 1 */
 211        ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID,
 212                        ST90TDS_CONT_WUP_BIT);
 213        if (WARN_ON(ret))
 214                return ret;
 215
 216        ret = cw1200_bh_read_ctrl_reg(priv, &ctrl_reg);
 217        if (WARN_ON(ret))
 218                return ret;
 219
 220        /* If the device returns WLAN_RDY as 1, the device is active and will
 221         * remain active.
 222         */
 223        if (ctrl_reg & ST90TDS_CONT_RDY_BIT) {
 224                pr_debug("[BH] Device awake.\n");
 225                return 1;
 226        }
 227
 228        return 0;
 229}
 230
 231/* Must be called from BH thraed. */
 232void cw1200_enable_powersave(struct cw1200_common *priv,
 233                             bool enable)
 234{
 235        pr_debug("[BH] Powerave is %s.\n",
 236                 enable ? "enabled" : "disabled");
 237        priv->powersave_enabled = enable;
 238}
 239
 240static int cw1200_bh_rx_helper(struct cw1200_common *priv,
 241                               uint16_t *ctrl_reg,
 242                               int *tx)
 243{
 244        size_t read_len = 0;
 245        struct sk_buff *skb_rx = NULL;
 246        struct wsm_hdr *wsm;
 247        size_t wsm_len;
 248        u16 wsm_id;
 249        u8 wsm_seq;
 250        int rx_resync = 1;
 251
 252        size_t alloc_len;
 253        u8 *data;
 254
 255        read_len = (*ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) * 2;
 256        if (!read_len)
 257                return 0; /* No more work */
 258
 259        if (WARN_ON((read_len < sizeof(struct wsm_hdr)) ||
 260                    (read_len > EFFECTIVE_BUF_SIZE))) {
 261                pr_debug("Invalid read len: %zu (%04x)",
 262                         read_len, *ctrl_reg);
 263                goto err;
 264        }
 265
 266        /* Add SIZE of PIGGYBACK reg (CONTROL Reg)
 267         * to the NEXT Message length + 2 Bytes for SKB
 268         */
 269        read_len = read_len + 2;
 270
 271        alloc_len = priv->hwbus_ops->align_size(
 272                priv->hwbus_priv, read_len);
 273
 274        /* Check if not exceeding CW1200 capabilities */
 275        if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) {
 276                pr_debug("Read aligned len: %zu\n",
 277                         alloc_len);
 278        }
 279
 280        skb_rx = dev_alloc_skb(alloc_len);
 281        if (WARN_ON(!skb_rx))
 282                goto err;
 283
 284        skb_trim(skb_rx, 0);
 285        skb_put(skb_rx, read_len);
 286        data = skb_rx->data;
 287        if (WARN_ON(!data))
 288                goto err;
 289
 290        if (WARN_ON(cw1200_data_read(priv, data, alloc_len))) {
 291                pr_err("rx blew up, len %zu\n", alloc_len);
 292                goto err;
 293        }
 294
 295        /* Piggyback */
 296        *ctrl_reg = __le16_to_cpu(
 297                ((__le16 *)data)[alloc_len / 2 - 1]);
 298
 299        wsm = (struct wsm_hdr *)data;
 300        wsm_len = __le16_to_cpu(wsm->len);
 301        if (WARN_ON(wsm_len > read_len))
 302                goto err;
 303
 304        if (priv->wsm_enable_wsm_dumps)
 305                print_hex_dump_bytes("<-- ",
 306                                     DUMP_PREFIX_NONE,
 307                                     data, wsm_len);
 308
 309        wsm_id  = __le16_to_cpu(wsm->id) & 0xFFF;
 310        wsm_seq = (__le16_to_cpu(wsm->id) >> 13) & 7;
 311
 312        skb_trim(skb_rx, wsm_len);
 313
 314        if (wsm_id == 0x0800) {
 315                wsm_handle_exception(priv,
 316                                     &data[sizeof(*wsm)],
 317                                     wsm_len - sizeof(*wsm));
 318                goto err;
 319        } else if (!rx_resync) {
 320                if (WARN_ON(wsm_seq != priv->wsm_rx_seq))
 321                        goto err;
 322        }
 323        priv->wsm_rx_seq = (wsm_seq + 1) & 7;
 324        rx_resync = 0;
 325
 326        if (wsm_id & 0x0400) {
 327                int rc = wsm_release_tx_buffer(priv, 1);
 328                if (WARN_ON(rc < 0))
 329                        return rc;
 330                else if (rc > 0)
 331                        *tx = 1;
 332        }
 333
 334        /* cw1200_wsm_rx takes care on SKB livetime */
 335        if (WARN_ON(wsm_handle_rx(priv, wsm_id, wsm, &skb_rx)))
 336                goto err;
 337
 338        if (skb_rx) {
 339                dev_kfree_skb(skb_rx);
 340                skb_rx = NULL;
 341        }
 342
 343        return 0;
 344
 345err:
 346        if (skb_rx) {
 347                dev_kfree_skb(skb_rx);
 348                skb_rx = NULL;
 349        }
 350        return -1;
 351}
 352
 353static int cw1200_bh_tx_helper(struct cw1200_common *priv,
 354                               int *pending_tx,
 355                               int *tx_burst)
 356{
 357        size_t tx_len;
 358        u8 *data;
 359        int ret;
 360        struct wsm_hdr *wsm;
 361
 362        if (priv->device_can_sleep) {
 363                ret = cw1200_device_wakeup(priv);
 364                if (WARN_ON(ret < 0)) { /* Error in wakeup */
 365                        *pending_tx = 1;
 366                        return 0;
 367                } else if (ret) { /* Woke up */
 368                        priv->device_can_sleep = false;
 369                } else { /* Did not awake */
 370                        *pending_tx = 1;
 371                        return 0;
 372                }
 373        }
 374
 375        wsm_alloc_tx_buffer(priv);
 376        ret = wsm_get_tx(priv, &data, &tx_len, tx_burst);
 377        if (ret <= 0) {
 378                wsm_release_tx_buffer(priv, 1);
 379                if (WARN_ON(ret < 0))
 380                        return ret; /* Error */
 381                return 0; /* No work */
 382        }
 383
 384        wsm = (struct wsm_hdr *)data;
 385        BUG_ON(tx_len < sizeof(*wsm));
 386        BUG_ON(__le16_to_cpu(wsm->len) != tx_len);
 387
 388        atomic_add(1, &priv->bh_tx);
 389
 390        tx_len = priv->hwbus_ops->align_size(
 391                priv->hwbus_priv, tx_len);
 392
 393        /* Check if not exceeding CW1200 capabilities */
 394        if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE))
 395                pr_debug("Write aligned len: %zu\n", tx_len);
 396
 397        wsm->id &= __cpu_to_le16(0xffff ^ WSM_TX_SEQ(WSM_TX_SEQ_MAX));
 398        wsm->id |= __cpu_to_le16(WSM_TX_SEQ(priv->wsm_tx_seq));
 399
 400        if (WARN_ON(cw1200_data_write(priv, data, tx_len))) {
 401                pr_err("tx blew up, len %zu\n", tx_len);
 402                wsm_release_tx_buffer(priv, 1);
 403                return -1; /* Error */
 404        }
 405
 406        if (priv->wsm_enable_wsm_dumps)
 407                print_hex_dump_bytes("--> ",
 408                                     DUMP_PREFIX_NONE,
 409                                     data,
 410                                     __le16_to_cpu(wsm->len));
 411
 412        wsm_txed(priv, data);
 413        priv->wsm_tx_seq = (priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX;
 414
 415        if (*tx_burst > 1) {
 416                cw1200_debug_tx_burst(priv);
 417                return 1; /* Work remains */
 418        }
 419
 420        return 0;
 421}
 422
 423static int cw1200_bh(void *arg)
 424{
 425        struct cw1200_common *priv = arg;
 426        int rx, tx, term, suspend;
 427        u16 ctrl_reg = 0;
 428        int tx_allowed;
 429        int pending_tx = 0;
 430        int tx_burst;
 431        long status;
 432        u32 dummy;
 433        int ret;
 434
 435        for (;;) {
 436                if (!priv->hw_bufs_used &&
 437                    priv->powersave_enabled &&
 438                    !priv->device_can_sleep &&
 439                    !atomic_read(&priv->recent_scan)) {
 440                        status = 1 * HZ;
 441                        pr_debug("[BH] Device wakedown. No data.\n");
 442                        cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, 0);
 443                        priv->device_can_sleep = true;
 444                } else if (priv->hw_bufs_used) {
 445                        /* Interrupt loss detection */
 446                        status = 1 * HZ;
 447                } else {
 448                        status = MAX_SCHEDULE_TIMEOUT;
 449                }
 450
 451                /* Dummy Read for SDIO retry mechanism*/
 452                if ((priv->hw_type != -1) &&
 453                    (atomic_read(&priv->bh_rx) == 0) &&
 454                    (atomic_read(&priv->bh_tx) == 0))
 455                        cw1200_reg_read(priv, ST90TDS_CONFIG_REG_ID,
 456                                        &dummy, sizeof(dummy));
 457
 458                pr_debug("[BH] waiting ...\n");
 459                status = wait_event_interruptible_timeout(priv->bh_wq, ({
 460                                rx = atomic_xchg(&priv->bh_rx, 0);
 461                                tx = atomic_xchg(&priv->bh_tx, 0);
 462                                term = atomic_xchg(&priv->bh_term, 0);
 463                                suspend = pending_tx ?
 464                                        0 : atomic_read(&priv->bh_suspend);
 465                                (rx || tx || term || suspend || priv->bh_error);
 466                        }), status);
 467
 468                pr_debug("[BH] - rx: %d, tx: %d, term: %d, bh_err: %d, suspend: %d, status: %ld\n",
 469                         rx, tx, term, suspend, priv->bh_error, status);
 470
 471                /* Did an error occur? */
 472                if ((status < 0 && status != -ERESTARTSYS) ||
 473                    term || priv->bh_error) {
 474                        break;
 475                }
 476                if (!status) {  /* wait_event timed out */
 477                        unsigned long timestamp = jiffies;
 478                        long timeout;
 479                        int pending = 0;
 480                        int i;
 481
 482                        /* Check to see if we have any outstanding frames */
 483                        if (priv->hw_bufs_used && (!rx || !tx)) {
 484                                wiphy_warn(priv->hw->wiphy,
 485                                           "Missed interrupt? (%d frames outstanding)\n",
 486                                           priv->hw_bufs_used);
 487                                rx = 1;
 488
 489                                /* Get a timestamp of "oldest" frame */
 490                                for (i = 0; i < 4; ++i)
 491                                        pending += cw1200_queue_get_xmit_timestamp(
 492                                                &priv->tx_queue[i],
 493                                                &timestamp,
 494                                                priv->pending_frame_id);
 495
 496                                /* Check if frame transmission is timed out.
 497                                 * Add an extra second with respect to possible
 498                                 * interrupt loss.
 499                                 */
 500                                timeout = timestamp +
 501                                        WSM_CMD_LAST_CHANCE_TIMEOUT +
 502                                        1 * HZ  -
 503                                        jiffies;
 504
 505                                /* And terminate BH thread if the frame is "stuck" */
 506                                if (pending && timeout < 0) {
 507                                        wiphy_warn(priv->hw->wiphy,
 508                                                   "Timeout waiting for TX confirm (%d/%d pending, %ld vs %lu).\n",
 509                                                   priv->hw_bufs_used, pending,
 510                                                   timestamp, jiffies);
 511                                        break;
 512                                }
 513                        } else if (!priv->device_can_sleep &&
 514                                   !atomic_read(&priv->recent_scan)) {
 515                                pr_debug("[BH] Device wakedown. Timeout.\n");
 516                                cw1200_reg_write_16(priv,
 517                                                    ST90TDS_CONTROL_REG_ID, 0);
 518                                priv->device_can_sleep = true;
 519                        }
 520                        goto done;
 521                } else if (suspend) {
 522                        pr_debug("[BH] Device suspend.\n");
 523                        if (priv->powersave_enabled) {
 524                                pr_debug("[BH] Device wakedown. Suspend.\n");
 525                                cw1200_reg_write_16(priv,
 526                                                    ST90TDS_CONTROL_REG_ID, 0);
 527                                priv->device_can_sleep = true;
 528                        }
 529
 530                        atomic_set(&priv->bh_suspend, CW1200_BH_SUSPENDED);
 531                        wake_up(&priv->bh_evt_wq);
 532                        status = wait_event_interruptible(priv->bh_wq,
 533                                                          CW1200_BH_RESUME == atomic_read(&priv->bh_suspend));
 534                        if (status < 0) {
 535                                wiphy_err(priv->hw->wiphy,
 536                                          "Failed to wait for resume: %ld.\n",
 537                                          status);
 538                                break;
 539                        }
 540                        pr_debug("[BH] Device resume.\n");
 541                        atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED);
 542                        wake_up(&priv->bh_evt_wq);
 543                        atomic_add(1, &priv->bh_rx);
 544                        goto done;
 545                }
 546
 547        rx:
 548                tx += pending_tx;
 549                pending_tx = 0;
 550
 551                if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg))
 552                        break;
 553
 554                /* Don't bother trying to rx unless we have data to read */
 555                if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) {
 556                        ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx);
 557                        if (ret < 0)
 558                                break;
 559                        /* Double up here if there's more data.. */
 560                        if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) {
 561                                ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx);
 562                                if (ret < 0)
 563                                        break;
 564                        }
 565                }
 566
 567        tx:
 568                if (tx) {
 569                        tx = 0;
 570
 571                        BUG_ON(priv->hw_bufs_used > priv->wsm_caps.input_buffers);
 572                        tx_burst = priv->wsm_caps.input_buffers - priv->hw_bufs_used;
 573                        tx_allowed = tx_burst > 0;
 574
 575                        if (!tx_allowed) {
 576                                /* Buffers full.  Ensure we process tx
 577                                 * after we handle rx..
 578                                 */
 579                                pending_tx = tx;
 580                                goto done_rx;
 581                        }
 582                        ret = cw1200_bh_tx_helper(priv, &pending_tx, &tx_burst);
 583                        if (ret < 0)
 584                                break;
 585                        if (ret > 0) /* More to transmit */
 586                                tx = ret;
 587
 588                        /* Re-read ctrl reg */
 589                        if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg))
 590                                break;
 591                }
 592
 593        done_rx:
 594                if (priv->bh_error)
 595                        break;
 596                if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK)
 597                        goto rx;
 598                if (tx)
 599                        goto tx;
 600
 601        done:
 602                /* Re-enable device interrupts */
 603                priv->hwbus_ops->lock(priv->hwbus_priv);
 604                __cw1200_irq_enable(priv, 1);
 605                priv->hwbus_ops->unlock(priv->hwbus_priv);
 606        }
 607
 608        /* Explicitly disable device interrupts */
 609        priv->hwbus_ops->lock(priv->hwbus_priv);
 610        __cw1200_irq_enable(priv, 0);
 611        priv->hwbus_ops->unlock(priv->hwbus_priv);
 612
 613        if (!term) {
 614                pr_err("[BH] Fatal error, exiting.\n");
 615                priv->bh_error = 1;
 616                /* TODO: schedule_work(recovery) */
 617        }
 618        return 0;
 619}
 620