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, 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 = (struct htc_config_pipe_msg *)
 159                skb_put(skb, sizeof(struct htc_config_pipe_msg));
 160
 161        cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
 162        cp_msg->pipe_id = USB_WLAN_TX_PIPE;
 163        cp_msg->credits = target->credits;
 164
 165        target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
 166
 167        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 168        if (ret)
 169                goto err;
 170
 171        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 172        if (!time_left) {
 173                dev_err(target->dev, "HTC credit config timeout\n");
 174                return -ETIMEDOUT;
 175        }
 176
 177        return 0;
 178err:
 179        kfree_skb(skb);
 180        return -EINVAL;
 181}
 182
 183static int htc_setup_complete(struct htc_target *target)
 184{
 185        struct sk_buff *skb;
 186        struct htc_comp_msg *comp_msg;
 187        int ret = 0, 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 = (struct htc_comp_msg *)
 197                skb_put(skb, sizeof(struct htc_comp_msg));
 198        comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID);
 199
 200        target->htc_flags |= HTC_OP_START_WAIT;
 201
 202        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 203        if (ret)
 204                goto err;
 205
 206        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 207        if (!time_left) {
 208                dev_err(target->dev, "HTC start timeout\n");
 209                return -ETIMEDOUT;
 210        }
 211
 212        return 0;
 213
 214err:
 215        kfree_skb(skb);
 216        return -EINVAL;
 217}
 218
 219/* HTC APIs */
 220
 221int htc_init(struct htc_target *target)
 222{
 223        int ret;
 224
 225        ret = htc_config_pipe_credits(target);
 226        if (ret)
 227                return ret;
 228
 229        return htc_setup_complete(target);
 230}
 231
 232int htc_connect_service(struct htc_target *target,
 233                     struct htc_service_connreq *service_connreq,
 234                     enum htc_endpoint_id *conn_rsp_epid)
 235{
 236        struct sk_buff *skb;
 237        struct htc_endpoint *endpoint;
 238        struct htc_conn_svc_msg *conn_msg;
 239        int ret, 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"
 245                        "service %d\n", 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 = (struct htc_conn_svc_msg *)
 266                        skb_put(skb, sizeof(struct htc_conn_svc_msg));
 267        conn_msg->service_id = cpu_to_be16(service_connreq->service_id);
 268        conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID);
 269        conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags);
 270        conn_msg->dl_pipeid = endpoint->dl_pipeid;
 271        conn_msg->ul_pipeid = endpoint->ul_pipeid;
 272
 273        ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
 274        if (ret)
 275                goto err;
 276
 277        time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
 278        if (!time_left) {
 279                dev_err(target->dev, "Service connection timeout for: %d\n",
 280                        service_connreq->service_id);
 281                return -ETIMEDOUT;
 282        }
 283
 284        *conn_rsp_epid = target->conn_rsp_epid;
 285        return 0;
 286err:
 287        kfree_skb(skb);
 288        return ret;
 289}
 290
 291int htc_send(struct htc_target *target, struct sk_buff *skb)
 292{
 293        struct ath9k_htc_tx_ctl *tx_ctl;
 294
 295        tx_ctl = HTC_SKB_CB(skb);
 296        return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
 297}
 298
 299int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
 300                  enum htc_endpoint_id epid)
 301{
 302        return htc_issue_send(target, skb, skb->len, 0, epid);
 303}
 304
 305void htc_stop(struct htc_target *target)
 306{
 307        target->hif->stop(target->hif_dev);
 308}
 309
 310void htc_start(struct htc_target *target)
 311{
 312        target->hif->start(target->hif_dev);
 313}
 314
 315void htc_sta_drain(struct htc_target *target, u8 idx)
 316{
 317        target->hif->sta_drain(target->hif_dev, idx);
 318}
 319
 320void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
 321                               struct sk_buff *skb, bool txok)
 322{
 323        struct htc_endpoint *endpoint;
 324        struct htc_frame_hdr *htc_hdr = NULL;
 325
 326        if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) {
 327                complete(&htc_handle->cmd_wait);
 328                htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS;
 329                goto ret;
 330        }
 331
 332        if (htc_handle->htc_flags & HTC_OP_START_WAIT) {
 333                complete(&htc_handle->cmd_wait);
 334                htc_handle->htc_flags &= ~HTC_OP_START_WAIT;
 335                goto ret;
 336        }
 337
 338        if (skb) {
 339                htc_hdr = (struct htc_frame_hdr *) skb->data;
 340                endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id];
 341                skb_pull(skb, sizeof(struct htc_frame_hdr));
 342
 343                if (endpoint->ep_callbacks.tx) {
 344                        endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
 345                                                  skb, htc_hdr->endpoint_id,
 346                                                  txok);
 347                } else {
 348                        kfree_skb(skb);
 349                }
 350        }
 351
 352        return;
 353ret:
 354        /* HTC-generated packets are freed here. */
 355        if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0)
 356                dev_kfree_skb_any(skb);
 357        else
 358                kfree_skb(skb);
 359}
 360
 361/*
 362 * HTC Messages are handled directly here and the obtained SKB
 363 * is freed.
 364 *
 365 * Service messages (Data, WMI) passed to the corresponding
 366 * endpoint RX handlers, which have to free the SKB.
 367 */
 368void ath9k_htc_rx_msg(struct htc_target *htc_handle,
 369                      struct sk_buff *skb, u32 len, u8 pipe_id)
 370{
 371        struct htc_frame_hdr *htc_hdr;
 372        enum htc_endpoint_id epid;
 373        struct htc_endpoint *endpoint;
 374        __be16 *msg_id;
 375
 376        if (!htc_handle || !skb)
 377                return;
 378
 379        htc_hdr = (struct htc_frame_hdr *) skb->data;
 380        epid = htc_hdr->endpoint_id;
 381
 382        if (epid >= ENDPOINT_MAX) {
 383                if (pipe_id != USB_REG_IN_PIPE)
 384                        dev_kfree_skb_any(skb);
 385                else
 386                        kfree_skb(skb);
 387                return;
 388        }
 389
 390        if (epid == ENDPOINT0) {
 391
 392                /* Handle trailer */
 393                if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
 394                        if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000)
 395                                /* Move past the Watchdog pattern */
 396                                htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
 397                }
 398
 399                /* Get the message ID */
 400                msg_id = (__be16 *) ((void *) htc_hdr +
 401                                     sizeof(struct htc_frame_hdr));
 402
 403                /* Now process HTC messages */
 404                switch (be16_to_cpu(*msg_id)) {
 405                case HTC_MSG_READY_ID:
 406                        htc_process_target_rdy(htc_handle, htc_hdr);
 407                        break;
 408                case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID:
 409                        htc_process_conn_rsp(htc_handle, htc_hdr);
 410                        break;
 411                default:
 412                        break;
 413                }
 414
 415                kfree_skb(skb);
 416
 417        } else {
 418                if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER)
 419                        skb_trim(skb, len - htc_hdr->control[0]);
 420
 421                skb_pull(skb, sizeof(struct htc_frame_hdr));
 422
 423                endpoint = &htc_handle->endpoint[epid];
 424                if (endpoint->ep_callbacks.rx)
 425                        endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv,
 426                                                  skb, epid);
 427        }
 428}
 429
 430struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
 431                                      struct ath9k_htc_hif *hif,
 432                                      struct device *dev)
 433{
 434        struct htc_endpoint *endpoint;
 435        struct htc_target *target;
 436
 437        target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
 438        if (!target)
 439                return NULL;
 440
 441        init_completion(&target->target_wait);
 442        init_completion(&target->cmd_wait);
 443
 444        target->hif = hif;
 445        target->hif_dev = hif_handle;
 446        target->dev = dev;
 447
 448        /* Assign control endpoint pipe IDs */
 449        endpoint = &target->endpoint[ENDPOINT0];
 450        endpoint->ul_pipeid = hif->control_ul_pipe;
 451        endpoint->dl_pipeid = hif->control_dl_pipe;
 452
 453        atomic_set(&target->tgt_ready, 0);
 454
 455        return target;
 456}
 457
 458void ath9k_htc_hw_free(struct htc_target *htc)
 459{
 460        kfree(htc);
 461}
 462
 463int ath9k_htc_hw_init(struct htc_target *target,
 464                      struct device *dev, u16 devid,
 465                      char *product, u32 drv_info)
 466{
 467        if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) {
 468                pr_err("Failed to initialize the device\n");
 469                return -ENODEV;
 470        }
 471
 472        return 0;
 473}
 474
 475void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug)
 476{
 477        if (target)
 478                ath9k_htc_disconnect_device(target, hot_unplug);
 479}
 480