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                if (epid < 0 || epid >= ENDPOINT_MAX)
 117                        return;
 118
 119                service_id = be16_to_cpu(svc_rspmsg->service_id);
 120                max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
 121                endpoint = &target->endpoint[epid];
 122
 123                for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) {
 124                        tmp_endpoint = &target->endpoint[tepid];
 125                        if (tmp_endpoint->service_id == service_id) {
 126                                tmp_endpoint->service_id = 0;
 127                                break;
 128                        }
 129                }
 130
 131                if (tepid == ENDPOINT0)
 132                        return;
 133
 134                endpoint->service_id = service_id;
 135                endpoint->max_txqdepth = tmp_endpoint->max_txqdepth;
 136                endpoint->ep_callbacks = tmp_endpoint->ep_callbacks;
 137                endpoint->ul_pipeid = tmp_endpoint->ul_pipeid;
 138                endpoint->dl_pipeid = tmp_endpoint->dl_pipeid;
 139                endpoint->max_msglen = max_msglen;
 140                target->conn_rsp_epid = epid;
 141                complete(&target->cmd_wait);
 142        } else {
 143                target->conn_rsp_epid = ENDPOINT_UNUSED;
 144        }
 145}
 146
 147static int htc_config_pipe_credits(struct htc_target *target)
 148{
 149        struct sk_buff *skb;
 150        struct htc_config_pipe_msg *cp_msg;
 151        int ret;
 152        unsigned long time_left;
 153
 154        skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
 155        if (!skb) {
 156                dev_err(target->dev, "failed to allocate send buffer\n");
 157                return -ENOMEM;
 158        }
 159        skb_reserve(skb, sizeof(struct htc_frame_hdr));
 160
 161        cp_msg = skb_put(skb, sizeof(struct htc_config_pipe_msg));
 162
 163        cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
 164        cp_msg->pipe_id = USB_WLAN_TX_PIPE;
 165        cp_msg->credits = target->credits;
 166
 167        target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
 168
 169        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 170        if (ret)
 171                goto err;
 172
 173        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 174        if (!time_left) {
 175                dev_err(target->dev, "HTC credit config timeout\n");
 176                return -ETIMEDOUT;
 177        }
 178
 179        return 0;
 180err:
 181        kfree_skb(skb);
 182        return -EINVAL;
 183}
 184
 185static int htc_setup_complete(struct htc_target *target)
 186{
 187        struct sk_buff *skb;
 188        struct htc_comp_msg *comp_msg;
 189        int ret = 0;
 190        unsigned long time_left;
 191
 192        skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
 193        if (!skb) {
 194                dev_err(target->dev, "failed to allocate send buffer\n");
 195                return -ENOMEM;
 196        }
 197        skb_reserve(skb, sizeof(struct htc_frame_hdr));
 198
 199        comp_msg = skb_put(skb, sizeof(struct htc_comp_msg));
 200        comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID);
 201
 202        target->htc_flags |= HTC_OP_START_WAIT;
 203
 204        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 205        if (ret)
 206                goto err;
 207
 208        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 209        if (!time_left) {
 210                dev_err(target->dev, "HTC start timeout\n");
 211                return -ETIMEDOUT;
 212        }
 213
 214        return 0;
 215
 216err:
 217        kfree_skb(skb);
 218        return -EINVAL;
 219}
 220
 221/* HTC APIs */
 222
 223int htc_init(struct htc_target *target)
 224{
 225        int ret;
 226
 227        ret = htc_config_pipe_credits(target);
 228        if (ret)
 229                return ret;
 230
 231        return htc_setup_complete(target);
 232}
 233
 234int htc_connect_service(struct htc_target *target,
 235                     struct htc_service_connreq *service_connreq,
 236                     enum htc_endpoint_id *conn_rsp_epid)
 237{
 238        struct sk_buff *skb;
 239        struct htc_endpoint *endpoint;
 240        struct htc_conn_svc_msg *conn_msg;
 241        int ret;
 242        unsigned long time_left;
 243
 244        /* Find an available endpoint */
 245        endpoint = get_next_avail_ep(target->endpoint);
 246        if (!endpoint) {
 247                dev_err(target->dev, "Endpoint is not available for service %d\n",
 248                        service_connreq->service_id);
 249                return -EINVAL;
 250        }
 251
 252        endpoint->service_id = service_connreq->service_id;
 253        endpoint->max_txqdepth = service_connreq->max_send_qdepth;
 254        endpoint->ul_pipeid = service_to_ulpipe(service_connreq->service_id);
 255        endpoint->dl_pipeid = service_to_dlpipe(service_connreq->service_id);
 256        endpoint->ep_callbacks = service_connreq->ep_callbacks;
 257
 258        skb = alloc_skb(sizeof(struct htc_conn_svc_msg) +
 259                            sizeof(struct htc_frame_hdr), GFP_ATOMIC);
 260        if (!skb) {
 261                dev_err(target->dev, "Failed to allocate buf to send"
 262                        "service connect req\n");
 263                return -ENOMEM;
 264        }
 265
 266        skb_reserve(skb, sizeof(struct htc_frame_hdr));
 267
 268        conn_msg = skb_put(skb, sizeof(struct htc_conn_svc_msg));
 269        conn_msg->service_id = cpu_to_be16(service_connreq->service_id);
 270        conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID);
 271        conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags);
 272        conn_msg->dl_pipeid = endpoint->dl_pipeid;
 273        conn_msg->ul_pipeid = endpoint->ul_pipeid;
 274
 275        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 276        if (ret)
 277                goto err;
 278
 279        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 280        if (!time_left) {
 281                dev_err(target->dev, "Service connection timeout for: %d\n",
 282                        service_connreq->service_id);
 283                return -ETIMEDOUT;
 284        }
 285
 286        *conn_rsp_epid = target->conn_rsp_epid;
 287        return 0;
 288err:
 289        kfree_skb(skb);
 290        return ret;
 291}
 292
 293int htc_send(struct htc_target *target, struct sk_buff *skb)
 294{
 295        struct ath9k_htc_tx_ctl *tx_ctl;
 296
 297        tx_ctl = HTC_SKB_CB(skb);
 298        return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
 299}
 300
 301int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
 302                  enum htc_endpoint_id epid)
 303{
 304        return htc_issue_send(target, skb, skb->len, 0, epid);
 305}
 306
 307void htc_stop(struct htc_target *target)
 308{
 309        target->hif->stop(target->hif_dev);
 310}
 311
 312void htc_start(struct htc_target *target)
 313{
 314        target->hif->start(target->hif_dev);
 315}
 316
 317void htc_sta_drain(struct htc_target *target, u8 idx)
 318{
 319        target->hif->sta_drain(target->hif_dev, idx);
 320}
 321
 322void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
 323                               struct sk_buff *skb, bool txok)
 324{
 325        struct htc_endpoint *endpoint;
 326        struct htc_frame_hdr *htc_hdr = NULL;
 327
 328        if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) {
 329                complete(&htc_handle->cmd_wait);
 330                htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS;
 331                goto ret;
 332        }
 333
 334        if (htc_handle->htc_flags & HTC_OP_START_WAIT) {
 335                complete(&htc_handle->cmd_wait);
 336                htc_handle->htc_flags &= ~HTC_OP_START_WAIT;
 337                goto ret;
 338        }
 339
 340        if (skb) {
 341                htc_hdr = (struct htc_frame_hdr *) skb->data;
 342                if (htc_hdr->endpoint_id >= ARRAY_SIZE(htc_handle->endpoint))
 343                        goto ret;
 344                endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id];
 345                skb_pull(skb, sizeof(struct htc_frame_hdr));
 346
 347                if (endpoint->ep_callbacks.tx) {
 348                        endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
 349                                                  skb, htc_hdr->endpoint_id,
 350                                                  txok);
 351                } else {
 352                        kfree_skb(skb);
 353                }
 354        }
 355
 356        return;
 357ret:
 358        kfree_skb(skb);
 359}
 360
 361static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle,
 362                                      struct sk_buff *skb)
 363{
 364        uint32_t *pattern = (uint32_t *)skb->data;
 365
 366        switch (*pattern) {
 367        case 0x33221199:
 368                {
 369                struct htc_panic_bad_vaddr *htc_panic;
 370                htc_panic = (struct htc_panic_bad_vaddr *) skb->data;
 371                dev_err(htc_handle->dev, "ath: firmware panic! "
 372                        "exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n",
 373                        htc_panic->exccause, htc_panic->pc,
 374                        htc_panic->badvaddr);
 375                break;
 376                }
 377        case 0x33221299:
 378                {
 379                struct htc_panic_bad_epid *htc_panic;
 380                htc_panic = (struct htc_panic_bad_epid *) skb->data;
 381                dev_err(htc_handle->dev, "ath: firmware panic! "
 382                        "bad epid: 0x%08x\n", htc_panic->epid);
 383                break;
 384                }
 385        default:
 386                dev_err(htc_handle->dev, "ath: unknown panic pattern!\n");
 387                break;
 388        }
 389}
 390
 391/*
 392 * HTC Messages are handled directly here and the obtained SKB
 393 * is freed.
 394 *
 395 * Service messages (Data, WMI) passed to the corresponding
 396 * endpoint RX handlers, which have to free the SKB.
 397 */
 398void ath9k_htc_rx_msg(struct htc_target *htc_handle,
 399                      struct sk_buff *skb, u32 len, u8 pipe_id)
 400{
 401        struct htc_frame_hdr *htc_hdr;
 402        enum htc_endpoint_id epid;
 403        struct htc_endpoint *endpoint;
 404        __be16 *msg_id;
 405
 406        if (!htc_handle || !skb)
 407                return;
 408
 409        htc_hdr = (struct htc_frame_hdr *) skb->data;
 410        epid = htc_hdr->endpoint_id;
 411
 412        if (epid == 0x99) {
 413                ath9k_htc_fw_panic_report(htc_handle, skb);
 414                kfree_skb(skb);
 415                return;
 416        }
 417
 418        if (epid < 0 || epid >= ENDPOINT_MAX) {
 419                if (pipe_id != USB_REG_IN_PIPE)
 420                        dev_kfree_skb_any(skb);
 421                else
 422                        kfree_skb(skb);
 423                return;
 424        }
 425
 426        if (epid == ENDPOINT0) {
 427
 428                /* Handle trailer */
 429                if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
 430                        if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000)
 431                                /* Move past the Watchdog pattern */
 432                                htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
 433                }
 434
 435                /* Get the message ID */
 436                msg_id = (__be16 *) ((void *) htc_hdr +
 437                                     sizeof(struct htc_frame_hdr));
 438
 439                /* Now process HTC messages */
 440                switch (be16_to_cpu(*msg_id)) {
 441                case HTC_MSG_READY_ID:
 442                        htc_process_target_rdy(htc_handle, htc_hdr);
 443                        break;
 444                case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID:
 445                        htc_process_conn_rsp(htc_handle, htc_hdr);
 446                        break;
 447                default:
 448                        break;
 449                }
 450
 451                kfree_skb(skb);
 452
 453        } else {
 454                if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER)
 455                        skb_trim(skb, len - htc_hdr->control[0]);
 456
 457                skb_pull(skb, sizeof(struct htc_frame_hdr));
 458
 459                endpoint = &htc_handle->endpoint[epid];
 460                if (endpoint->ep_callbacks.rx)
 461                        endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv,
 462                                                  skb, epid);
 463        }
 464}
 465
 466struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
 467                                      struct ath9k_htc_hif *hif,
 468                                      struct device *dev)
 469{
 470        struct htc_endpoint *endpoint;
 471        struct htc_target *target;
 472
 473        target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
 474        if (!target)
 475                return NULL;
 476
 477        init_completion(&target->target_wait);
 478        init_completion(&target->cmd_wait);
 479
 480        target->hif = hif;
 481        target->hif_dev = hif_handle;
 482        target->dev = dev;
 483
 484        /* Assign control endpoint pipe IDs */
 485        endpoint = &target->endpoint[ENDPOINT0];
 486        endpoint->ul_pipeid = hif->control_ul_pipe;
 487        endpoint->dl_pipeid = hif->control_dl_pipe;
 488
 489        atomic_set(&target->tgt_ready, 0);
 490
 491        return target;
 492}
 493
 494void ath9k_htc_hw_free(struct htc_target *htc)
 495{
 496        kfree(htc);
 497}
 498
 499int ath9k_htc_hw_init(struct htc_target *target,
 500                      struct device *dev, u16 devid,
 501                      char *product, u32 drv_info)
 502{
 503        if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) {
 504                pr_err("Failed to initialize the device\n");
 505                return -ENODEV;
 506        }
 507
 508        return 0;
 509}
 510
 511void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug)
 512{
 513        if (target)
 514                ath9k_htc_disconnect_device(target, hot_unplug);
 515}
 516