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 = (struct htc_frame_hdr *)
  30                skb_push(skb, sizeof(struct htc_frame_hdr));
  31        hdr->endpoint_id = epid;
  32        hdr->flags = flags;
  33        hdr->payload_len = cpu_to_be16(len);
  34
  35        status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb);
  36
  37        return status;
  38}
  39
  40static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint)
  41{
  42        enum htc_endpoint_id avail_epid;
  43
  44        for (avail_epid = (ENDPOINT_MAX - 1); avail_epid > ENDPOINT0; avail_epid--)
  45                if (endpoint[avail_epid].service_id == 0)
  46                        return &endpoint[avail_epid];
  47        return NULL;
  48}
  49
  50static u8 service_to_ulpipe(u16 service_id)
  51{
  52        switch (service_id) {
  53        case WMI_CONTROL_SVC:
  54                return 4;
  55        case WMI_BEACON_SVC:
  56        case WMI_CAB_SVC:
  57        case WMI_UAPSD_SVC:
  58        case WMI_MGMT_SVC:
  59        case WMI_DATA_VO_SVC:
  60        case WMI_DATA_VI_SVC:
  61        case WMI_DATA_BE_SVC:
  62        case WMI_DATA_BK_SVC:
  63                return 1;
  64        default:
  65                return 0;
  66        }
  67}
  68
  69static u8 service_to_dlpipe(u16 service_id)
  70{
  71        switch (service_id) {
  72        case WMI_CONTROL_SVC:
  73                return 3;
  74        case WMI_BEACON_SVC:
  75        case WMI_CAB_SVC:
  76        case WMI_UAPSD_SVC:
  77        case WMI_MGMT_SVC:
  78        case WMI_DATA_VO_SVC:
  79        case WMI_DATA_VI_SVC:
  80        case WMI_DATA_BE_SVC:
  81        case WMI_DATA_BK_SVC:
  82                return 2;
  83        default:
  84                return 0;
  85        }
  86}
  87
  88static void htc_process_target_rdy(struct htc_target *target,
  89                                   void *buf)
  90{
  91        struct htc_endpoint *endpoint;
  92        struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf;
  93
  94        target->credit_size = be16_to_cpu(htc_ready_msg->credit_size);
  95
  96        endpoint = &target->endpoint[ENDPOINT0];
  97        endpoint->service_id = HTC_CTRL_RSVD_SVC;
  98        endpoint->max_msglen = HTC_MAX_CONTROL_MESSAGE_LENGTH;
  99        atomic_inc(&target->tgt_ready);
 100        complete(&target->target_wait);
 101}
 102
 103static void htc_process_conn_rsp(struct htc_target *target,
 104                                 struct htc_frame_hdr *htc_hdr)
 105{
 106        struct htc_conn_svc_rspmsg *svc_rspmsg;
 107        struct htc_endpoint *endpoint, *tmp_endpoint = NULL;
 108        u16 service_id;
 109        u16 max_msglen;
 110        enum htc_endpoint_id epid, tepid;
 111
 112        svc_rspmsg = (struct htc_conn_svc_rspmsg *)
 113                ((void *) htc_hdr + sizeof(struct htc_frame_hdr));
 114
 115        if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) {
 116                epid = svc_rspmsg->endpoint_id;
 117                service_id = be16_to_cpu(svc_rspmsg->service_id);
 118                max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
 119                endpoint = &target->endpoint[epid];
 120
 121                for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) {
 122                        tmp_endpoint = &target->endpoint[tepid];
 123                        if (tmp_endpoint->service_id == service_id) {
 124                                tmp_endpoint->service_id = 0;
 125                                break;
 126                        }
 127                }
 128
 129                if (tepid == ENDPOINT0)
 130                        return;
 131
 132                endpoint->service_id = service_id;
 133                endpoint->max_txqdepth = tmp_endpoint->max_txqdepth;
 134                endpoint->ep_callbacks = tmp_endpoint->ep_callbacks;
 135                endpoint->ul_pipeid = tmp_endpoint->ul_pipeid;
 136                endpoint->dl_pipeid = tmp_endpoint->dl_pipeid;
 137                endpoint->max_msglen = max_msglen;
 138                target->conn_rsp_epid = epid;
 139                complete(&target->cmd_wait);
 140        } else {
 141                target->conn_rsp_epid = ENDPOINT_UNUSED;
 142        }
 143}
 144
 145static int htc_config_pipe_credits(struct htc_target *target)
 146{
 147        struct sk_buff *skb;
 148        struct htc_config_pipe_msg *cp_msg;
 149        int ret;
 150        unsigned long time_left;
 151
 152        skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
 153        if (!skb) {
 154                dev_err(target->dev, "failed to allocate send buffer\n");
 155                return -ENOMEM;
 156        }
 157        skb_reserve(skb, sizeof(struct htc_frame_hdr));
 158
 159        cp_msg = (struct htc_config_pipe_msg *)
 160                skb_put(skb, sizeof(struct htc_config_pipe_msg));
 161
 162        cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
 163        cp_msg->pipe_id = USB_WLAN_TX_PIPE;
 164        cp_msg->credits = target->credits;
 165
 166        target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
 167
 168        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 169        if (ret)
 170                goto err;
 171
 172        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 173        if (!time_left) {
 174                dev_err(target->dev, "HTC credit config timeout\n");
 175                return -ETIMEDOUT;
 176        }
 177
 178        return 0;
 179err:
 180        kfree_skb(skb);
 181        return -EINVAL;
 182}
 183
 184static int htc_setup_complete(struct htc_target *target)
 185{
 186        struct sk_buff *skb;
 187        struct htc_comp_msg *comp_msg;
 188        int ret = 0;
 189        unsigned long time_left;
 190
 191        skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
 192        if (!skb) {
 193                dev_err(target->dev, "failed to allocate send buffer\n");
 194                return -ENOMEM;
 195        }
 196        skb_reserve(skb, sizeof(struct htc_frame_hdr));
 197
 198        comp_msg = (struct htc_comp_msg *)
 199                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 = (struct htc_conn_svc_msg *)
 269                        skb_put(skb, sizeof(struct htc_conn_svc_msg));
 270        conn_msg->service_id = cpu_to_be16(service_connreq->service_id);
 271        conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID);
 272        conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags);
 273        conn_msg->dl_pipeid = endpoint->dl_pipeid;
 274        conn_msg->ul_pipeid = endpoint->ul_pipeid;
 275
 276        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 277        if (ret)
 278                goto err;
 279
 280        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 281        if (!time_left) {
 282                dev_err(target->dev, "Service connection timeout for: %d\n",
 283                        service_connreq->service_id);
 284                return -ETIMEDOUT;
 285        }
 286
 287        *conn_rsp_epid = target->conn_rsp_epid;
 288        return 0;
 289err:
 290        kfree_skb(skb);
 291        return ret;
 292}
 293
 294int htc_send(struct htc_target *target, struct sk_buff *skb)
 295{
 296        struct ath9k_htc_tx_ctl *tx_ctl;
 297
 298        tx_ctl = HTC_SKB_CB(skb);
 299        return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
 300}
 301
 302int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
 303                  enum htc_endpoint_id epid)
 304{
 305        return htc_issue_send(target, skb, skb->len, 0, epid);
 306}
 307
 308void htc_stop(struct htc_target *target)
 309{
 310        target->hif->stop(target->hif_dev);
 311}
 312
 313void htc_start(struct htc_target *target)
 314{
 315        target->hif->start(target->hif_dev);
 316}
 317
 318void htc_sta_drain(struct htc_target *target, u8 idx)
 319{
 320        target->hif->sta_drain(target->hif_dev, idx);
 321}
 322
 323void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
 324                               struct sk_buff *skb, bool txok)
 325{
 326        struct htc_endpoint *endpoint;
 327        struct htc_frame_hdr *htc_hdr = NULL;
 328
 329        if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) {
 330                complete(&htc_handle->cmd_wait);
 331                htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS;
 332                goto ret;
 333        }
 334
 335        if (htc_handle->htc_flags & HTC_OP_START_WAIT) {
 336                complete(&htc_handle->cmd_wait);
 337                htc_handle->htc_flags &= ~HTC_OP_START_WAIT;
 338                goto ret;
 339        }
 340
 341        if (skb) {
 342                htc_hdr = (struct htc_frame_hdr *) skb->data;
 343                endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id];
 344                skb_pull(skb, sizeof(struct htc_frame_hdr));
 345
 346                if (endpoint->ep_callbacks.tx) {
 347                        endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
 348                                                  skb, htc_hdr->endpoint_id,
 349                                                  txok);
 350                } else {
 351                        kfree_skb(skb);
 352                }
 353        }
 354
 355        return;
 356ret:
 357        kfree_skb(skb);
 358}
 359
 360static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle,
 361                                      struct sk_buff *skb)
 362{
 363        uint32_t *pattern = (uint32_t *)skb->data;
 364
 365        switch (*pattern) {
 366        case 0x33221199:
 367                {
 368                struct htc_panic_bad_vaddr *htc_panic;
 369                htc_panic = (struct htc_panic_bad_vaddr *) skb->data;
 370                dev_err(htc_handle->dev, "ath: firmware panic! "
 371                        "exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n",
 372                        htc_panic->exccause, htc_panic->pc,
 373                        htc_panic->badvaddr);
 374                break;
 375                }
 376        case 0x33221299:
 377                {
 378                struct htc_panic_bad_epid *htc_panic;
 379                htc_panic = (struct htc_panic_bad_epid *) skb->data;
 380                dev_err(htc_handle->dev, "ath: firmware panic! "
 381                        "bad epid: 0x%08x\n", htc_panic->epid);
 382                break;
 383                }
 384        default:
 385                dev_err(htc_handle->dev, "ath: unknown panic pattern!\n");
 386                break;
 387        }
 388}
 389
 390/*
 391 * HTC Messages are handled directly here and the obtained SKB
 392 * is freed.
 393 *
 394 * Service messages (Data, WMI) passed to the corresponding
 395 * endpoint RX handlers, which have to free the SKB.
 396 */
 397void ath9k_htc_rx_msg(struct htc_target *htc_handle,
 398                      struct sk_buff *skb, u32 len, u8 pipe_id)
 399{
 400        struct htc_frame_hdr *htc_hdr;
 401        enum htc_endpoint_id epid;
 402        struct htc_endpoint *endpoint;
 403        __be16 *msg_id;
 404
 405        if (!htc_handle || !skb)
 406                return;
 407
 408        htc_hdr = (struct htc_frame_hdr *) skb->data;
 409        epid = htc_hdr->endpoint_id;
 410
 411        if (epid == 0x99) {
 412                ath9k_htc_fw_panic_report(htc_handle, skb);
 413                kfree_skb(skb);
 414                return;
 415        }
 416
 417        if (epid < 0 || epid >= ENDPOINT_MAX) {
 418                if (pipe_id != USB_REG_IN_PIPE)
 419                        dev_kfree_skb_any(skb);
 420                else
 421                        kfree_skb(skb);
 422                return;
 423        }
 424
 425        if (epid == ENDPOINT0) {
 426
 427                /* Handle trailer */
 428                if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
 429                        if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000)
 430                                /* Move past the Watchdog pattern */
 431                                htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
 432                }
 433
 434                /* Get the message ID */
 435                msg_id = (__be16 *) ((void *) htc_hdr +
 436                                     sizeof(struct htc_frame_hdr));
 437
 438                /* Now process HTC messages */
 439                switch (be16_to_cpu(*msg_id)) {
 440                case HTC_MSG_READY_ID:
 441                        htc_process_target_rdy(htc_handle, htc_hdr);
 442                        break;
 443                case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID:
 444                        htc_process_conn_rsp(htc_handle, htc_hdr);
 445                        break;
 446                default:
 447                        break;
 448                }
 449
 450                kfree_skb(skb);
 451
 452        } else {
 453                if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER)
 454                        skb_trim(skb, len - htc_hdr->control[0]);
 455
 456                skb_pull(skb, sizeof(struct htc_frame_hdr));
 457
 458                endpoint = &htc_handle->endpoint[epid];
 459                if (endpoint->ep_callbacks.rx)
 460                        endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv,
 461                                                  skb, epid);
 462        }
 463}
 464
 465struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
 466                                      struct ath9k_htc_hif *hif,
 467                                      struct device *dev)
 468{
 469        struct htc_endpoint *endpoint;
 470        struct htc_target *target;
 471
 472        target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
 473        if (!target)
 474                return NULL;
 475
 476        init_completion(&target->target_wait);
 477        init_completion(&target->cmd_wait);
 478
 479        target->hif = hif;
 480        target->hif_dev = hif_handle;
 481        target->dev = dev;
 482
 483        /* Assign control endpoint pipe IDs */
 484        endpoint = &target->endpoint[ENDPOINT0];
 485        endpoint->ul_pipeid = hif->control_ul_pipe;
 486        endpoint->dl_pipeid = hif->control_dl_pipe;
 487
 488        atomic_set(&target->tgt_ready, 0);
 489
 490        return target;
 491}
 492
 493void ath9k_htc_hw_free(struct htc_target *htc)
 494{
 495        kfree(htc);
 496}
 497
 498int ath9k_htc_hw_init(struct htc_target *target,
 499                      struct device *dev, u16 devid,
 500                      char *product, u32 drv_info)
 501{
 502        if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) {
 503                pr_err("Failed to initialize the device\n");
 504                return -ENODEV;
 505        }
 506
 507        return 0;
 508}
 509
 510void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug)
 511{
 512        if (target)
 513                ath9k_htc_disconnect_device(target, hot_unplug);
 514}
 515