linux/drivers/net/wireless/ath/ath9k/htc_hst.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010-2011 Atheros Communications Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  18
  19#include "htc.h"
  20
  21static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
  22                          u16 len, u8 flags, u8 epid)
  23
  24{
  25        struct htc_frame_hdr *hdr;
  26        struct htc_endpoint *endpoint = &target->endpoint[epid];
  27        int status;
  28
  29        hdr = skb_push(skb, sizeof(struct htc_frame_hdr));
  30        hdr->endpoint_id = epid;
  31        hdr->flags = flags;
  32        hdr->payload_len = cpu_to_be16(len);
  33
  34        status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb);
  35
  36        return status;
  37}
  38
  39static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint)
  40{
  41        enum htc_endpoint_id avail_epid;
  42
  43        for (avail_epid = (ENDPOINT_MAX - 1); avail_epid > ENDPOINT0; avail_epid--)
  44                if (endpoint[avail_epid].service_id == 0)
  45                        return &endpoint[avail_epid];
  46        return NULL;
  47}
  48
  49static u8 service_to_ulpipe(u16 service_id)
  50{
  51        switch (service_id) {
  52        case WMI_CONTROL_SVC:
  53                return 4;
  54        case WMI_BEACON_SVC:
  55        case WMI_CAB_SVC:
  56        case WMI_UAPSD_SVC:
  57        case WMI_MGMT_SVC:
  58        case WMI_DATA_VO_SVC:
  59        case WMI_DATA_VI_SVC:
  60        case WMI_DATA_BE_SVC:
  61        case WMI_DATA_BK_SVC:
  62                return 1;
  63        default:
  64                return 0;
  65        }
  66}
  67
  68static u8 service_to_dlpipe(u16 service_id)
  69{
  70        switch (service_id) {
  71        case WMI_CONTROL_SVC:
  72                return 3;
  73        case WMI_BEACON_SVC:
  74        case WMI_CAB_SVC:
  75        case WMI_UAPSD_SVC:
  76        case WMI_MGMT_SVC:
  77        case WMI_DATA_VO_SVC:
  78        case WMI_DATA_VI_SVC:
  79        case WMI_DATA_BE_SVC:
  80        case WMI_DATA_BK_SVC:
  81                return 2;
  82        default:
  83                return 0;
  84        }
  85}
  86
  87static void htc_process_target_rdy(struct htc_target *target,
  88                                   void *buf)
  89{
  90        struct htc_endpoint *endpoint;
  91        struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf;
  92
  93        target->credit_size = be16_to_cpu(htc_ready_msg->credit_size);
  94
  95        endpoint = &target->endpoint[ENDPOINT0];
  96        endpoint->service_id = HTC_CTRL_RSVD_SVC;
  97        endpoint->max_msglen = HTC_MAX_CONTROL_MESSAGE_LENGTH;
  98        atomic_inc(&target->tgt_ready);
  99        complete(&target->target_wait);
 100}
 101
 102static void htc_process_conn_rsp(struct htc_target *target,
 103                                 struct htc_frame_hdr *htc_hdr)
 104{
 105        struct htc_conn_svc_rspmsg *svc_rspmsg;
 106        struct htc_endpoint *endpoint, *tmp_endpoint = NULL;
 107        u16 service_id;
 108        u16 max_msglen;
 109        enum htc_endpoint_id epid, tepid;
 110
 111        svc_rspmsg = (struct htc_conn_svc_rspmsg *)
 112                ((void *) htc_hdr + sizeof(struct htc_frame_hdr));
 113
 114        if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) {
 115                epid = svc_rspmsg->endpoint_id;
 116                service_id = be16_to_cpu(svc_rspmsg->service_id);
 117                max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
 118                endpoint = &target->endpoint[epid];
 119
 120                for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) {
 121                        tmp_endpoint = &target->endpoint[tepid];
 122                        if (tmp_endpoint->service_id == service_id) {
 123                                tmp_endpoint->service_id = 0;
 124                                break;
 125                        }
 126                }
 127
 128                if (tepid == ENDPOINT0)
 129                        return;
 130
 131                endpoint->service_id = service_id;
 132                endpoint->max_txqdepth = tmp_endpoint->max_txqdepth;
 133                endpoint->ep_callbacks = tmp_endpoint->ep_callbacks;
 134                endpoint->ul_pipeid = tmp_endpoint->ul_pipeid;
 135                endpoint->dl_pipeid = tmp_endpoint->dl_pipeid;
 136                endpoint->max_msglen = max_msglen;
 137                target->conn_rsp_epid = epid;
 138                complete(&target->cmd_wait);
 139        } else {
 140                target->conn_rsp_epid = ENDPOINT_UNUSED;
 141        }
 142}
 143
 144static int htc_config_pipe_credits(struct htc_target *target)
 145{
 146        struct sk_buff *skb;
 147        struct htc_config_pipe_msg *cp_msg;
 148        int ret;
 149        unsigned long time_left;
 150
 151        skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
 152        if (!skb) {
 153                dev_err(target->dev, "failed to allocate send buffer\n");
 154                return -ENOMEM;
 155        }
 156        skb_reserve(skb, sizeof(struct htc_frame_hdr));
 157
 158        cp_msg = skb_put(skb, sizeof(struct htc_config_pipe_msg));
 159
 160        cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
 161        cp_msg->pipe_id = USB_WLAN_TX_PIPE;
 162        cp_msg->credits = target->credits;
 163
 164        target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
 165
 166        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 167        if (ret)
 168                goto err;
 169
 170        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 171        if (!time_left) {
 172                dev_err(target->dev, "HTC credit config timeout\n");
 173                return -ETIMEDOUT;
 174        }
 175
 176        return 0;
 177err:
 178        kfree_skb(skb);
 179        return -EINVAL;
 180}
 181
 182static int htc_setup_complete(struct htc_target *target)
 183{
 184        struct sk_buff *skb;
 185        struct htc_comp_msg *comp_msg;
 186        int ret = 0;
 187        unsigned long time_left;
 188
 189        skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
 190        if (!skb) {
 191                dev_err(target->dev, "failed to allocate send buffer\n");
 192                return -ENOMEM;
 193        }
 194        skb_reserve(skb, sizeof(struct htc_frame_hdr));
 195
 196        comp_msg = skb_put(skb, sizeof(struct htc_comp_msg));
 197        comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID);
 198
 199        target->htc_flags |= HTC_OP_START_WAIT;
 200
 201        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 202        if (ret)
 203                goto err;
 204
 205        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 206        if (!time_left) {
 207                dev_err(target->dev, "HTC start timeout\n");
 208                return -ETIMEDOUT;
 209        }
 210
 211        return 0;
 212
 213err:
 214        kfree_skb(skb);
 215        return -EINVAL;
 216}
 217
 218/* HTC APIs */
 219
 220int htc_init(struct htc_target *target)
 221{
 222        int ret;
 223
 224        ret = htc_config_pipe_credits(target);
 225        if (ret)
 226                return ret;
 227
 228        return htc_setup_complete(target);
 229}
 230
 231int htc_connect_service(struct htc_target *target,
 232                     struct htc_service_connreq *service_connreq,
 233                     enum htc_endpoint_id *conn_rsp_epid)
 234{
 235        struct sk_buff *skb;
 236        struct htc_endpoint *endpoint;
 237        struct htc_conn_svc_msg *conn_msg;
 238        int ret;
 239        unsigned long time_left;
 240
 241        /* Find an available endpoint */
 242        endpoint = get_next_avail_ep(target->endpoint);
 243        if (!endpoint) {
 244                dev_err(target->dev, "Endpoint is not available for service %d\n",
 245                        service_connreq->service_id);
 246                return -EINVAL;
 247        }
 248
 249        endpoint->service_id = service_connreq->service_id;
 250        endpoint->max_txqdepth = service_connreq->max_send_qdepth;
 251        endpoint->ul_pipeid = service_to_ulpipe(service_connreq->service_id);
 252        endpoint->dl_pipeid = service_to_dlpipe(service_connreq->service_id);
 253        endpoint->ep_callbacks = service_connreq->ep_callbacks;
 254
 255        skb = alloc_skb(sizeof(struct htc_conn_svc_msg) +
 256                            sizeof(struct htc_frame_hdr), GFP_ATOMIC);
 257        if (!skb) {
 258                dev_err(target->dev, "Failed to allocate buf to send"
 259                        "service connect req\n");
 260                return -ENOMEM;
 261        }
 262
 263        skb_reserve(skb, sizeof(struct htc_frame_hdr));
 264
 265        conn_msg = skb_put(skb, sizeof(struct htc_conn_svc_msg));
 266        conn_msg->service_id = cpu_to_be16(service_connreq->service_id);
 267        conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID);
 268        conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags);
 269        conn_msg->dl_pipeid = endpoint->dl_pipeid;
 270        conn_msg->ul_pipeid = endpoint->ul_pipeid;
 271
 272        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 273        if (ret)
 274                goto err;
 275
 276        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 277        if (!time_left) {
 278                dev_err(target->dev, "Service connection timeout for: %d\n",
 279                        service_connreq->service_id);
 280                return -ETIMEDOUT;
 281        }
 282
 283        *conn_rsp_epid = target->conn_rsp_epid;
 284        return 0;
 285err:
 286        kfree_skb(skb);
 287        return ret;
 288}
 289
 290int htc_send(struct htc_target *target, struct sk_buff *skb)
 291{
 292        struct ath9k_htc_tx_ctl *tx_ctl;
 293
 294        tx_ctl = HTC_SKB_CB(skb);
 295        return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
 296}
 297
 298int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
 299                  enum htc_endpoint_id epid)
 300{
 301        return htc_issue_send(target, skb, skb->len, 0, epid);
 302}
 303
 304void htc_stop(struct htc_target *target)
 305{
 306        target->hif->stop(target->hif_dev);
 307}
 308
 309void htc_start(struct htc_target *target)
 310{
 311        target->hif->start(target->hif_dev);
 312}
 313
 314void htc_sta_drain(struct htc_target *target, u8 idx)
 315{
 316        target->hif->sta_drain(target->hif_dev, idx);
 317}
 318
 319void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
 320                               struct sk_buff *skb, bool txok)
 321{
 322        struct htc_endpoint *endpoint;
 323        struct htc_frame_hdr *htc_hdr = NULL;
 324
 325        if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) {
 326                complete(&htc_handle->cmd_wait);
 327                htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS;
 328                goto ret;
 329        }
 330
 331        if (htc_handle->htc_flags & HTC_OP_START_WAIT) {
 332                complete(&htc_handle->cmd_wait);
 333                htc_handle->htc_flags &= ~HTC_OP_START_WAIT;
 334                goto ret;
 335        }
 336
 337        if (skb) {
 338                htc_hdr = (struct htc_frame_hdr *) skb->data;
 339                endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id];
 340                skb_pull(skb, sizeof(struct htc_frame_hdr));
 341
 342                if (endpoint->ep_callbacks.tx) {
 343                        endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
 344                                                  skb, htc_hdr->endpoint_id,
 345                                                  txok);
 346                } else {
 347                        kfree_skb(skb);
 348                }
 349        }
 350
 351        return;
 352ret:
 353        kfree_skb(skb);
 354}
 355
 356static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle,
 357                                      struct sk_buff *skb)
 358{
 359        uint32_t *pattern = (uint32_t *)skb->data;
 360
 361        switch (*pattern) {
 362        case 0x33221199:
 363                {
 364                struct htc_panic_bad_vaddr *htc_panic;
 365                htc_panic = (struct htc_panic_bad_vaddr *) skb->data;
 366                dev_err(htc_handle->dev, "ath: firmware panic! "
 367                        "exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n",
 368                        htc_panic->exccause, htc_panic->pc,
 369                        htc_panic->badvaddr);
 370                break;
 371                }
 372        case 0x33221299:
 373                {
 374                struct htc_panic_bad_epid *htc_panic;
 375                htc_panic = (struct htc_panic_bad_epid *) skb->data;
 376                dev_err(htc_handle->dev, "ath: firmware panic! "
 377                        "bad epid: 0x%08x\n", htc_panic->epid);
 378                break;
 379                }
 380        default:
 381                dev_err(htc_handle->dev, "ath: unknown panic pattern!\n");
 382                break;
 383        }
 384}
 385
 386/*
 387 * HTC Messages are handled directly here and the obtained SKB
 388 * is freed.
 389 *
 390 * Service messages (Data, WMI) passed to the corresponding
 391 * endpoint RX handlers, which have to free the SKB.
 392 */
 393void ath9k_htc_rx_msg(struct htc_target *htc_handle,
 394                      struct sk_buff *skb, u32 len, u8 pipe_id)
 395{
 396        struct htc_frame_hdr *htc_hdr;
 397        enum htc_endpoint_id epid;
 398        struct htc_endpoint *endpoint;
 399        __be16 *msg_id;
 400
 401        if (!htc_handle || !skb)
 402                return;
 403
 404        htc_hdr = (struct htc_frame_hdr *) skb->data;
 405        epid = htc_hdr->endpoint_id;
 406
 407        if (epid == 0x99) {
 408                ath9k_htc_fw_panic_report(htc_handle, skb);
 409                kfree_skb(skb);
 410                return;
 411        }
 412
 413        if (epid < 0 || epid >= ENDPOINT_MAX) {
 414                if (pipe_id != USB_REG_IN_PIPE)
 415                        dev_kfree_skb_any(skb);
 416                else
 417                        kfree_skb(skb);
 418                return;
 419        }
 420
 421        if (epid == ENDPOINT0) {
 422
 423                /* Handle trailer */
 424                if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
 425                        if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000)
 426                                /* Move past the Watchdog pattern */
 427                                htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
 428                }
 429
 430                /* Get the message ID */
 431                msg_id = (__be16 *) ((void *) htc_hdr +
 432                                     sizeof(struct htc_frame_hdr));
 433
 434                /* Now process HTC messages */
 435                switch (be16_to_cpu(*msg_id)) {
 436                case HTC_MSG_READY_ID:
 437                        htc_process_target_rdy(htc_handle, htc_hdr);
 438                        break;
 439                case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID:
 440                        htc_process_conn_rsp(htc_handle, htc_hdr);
 441                        break;
 442                default:
 443                        break;
 444                }
 445
 446                kfree_skb(skb);
 447
 448        } else {
 449                if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER)
 450                        skb_trim(skb, len - htc_hdr->control[0]);
 451
 452                skb_pull(skb, sizeof(struct htc_frame_hdr));
 453
 454                endpoint = &htc_handle->endpoint[epid];
 455                if (endpoint->ep_callbacks.rx)
 456                        endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv,
 457                                                  skb, epid);
 458        }
 459}
 460
 461struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
 462                                      struct ath9k_htc_hif *hif,
 463                                      struct device *dev)
 464{
 465        struct htc_endpoint *endpoint;
 466        struct htc_target *target;
 467
 468        target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
 469        if (!target)
 470                return NULL;
 471
 472        init_completion(&target->target_wait);
 473        init_completion(&target->cmd_wait);
 474
 475        target->hif = hif;
 476        target->hif_dev = hif_handle;
 477        target->dev = dev;
 478
 479        /* Assign control endpoint pipe IDs */
 480        endpoint = &target->endpoint[ENDPOINT0];
 481        endpoint->ul_pipeid = hif->control_ul_pipe;
 482        endpoint->dl_pipeid = hif->control_dl_pipe;
 483
 484        atomic_set(&target->tgt_ready, 0);
 485
 486        return target;
 487}
 488
 489void ath9k_htc_hw_free(struct htc_target *htc)
 490{
 491        kfree(htc);
 492}
 493
 494int ath9k_htc_hw_init(struct htc_target *target,
 495                      struct device *dev, u16 devid,
 496                      char *product, u32 drv_info)
 497{
 498        if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) {
 499                pr_err("Failed to initialize the device\n");
 500                return -ENODEV;
 501        }
 502
 503        return 0;
 504}
 505
 506void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug)
 507{
 508        if (target)
 509                ath9k_htc_disconnect_device(target, hot_unplug);
 510}
 511