linux/drivers/hid/intel-ish-hid/ishtp/hbm.c
<<
>>
Prefs
   1/*
   2 * ISHTP bus layer messages handling
   3 *
   4 * Copyright (c) 2003-2016, Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13 * more details.
  14 *
  15 */
  16
  17#include <linux/export.h>
  18#include <linux/slab.h>
  19#include <linux/sched.h>
  20#include <linux/wait.h>
  21#include <linux/spinlock.h>
  22#include <linux/miscdevice.h>
  23#include "ishtp-dev.h"
  24#include "hbm.h"
  25#include "client.h"
  26
  27/**
  28 * ishtp_hbm_fw_cl_allocate() - Allocate FW clients
  29 * @dev: ISHTP device instance
  30 *
  31 * Allocates storage for fw clients
  32 */
  33static void ishtp_hbm_fw_cl_allocate(struct ishtp_device *dev)
  34{
  35        struct ishtp_fw_client *clients;
  36        int b;
  37
  38        /* count how many ISH clients we have */
  39        for_each_set_bit(b, dev->fw_clients_map, ISHTP_CLIENTS_MAX)
  40                dev->fw_clients_num++;
  41
  42        if (dev->fw_clients_num <= 0)
  43                return;
  44
  45        /* allocate storage for fw clients representation */
  46        clients = kcalloc(dev->fw_clients_num, sizeof(struct ishtp_fw_client),
  47                          GFP_KERNEL);
  48        if (!clients) {
  49                dev->dev_state = ISHTP_DEV_RESETTING;
  50                ish_hw_reset(dev);
  51                return;
  52        }
  53        dev->fw_clients = clients;
  54}
  55
  56/**
  57 * ishtp_hbm_cl_hdr() - construct client hbm header
  58 * @cl: client
  59 * @hbm_cmd: host bus message command
  60 * @buf: buffer for cl header
  61 * @len: buffer length
  62 *
  63 * Initialize HBM buffer
  64 */
  65static inline void ishtp_hbm_cl_hdr(struct ishtp_cl *cl, uint8_t hbm_cmd,
  66        void *buf, size_t len)
  67{
  68        struct ishtp_hbm_cl_cmd *cmd = buf;
  69
  70        memset(cmd, 0, len);
  71
  72        cmd->hbm_cmd = hbm_cmd;
  73        cmd->host_addr = cl->host_client_id;
  74        cmd->fw_addr = cl->fw_client_id;
  75}
  76
  77/**
  78 * ishtp_hbm_cl_addr_equal() - Compare client address
  79 * @cl: client
  80 * @buf: Client command buffer
  81 *
  82 * Compare client address with the address in command buffer
  83 *
  84 * Return: True if they have the same address
  85 */
  86static inline bool ishtp_hbm_cl_addr_equal(struct ishtp_cl *cl, void *buf)
  87{
  88        struct ishtp_hbm_cl_cmd *cmd = buf;
  89
  90        return cl->host_client_id == cmd->host_addr &&
  91                cl->fw_client_id == cmd->fw_addr;
  92}
  93
  94/**
  95 * ishtp_hbm_start_wait() - Wait for HBM start message
  96 * @dev: ISHTP device instance
  97 *
  98 * Wait for HBM start message from firmware
  99 *
 100 * Return: 0 if HBM start is/was received else timeout error
 101 */
 102int ishtp_hbm_start_wait(struct ishtp_device *dev)
 103{
 104        int ret;
 105
 106        if (dev->hbm_state > ISHTP_HBM_START)
 107                return 0;
 108
 109        dev_dbg(dev->devc, "Going to wait for ishtp start. hbm_state=%08X\n",
 110                dev->hbm_state);
 111        ret = wait_event_interruptible_timeout(dev->wait_hbm_recvd_msg,
 112                                        dev->hbm_state >= ISHTP_HBM_STARTED,
 113                                        (ISHTP_INTEROP_TIMEOUT * HZ));
 114
 115        dev_dbg(dev->devc,
 116                "Woke up from waiting for ishtp start. hbm_state=%08X\n",
 117                dev->hbm_state);
 118
 119        if (ret <= 0 && (dev->hbm_state <= ISHTP_HBM_START)) {
 120                dev->hbm_state = ISHTP_HBM_IDLE;
 121                dev_err(dev->devc,
 122                "waiting for ishtp start failed. ret=%d hbm_state=%08X\n",
 123                        ret, dev->hbm_state);
 124                return -ETIMEDOUT;
 125        }
 126        return 0;
 127}
 128
 129/**
 130 * ishtp_hbm_start_req() - Send HBM start message
 131 * @dev: ISHTP device instance
 132 *
 133 * Send HBM start message to firmware
 134 *
 135 * Return: 0 if success else error code
 136 */
 137int ishtp_hbm_start_req(struct ishtp_device *dev)
 138{
 139        struct ishtp_msg_hdr hdr;
 140        unsigned char data[128];
 141        struct ishtp_msg_hdr *ishtp_hdr = &hdr;
 142        struct hbm_host_version_request *start_req;
 143        const size_t len = sizeof(struct hbm_host_version_request);
 144
 145        ishtp_hbm_hdr(ishtp_hdr, len);
 146
 147        /* host start message */
 148        start_req = (struct hbm_host_version_request *)data;
 149        memset(start_req, 0, len);
 150        start_req->hbm_cmd = HOST_START_REQ_CMD;
 151        start_req->host_version.major_version = HBM_MAJOR_VERSION;
 152        start_req->host_version.minor_version = HBM_MINOR_VERSION;
 153
 154        /*
 155         * (!) Response to HBM start may be so quick that this thread would get
 156         * preempted BEFORE managing to set hbm_state = ISHTP_HBM_START.
 157         * So set it at first, change back to ISHTP_HBM_IDLE upon failure
 158         */
 159        dev->hbm_state = ISHTP_HBM_START;
 160        if (ishtp_write_message(dev, ishtp_hdr, data)) {
 161                dev_err(dev->devc, "version message send failed\n");
 162                dev->dev_state = ISHTP_DEV_RESETTING;
 163                dev->hbm_state = ISHTP_HBM_IDLE;
 164                ish_hw_reset(dev);
 165                return -ENODEV;
 166        }
 167
 168        return 0;
 169}
 170
 171/**
 172 * ishtp_hbm_enum_clients_req() - Send client enum req
 173 * @dev: ISHTP device instance
 174 *
 175 * Send enumeration client request message
 176 *
 177 * Return: 0 if success else error code
 178 */
 179void ishtp_hbm_enum_clients_req(struct ishtp_device *dev)
 180{
 181        struct ishtp_msg_hdr hdr;
 182        unsigned char data[128];
 183        struct ishtp_msg_hdr *ishtp_hdr = &hdr;
 184        struct hbm_host_enum_request *enum_req;
 185        const size_t len = sizeof(struct hbm_host_enum_request);
 186
 187        /* enumerate clients */
 188        ishtp_hbm_hdr(ishtp_hdr, len);
 189
 190        enum_req = (struct hbm_host_enum_request *)data;
 191        memset(enum_req, 0, len);
 192        enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
 193
 194        if (ishtp_write_message(dev, ishtp_hdr, data)) {
 195                dev->dev_state = ISHTP_DEV_RESETTING;
 196                dev_err(dev->devc, "enumeration request send failed\n");
 197                ish_hw_reset(dev);
 198        }
 199        dev->hbm_state = ISHTP_HBM_ENUM_CLIENTS;
 200}
 201
 202/**
 203 * ishtp_hbm_prop_req() - Request property
 204 * @dev: ISHTP device instance
 205 *
 206 * Request property for a single client
 207 *
 208 * Return: 0 if success else error code
 209 */
 210static int ishtp_hbm_prop_req(struct ishtp_device *dev)
 211{
 212
 213        struct ishtp_msg_hdr hdr;
 214        unsigned char data[128];
 215        struct ishtp_msg_hdr *ishtp_hdr = &hdr;
 216        struct hbm_props_request *prop_req;
 217        const size_t len = sizeof(struct hbm_props_request);
 218        unsigned long next_client_index;
 219        uint8_t client_num;
 220
 221        client_num = dev->fw_client_presentation_num;
 222
 223        next_client_index = find_next_bit(dev->fw_clients_map,
 224                ISHTP_CLIENTS_MAX, dev->fw_client_index);
 225
 226        /* We got all client properties */
 227        if (next_client_index == ISHTP_CLIENTS_MAX) {
 228                dev->hbm_state = ISHTP_HBM_WORKING;
 229                dev->dev_state = ISHTP_DEV_ENABLED;
 230
 231                for (dev->fw_client_presentation_num = 1;
 232                        dev->fw_client_presentation_num < client_num + 1;
 233                                ++dev->fw_client_presentation_num)
 234                        /* Add new client device */
 235                        ishtp_bus_new_client(dev);
 236                return 0;
 237        }
 238
 239        dev->fw_clients[client_num].client_id = next_client_index;
 240
 241        ishtp_hbm_hdr(ishtp_hdr, len);
 242        prop_req = (struct hbm_props_request *)data;
 243
 244        memset(prop_req, 0, sizeof(struct hbm_props_request));
 245
 246        prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
 247        prop_req->address = next_client_index;
 248
 249        if (ishtp_write_message(dev, ishtp_hdr, data)) {
 250                dev->dev_state = ISHTP_DEV_RESETTING;
 251                dev_err(dev->devc, "properties request send failed\n");
 252                ish_hw_reset(dev);
 253                return -EIO;
 254        }
 255
 256        dev->fw_client_index = next_client_index;
 257
 258        return 0;
 259}
 260
 261/**
 262 * ishtp_hbm_stop_req() - Send HBM stop
 263 * @dev: ISHTP device instance
 264 *
 265 * Send stop request message
 266 */
 267static void ishtp_hbm_stop_req(struct ishtp_device *dev)
 268{
 269        struct ishtp_msg_hdr hdr;
 270        unsigned char data[128];
 271        struct ishtp_msg_hdr *ishtp_hdr = &hdr;
 272        struct hbm_host_stop_request *req;
 273        const size_t len = sizeof(struct hbm_host_stop_request);
 274
 275        ishtp_hbm_hdr(ishtp_hdr, len);
 276        req = (struct hbm_host_stop_request *)data;
 277
 278        memset(req, 0, sizeof(struct hbm_host_stop_request));
 279        req->hbm_cmd = HOST_STOP_REQ_CMD;
 280        req->reason = DRIVER_STOP_REQUEST;
 281
 282        ishtp_write_message(dev, ishtp_hdr, data);
 283}
 284
 285/**
 286 * ishtp_hbm_cl_flow_control_req() - Send flow control request
 287 * @dev: ISHTP device instance
 288 * @cl: ISHTP client instance
 289 *
 290 * Send flow control request
 291 *
 292 * Return: 0 if success else error code
 293 */
 294int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev,
 295                                  struct ishtp_cl *cl)
 296{
 297        struct ishtp_msg_hdr hdr;
 298        unsigned char data[128];
 299        struct ishtp_msg_hdr *ishtp_hdr = &hdr;
 300        const size_t len = sizeof(struct hbm_flow_control);
 301        int     rv;
 302        unsigned int    num_frags;
 303        unsigned long   flags;
 304
 305        spin_lock_irqsave(&cl->fc_spinlock, flags);
 306        ishtp_hbm_hdr(ishtp_hdr, len);
 307        ishtp_hbm_cl_hdr(cl, ISHTP_FLOW_CONTROL_CMD, data, len);
 308
 309        /*
 310         * Sync possible race when RB recycle and packet receive paths
 311         * both try to send an out FC
 312         */
 313        if (cl->out_flow_ctrl_creds) {
 314                spin_unlock_irqrestore(&cl->fc_spinlock, flags);
 315                return  0;
 316        }
 317
 318        num_frags = cl->recv_msg_num_frags;
 319        cl->recv_msg_num_frags = 0;
 320
 321        rv = ishtp_write_message(dev, ishtp_hdr, data);
 322        if (!rv) {
 323                ++cl->out_flow_ctrl_creds;
 324                ++cl->out_flow_ctrl_cnt;
 325                getnstimeofday(&cl->ts_out_fc);
 326                if (cl->ts_rx.tv_sec && cl->ts_rx.tv_nsec) {
 327                        struct timespec ts_diff;
 328
 329                        ts_diff = timespec_sub(cl->ts_out_fc, cl->ts_rx);
 330                        if (timespec_compare(&ts_diff, &cl->ts_max_fc_delay)
 331                                        > 0)
 332                                cl->ts_max_fc_delay = ts_diff;
 333                }
 334        } else {
 335                ++cl->err_send_fc;
 336        }
 337
 338        spin_unlock_irqrestore(&cl->fc_spinlock, flags);
 339        return  rv;
 340}
 341
 342/**
 343 * ishtp_hbm_cl_disconnect_req() - Send disconnect request
 344 * @dev: ISHTP device instance
 345 * @cl: ISHTP client instance
 346 *
 347 * Send disconnect message to fw
 348 *
 349 * Return: 0 if success else error code
 350 */
 351int ishtp_hbm_cl_disconnect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
 352{
 353        struct ishtp_msg_hdr hdr;
 354        unsigned char data[128];
 355        struct ishtp_msg_hdr *ishtp_hdr = &hdr;
 356        const size_t len = sizeof(struct hbm_client_connect_request);
 357
 358        ishtp_hbm_hdr(ishtp_hdr, len);
 359        ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, data, len);
 360
 361        return ishtp_write_message(dev, ishtp_hdr, data);
 362}
 363
 364/**
 365 * ishtp_hbm_cl_disconnect_res() - Get disconnect response
 366 * @dev: ISHTP device instance
 367 * @rs: Response message
 368 *
 369 * Received disconnect response from fw
 370 */
 371static void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev,
 372        struct hbm_client_connect_response *rs)
 373{
 374        struct ishtp_cl *cl = NULL;
 375        unsigned long   flags;
 376
 377        spin_lock_irqsave(&dev->cl_list_lock, flags);
 378        list_for_each_entry(cl, &dev->cl_list, link) {
 379                if (!rs->status && ishtp_hbm_cl_addr_equal(cl, rs)) {
 380                        cl->state = ISHTP_CL_DISCONNECTED;
 381                        wake_up_interruptible(&cl->wait_ctrl_res);
 382                        break;
 383                }
 384        }
 385        spin_unlock_irqrestore(&dev->cl_list_lock, flags);
 386}
 387
 388/**
 389 * ishtp_hbm_cl_connect_req() - Send connect request
 390 * @dev: ISHTP device instance
 391 * @cl: client device instance
 392 *
 393 * Send connection request to specific fw client
 394 *
 395 * Return: 0 if success else error code
 396 */
 397int ishtp_hbm_cl_connect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
 398{
 399        struct ishtp_msg_hdr hdr;
 400        unsigned char data[128];
 401        struct ishtp_msg_hdr *ishtp_hdr = &hdr;
 402        const size_t len = sizeof(struct hbm_client_connect_request);
 403
 404        ishtp_hbm_hdr(ishtp_hdr, len);
 405        ishtp_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, data, len);
 406
 407        return ishtp_write_message(dev, ishtp_hdr, data);
 408}
 409
 410/**
 411 * ishtp_hbm_cl_connect_res() - Get connect response
 412 * @dev: ISHTP device instance
 413 * @rs: Response message
 414 *
 415 * Received connect response from fw
 416 */
 417static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev,
 418        struct hbm_client_connect_response *rs)
 419{
 420        struct ishtp_cl *cl = NULL;
 421        unsigned long   flags;
 422
 423        spin_lock_irqsave(&dev->cl_list_lock, flags);
 424        list_for_each_entry(cl, &dev->cl_list, link) {
 425                if (ishtp_hbm_cl_addr_equal(cl, rs)) {
 426                        if (!rs->status) {
 427                                cl->state = ISHTP_CL_CONNECTED;
 428                                cl->status = 0;
 429                        } else {
 430                                cl->state = ISHTP_CL_DISCONNECTED;
 431                                cl->status = -ENODEV;
 432                        }
 433                        wake_up_interruptible(&cl->wait_ctrl_res);
 434                        break;
 435                }
 436        }
 437        spin_unlock_irqrestore(&dev->cl_list_lock, flags);
 438}
 439
 440/**
 441 * ishtp_client_disconnect_request() - Receive disconnect request
 442 * @dev: ISHTP device instance
 443 * @disconnect_req: disconnect request structure
 444 *
 445 * Disconnect request bus message from the fw. Send diconnect response.
 446 */
 447static void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev,
 448        struct hbm_client_connect_request *disconnect_req)
 449{
 450        struct ishtp_cl *cl;
 451        const size_t len = sizeof(struct hbm_client_connect_response);
 452        unsigned long   flags;
 453        struct ishtp_msg_hdr hdr;
 454        unsigned char data[4];  /* All HBM messages are 4 bytes */
 455
 456        spin_lock_irqsave(&dev->cl_list_lock, flags);
 457        list_for_each_entry(cl, &dev->cl_list, link) {
 458                if (ishtp_hbm_cl_addr_equal(cl, disconnect_req)) {
 459                        cl->state = ISHTP_CL_DISCONNECTED;
 460
 461                        /* send disconnect response */
 462                        ishtp_hbm_hdr(&hdr, len);
 463                        ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, data,
 464                                len);
 465                        ishtp_write_message(dev, &hdr, data);
 466                        break;
 467                }
 468        }
 469        spin_unlock_irqrestore(&dev->cl_list_lock, flags);
 470}
 471
 472/**
 473 * ishtp_hbm_dma_xfer_ack(() - Receive transfer ACK
 474 * @dev: ISHTP device instance
 475 * @dma_xfer: HBM transfer message
 476 *
 477 * Receive ack for ISHTP-over-DMA client message
 478 */
 479static void ishtp_hbm_dma_xfer_ack(struct ishtp_device *dev,
 480                                   struct dma_xfer_hbm *dma_xfer)
 481{
 482        void    *msg;
 483        uint64_t        offs;
 484        struct ishtp_msg_hdr    *ishtp_hdr =
 485                (struct ishtp_msg_hdr *)&dev->ishtp_msg_hdr;
 486        unsigned int    msg_offs;
 487        struct ishtp_cl *cl;
 488
 489        for (msg_offs = 0; msg_offs < ishtp_hdr->length;
 490                msg_offs += sizeof(struct dma_xfer_hbm)) {
 491                offs = dma_xfer->msg_addr - dev->ishtp_host_dma_tx_buf_phys;
 492                if (offs > dev->ishtp_host_dma_tx_buf_size) {
 493                        dev_err(dev->devc, "Bad DMA Tx ack message address\n");
 494                        return;
 495                }
 496                if (dma_xfer->msg_length >
 497                                dev->ishtp_host_dma_tx_buf_size - offs) {
 498                        dev_err(dev->devc, "Bad DMA Tx ack message size\n");
 499                        return;
 500                }
 501
 502                /* logical address of the acked mem */
 503                msg = (unsigned char *)dev->ishtp_host_dma_tx_buf + offs;
 504                ishtp_cl_release_dma_acked_mem(dev, msg, dma_xfer->msg_length);
 505
 506                list_for_each_entry(cl, &dev->cl_list, link) {
 507                        if (cl->fw_client_id == dma_xfer->fw_client_id &&
 508                            cl->host_client_id == dma_xfer->host_client_id)
 509                                /*
 510                                 * in case that a single ack may be sent
 511                                 * over several dma transfers, and the last msg
 512                                 * addr was inside the acked memory, but not in
 513                                 * its start
 514                                 */
 515                                if (cl->last_dma_addr >=
 516                                                        (unsigned char *)msg &&
 517                                                cl->last_dma_addr <
 518                                                (unsigned char *)msg +
 519                                                dma_xfer->msg_length) {
 520                                        cl->last_dma_acked = 1;
 521
 522                                        if (!list_empty(&cl->tx_list.list) &&
 523                                                cl->ishtp_flow_ctrl_creds) {
 524                                                /*
 525                                                 * start sending the first msg
 526                                                 */
 527                                                ishtp_cl_send_msg(dev, cl);
 528                                        }
 529                                }
 530                }
 531                ++dma_xfer;
 532        }
 533}
 534
 535/**
 536 * ishtp_hbm_dma_xfer() - Receive DMA transfer message
 537 * @dev: ISHTP device instance
 538 * @dma_xfer: HBM transfer message
 539 *
 540 * Receive ISHTP-over-DMA client message
 541 */
 542static void ishtp_hbm_dma_xfer(struct ishtp_device *dev,
 543                               struct dma_xfer_hbm *dma_xfer)
 544{
 545        void    *msg;
 546        uint64_t        offs;
 547        struct ishtp_msg_hdr    hdr;
 548        struct ishtp_msg_hdr    *ishtp_hdr =
 549                (struct ishtp_msg_hdr *) &dev->ishtp_msg_hdr;
 550        struct dma_xfer_hbm     *prm = dma_xfer;
 551        unsigned int    msg_offs;
 552
 553        for (msg_offs = 0; msg_offs < ishtp_hdr->length;
 554                msg_offs += sizeof(struct dma_xfer_hbm)) {
 555
 556                offs = dma_xfer->msg_addr - dev->ishtp_host_dma_rx_buf_phys;
 557                if (offs > dev->ishtp_host_dma_rx_buf_size) {
 558                        dev_err(dev->devc, "Bad DMA Rx message address\n");
 559                        return;
 560                }
 561                if (dma_xfer->msg_length >
 562                                dev->ishtp_host_dma_rx_buf_size - offs) {
 563                        dev_err(dev->devc, "Bad DMA Rx message size\n");
 564                        return;
 565                }
 566                msg = dev->ishtp_host_dma_rx_buf + offs;
 567                recv_ishtp_cl_msg_dma(dev, msg, dma_xfer);
 568                dma_xfer->hbm = DMA_XFER_ACK;   /* Prepare for response */
 569                ++dma_xfer;
 570        }
 571
 572        /* Send DMA_XFER_ACK [...] */
 573        ishtp_hbm_hdr(&hdr, ishtp_hdr->length);
 574        ishtp_write_message(dev, &hdr, (unsigned char *)prm);
 575}
 576
 577/**
 578 * ishtp_hbm_dispatch() - HBM dispatch function
 579 * @dev: ISHTP device instance
 580 * @hdr: bus message
 581 *
 582 * Bottom half read routine after ISR to handle the read bus message cmd
 583 * processing
 584 */
 585void ishtp_hbm_dispatch(struct ishtp_device *dev,
 586                        struct ishtp_bus_message *hdr)
 587{
 588        struct ishtp_bus_message *ishtp_msg;
 589        struct ishtp_fw_client *fw_client;
 590        struct hbm_host_version_response *version_res;
 591        struct hbm_client_connect_response *connect_res;
 592        struct hbm_client_connect_response *disconnect_res;
 593        struct hbm_client_connect_request *disconnect_req;
 594        struct hbm_props_response *props_res;
 595        struct hbm_host_enum_response *enum_res;
 596        struct ishtp_msg_hdr ishtp_hdr;
 597        struct dma_alloc_notify dma_alloc_notify;
 598        struct dma_xfer_hbm     *dma_xfer;
 599
 600        ishtp_msg = hdr;
 601
 602        switch (ishtp_msg->hbm_cmd) {
 603        case HOST_START_RES_CMD:
 604                version_res = (struct hbm_host_version_response *)ishtp_msg;
 605                if (!version_res->host_version_supported) {
 606                        dev->version = version_res->fw_max_version;
 607
 608                        dev->hbm_state = ISHTP_HBM_STOPPED;
 609                        ishtp_hbm_stop_req(dev);
 610                        return;
 611                }
 612
 613                dev->version.major_version = HBM_MAJOR_VERSION;
 614                dev->version.minor_version = HBM_MINOR_VERSION;
 615                if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
 616                                dev->hbm_state == ISHTP_HBM_START) {
 617                        dev->hbm_state = ISHTP_HBM_STARTED;
 618                        ishtp_hbm_enum_clients_req(dev);
 619                } else {
 620                        dev_err(dev->devc,
 621                                "reset: wrong host start response\n");
 622                        /* BUG: why do we arrive here? */
 623                        ish_hw_reset(dev);
 624                        return;
 625                }
 626
 627                wake_up_interruptible(&dev->wait_hbm_recvd_msg);
 628                break;
 629
 630        case CLIENT_CONNECT_RES_CMD:
 631                connect_res = (struct hbm_client_connect_response *)ishtp_msg;
 632                ishtp_hbm_cl_connect_res(dev, connect_res);
 633                break;
 634
 635        case CLIENT_DISCONNECT_RES_CMD:
 636                disconnect_res =
 637                        (struct hbm_client_connect_response *)ishtp_msg;
 638                ishtp_hbm_cl_disconnect_res(dev, disconnect_res);
 639                break;
 640
 641        case HOST_CLIENT_PROPERTIES_RES_CMD:
 642                props_res = (struct hbm_props_response *)ishtp_msg;
 643                fw_client = &dev->fw_clients[dev->fw_client_presentation_num];
 644
 645                if (props_res->status || !dev->fw_clients) {
 646                        dev_err(dev->devc,
 647                        "reset: properties response hbm wrong status\n");
 648                        ish_hw_reset(dev);
 649                        return;
 650                }
 651
 652                if (fw_client->client_id != props_res->address) {
 653                        dev_err(dev->devc,
 654                                "reset: host properties response address mismatch [%02X %02X]\n",
 655                                fw_client->client_id, props_res->address);
 656                        ish_hw_reset(dev);
 657                        return;
 658                }
 659
 660                if (dev->dev_state != ISHTP_DEV_INIT_CLIENTS ||
 661                        dev->hbm_state != ISHTP_HBM_CLIENT_PROPERTIES) {
 662                        dev_err(dev->devc,
 663                                "reset: unexpected properties response\n");
 664                        ish_hw_reset(dev);
 665                        return;
 666                }
 667
 668                fw_client->props = props_res->client_properties;
 669                dev->fw_client_index++;
 670                dev->fw_client_presentation_num++;
 671
 672                /* request property for the next client */
 673                ishtp_hbm_prop_req(dev);
 674
 675                if (dev->dev_state != ISHTP_DEV_ENABLED)
 676                        break;
 677
 678                if (!ishtp_use_dma_transfer())
 679                        break;
 680
 681                dev_dbg(dev->devc, "Requesting to use DMA\n");
 682                ishtp_cl_alloc_dma_buf(dev);
 683                if (dev->ishtp_host_dma_rx_buf) {
 684                        const size_t len = sizeof(dma_alloc_notify);
 685
 686                        memset(&dma_alloc_notify, 0, sizeof(dma_alloc_notify));
 687                        dma_alloc_notify.hbm = DMA_BUFFER_ALLOC_NOTIFY;
 688                        dma_alloc_notify.buf_size =
 689                                        dev->ishtp_host_dma_rx_buf_size;
 690                        dma_alloc_notify.buf_address =
 691                                        dev->ishtp_host_dma_rx_buf_phys;
 692                        ishtp_hbm_hdr(&ishtp_hdr, len);
 693                        ishtp_write_message(dev, &ishtp_hdr,
 694                                (unsigned char *)&dma_alloc_notify);
 695                }
 696
 697                break;
 698
 699        case HOST_ENUM_RES_CMD:
 700                enum_res = (struct hbm_host_enum_response *) ishtp_msg;
 701                memcpy(dev->fw_clients_map, enum_res->valid_addresses, 32);
 702                if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
 703                        dev->hbm_state == ISHTP_HBM_ENUM_CLIENTS) {
 704                        dev->fw_client_presentation_num = 0;
 705                        dev->fw_client_index = 0;
 706
 707                        ishtp_hbm_fw_cl_allocate(dev);
 708                        dev->hbm_state = ISHTP_HBM_CLIENT_PROPERTIES;
 709
 710                        /* first property request */
 711                        ishtp_hbm_prop_req(dev);
 712                } else {
 713                        dev_err(dev->devc,
 714                              "reset: unexpected enumeration response hbm\n");
 715                        ish_hw_reset(dev);
 716                        return;
 717                }
 718                break;
 719
 720        case HOST_STOP_RES_CMD:
 721                if (dev->hbm_state != ISHTP_HBM_STOPPED)
 722                        dev_err(dev->devc, "unexpected stop response\n");
 723
 724                dev->dev_state = ISHTP_DEV_DISABLED;
 725                dev_info(dev->devc, "reset: FW stop response\n");
 726                ish_hw_reset(dev);
 727                break;
 728
 729        case CLIENT_DISCONNECT_REQ_CMD:
 730                /* search for client */
 731                disconnect_req =
 732                        (struct hbm_client_connect_request *)ishtp_msg;
 733                ishtp_hbm_fw_disconnect_req(dev, disconnect_req);
 734                break;
 735
 736        case FW_STOP_REQ_CMD:
 737                dev->hbm_state = ISHTP_HBM_STOPPED;
 738                break;
 739
 740        case DMA_BUFFER_ALLOC_RESPONSE:
 741                dev->ishtp_host_dma_enabled = 1;
 742                break;
 743
 744        case DMA_XFER:
 745                dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
 746                if (!dev->ishtp_host_dma_enabled) {
 747                        dev_err(dev->devc,
 748                                "DMA XFER requested but DMA is not enabled\n");
 749                        break;
 750                }
 751                ishtp_hbm_dma_xfer(dev, dma_xfer);
 752                break;
 753
 754        case DMA_XFER_ACK:
 755                dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
 756                if (!dev->ishtp_host_dma_enabled ||
 757                    !dev->ishtp_host_dma_tx_buf) {
 758                        dev_err(dev->devc,
 759                                "DMA XFER acked but DMA Tx is not enabled\n");
 760                        break;
 761                }
 762                ishtp_hbm_dma_xfer_ack(dev, dma_xfer);
 763                break;
 764
 765        default:
 766                dev_err(dev->devc, "unknown HBM: %u\n",
 767                        (unsigned int)ishtp_msg->hbm_cmd);
 768
 769                break;
 770        }
 771}
 772
 773/**
 774 * bh_hbm_work_fn() - HBM work function
 775 * @work: work struct
 776 *
 777 * Bottom half processing work function (instead of thread handler)
 778 * for processing hbm messages
 779 */
 780void    bh_hbm_work_fn(struct work_struct *work)
 781{
 782        unsigned long   flags;
 783        struct ishtp_device     *dev;
 784        unsigned char   hbm[IPC_PAYLOAD_SIZE];
 785
 786        dev = container_of(work, struct ishtp_device, bh_hbm_work);
 787        spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
 788        if (dev->rd_msg_fifo_head != dev->rd_msg_fifo_tail) {
 789                memcpy(hbm, dev->rd_msg_fifo + dev->rd_msg_fifo_head,
 790                        IPC_PAYLOAD_SIZE);
 791                dev->rd_msg_fifo_head =
 792                        (dev->rd_msg_fifo_head + IPC_PAYLOAD_SIZE) %
 793                        (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
 794                spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
 795                ishtp_hbm_dispatch(dev, (struct ishtp_bus_message *)hbm);
 796        } else {
 797                spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
 798        }
 799}
 800
 801/**
 802 * recv_hbm() - Receive HBM message
 803 * @dev: ISHTP device instance
 804 * @ishtp_hdr: received bus message
 805 *
 806 * Receive and process ISHTP bus messages in ISR context. This will schedule
 807 * work function to process message
 808 */
 809void    recv_hbm(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr)
 810{
 811        uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
 812        struct ishtp_bus_message        *ishtp_msg =
 813                (struct ishtp_bus_message *)rd_msg_buf;
 814        unsigned long   flags;
 815
 816        dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
 817
 818        /* Flow control - handle in place */
 819        if (ishtp_msg->hbm_cmd == ISHTP_FLOW_CONTROL_CMD) {
 820                struct hbm_flow_control *flow_control =
 821                        (struct hbm_flow_control *)ishtp_msg;
 822                struct ishtp_cl *cl = NULL;
 823                unsigned long   flags, tx_flags;
 824
 825                spin_lock_irqsave(&dev->cl_list_lock, flags);
 826                list_for_each_entry(cl, &dev->cl_list, link) {
 827                        if (cl->host_client_id == flow_control->host_addr &&
 828                                        cl->fw_client_id ==
 829                                        flow_control->fw_addr) {
 830                                /*
 831                                 * NOTE: It's valid only for counting
 832                                 * flow-control implementation to receive a
 833                                 * FC in the middle of sending. Meanwhile not
 834                                 * supported
 835                                 */
 836                                if (cl->ishtp_flow_ctrl_creds)
 837                                        dev_err(dev->devc,
 838                                         "recv extra FC from FW client %u (host client %u) (FC count was %d)\n",
 839                                         (unsigned int)cl->fw_client_id,
 840                                         (unsigned int)cl->host_client_id,
 841                                         cl->ishtp_flow_ctrl_creds);
 842                                else {
 843                                        ++cl->ishtp_flow_ctrl_creds;
 844                                        ++cl->ishtp_flow_ctrl_cnt;
 845                                        cl->last_ipc_acked = 1;
 846                                        spin_lock_irqsave(
 847                                                        &cl->tx_list_spinlock,
 848                                                        tx_flags);
 849                                        if (!list_empty(&cl->tx_list.list)) {
 850                                                /*
 851                                                 * start sending the first msg
 852                                                 *      = the callback function
 853                                                 */
 854                                                spin_unlock_irqrestore(
 855                                                        &cl->tx_list_spinlock,
 856                                                        tx_flags);
 857                                                ishtp_cl_send_msg(dev, cl);
 858                                        } else {
 859                                                spin_unlock_irqrestore(
 860                                                        &cl->tx_list_spinlock,
 861                                                        tx_flags);
 862                                        }
 863                                }
 864                                break;
 865                        }
 866                }
 867                spin_unlock_irqrestore(&dev->cl_list_lock, flags);
 868                goto    eoi;
 869        }
 870
 871        /*
 872         * Some messages that are safe for ISR processing and important
 873         * to be done "quickly" and in-order, go here
 874         */
 875        if (ishtp_msg->hbm_cmd == CLIENT_CONNECT_RES_CMD ||
 876                        ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_RES_CMD ||
 877                        ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_REQ_CMD ||
 878                        ishtp_msg->hbm_cmd == DMA_XFER) {
 879                ishtp_hbm_dispatch(dev, ishtp_msg);
 880                goto    eoi;
 881        }
 882
 883        /*
 884         * All other HBMs go here.
 885         * We schedule HBMs for processing serially by using system wq,
 886         * possibly there will be multiple HBMs scheduled at the same time.
 887         */
 888        spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
 889        if ((dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
 890                        (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE) ==
 891                        dev->rd_msg_fifo_head) {
 892                spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
 893                dev_err(dev->devc, "BH buffer overflow, dropping HBM %u\n",
 894                        (unsigned int)ishtp_msg->hbm_cmd);
 895                goto    eoi;
 896        }
 897        memcpy(dev->rd_msg_fifo + dev->rd_msg_fifo_tail, ishtp_msg,
 898                ishtp_hdr->length);
 899        dev->rd_msg_fifo_tail = (dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
 900                (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
 901        spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
 902        schedule_work(&dev->bh_hbm_work);
 903eoi:
 904        return;
 905}
 906
 907/**
 908 * recv_fixed_cl_msg() - Receive fixed client message
 909 * @dev: ISHTP device instance
 910 * @ishtp_hdr: received bus message
 911 *
 912 * Receive and process ISHTP fixed client messages (address == 0)
 913 * in ISR context
 914 */
 915void recv_fixed_cl_msg(struct ishtp_device *dev,
 916        struct ishtp_msg_hdr *ishtp_hdr)
 917{
 918        uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
 919
 920        dev->print_log(dev,
 921                "%s() got fixed client msg from client #%d\n",
 922                __func__, ishtp_hdr->fw_addr);
 923        dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
 924        if (ishtp_hdr->fw_addr == ISHTP_SYSTEM_STATE_CLIENT_ADDR) {
 925                struct ish_system_states_header *msg_hdr =
 926                        (struct ish_system_states_header *)rd_msg_buf;
 927                if (msg_hdr->cmd == SYSTEM_STATE_SUBSCRIBE)
 928                        ishtp_send_resume(dev);
 929                /* if FW request arrived here, the system is not suspended */
 930                else
 931                        dev_err(dev->devc, "unknown fixed client msg [%02X]\n",
 932                                msg_hdr->cmd);
 933        }
 934}
 935
 936/**
 937 * fix_cl_hdr() - Initialize fixed client header
 938 * @hdr: message header
 939 * @length: length of message
 940 * @cl_addr: Client address
 941 *
 942 * Initialize message header for fixed client
 943 */
 944static inline void fix_cl_hdr(struct ishtp_msg_hdr *hdr, size_t length,
 945        uint8_t cl_addr)
 946{
 947        hdr->host_addr = 0;
 948        hdr->fw_addr = cl_addr;
 949        hdr->length = length;
 950        hdr->msg_complete = 1;
 951        hdr->reserved = 0;
 952}
 953
 954/*** Suspend and resume notification ***/
 955
 956static uint32_t current_state;
 957static uint32_t supported_states = 0 | SUSPEND_STATE_BIT;
 958
 959/**
 960 * ishtp_send_suspend() - Send suspend message to FW
 961 * @dev: ISHTP device instance
 962 *
 963 * Send suspend message to FW. This is useful for system freeze (non S3) case
 964 */
 965void ishtp_send_suspend(struct ishtp_device *dev)
 966{
 967        struct ishtp_msg_hdr    ishtp_hdr;
 968        struct ish_system_states_status state_status_msg;
 969        const size_t len = sizeof(struct ish_system_states_status);
 970
 971        fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
 972
 973        memset(&state_status_msg, 0, len);
 974        state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
 975        state_status_msg.supported_states = supported_states;
 976        current_state |= SUSPEND_STATE_BIT;
 977        dev->print_log(dev, "%s() sends SUSPEND notification\n", __func__);
 978        state_status_msg.states_status = current_state;
 979
 980        ishtp_write_message(dev, &ishtp_hdr,
 981                (unsigned char *)&state_status_msg);
 982}
 983EXPORT_SYMBOL(ishtp_send_suspend);
 984
 985/**
 986 * ishtp_send_resume() - Send resume message to FW
 987 * @dev: ISHTP device instance
 988 *
 989 * Send resume message to FW. This is useful for system freeze (non S3) case
 990 */
 991void ishtp_send_resume(struct ishtp_device *dev)
 992{
 993        struct ishtp_msg_hdr    ishtp_hdr;
 994        struct ish_system_states_status state_status_msg;
 995        const size_t len = sizeof(struct ish_system_states_status);
 996
 997        fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
 998
 999        memset(&state_status_msg, 0, len);
1000        state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
1001        state_status_msg.supported_states = supported_states;
1002        current_state &= ~SUSPEND_STATE_BIT;
1003        dev->print_log(dev, "%s() sends RESUME notification\n", __func__);
1004        state_status_msg.states_status = current_state;
1005
1006        ishtp_write_message(dev, &ishtp_hdr,
1007                (unsigned char *)&state_status_msg);
1008}
1009EXPORT_SYMBOL(ishtp_send_resume);
1010
1011/**
1012 * ishtp_query_subscribers() - Send query subscribers message
1013 * @dev: ISHTP device instance
1014 *
1015 * Send message to query subscribers
1016 */
1017void ishtp_query_subscribers(struct ishtp_device *dev)
1018{
1019        struct ishtp_msg_hdr    ishtp_hdr;
1020        struct ish_system_states_query_subscribers query_subscribers_msg;
1021        const size_t len = sizeof(struct ish_system_states_query_subscribers);
1022
1023        fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
1024
1025        memset(&query_subscribers_msg, 0, len);
1026        query_subscribers_msg.hdr.cmd = SYSTEM_STATE_QUERY_SUBSCRIBERS;
1027
1028        ishtp_write_message(dev, &ishtp_hdr,
1029                (unsigned char *)&query_subscribers_msg);
1030}
1031