linux/drivers/hid/intel-ish-hid/ipc/ipc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * H/W layer of ISHTP provider device (ISH)
   4 *
   5 * Copyright (c) 2014-2016, Intel Corporation.
   6 */
   7
   8#include <linux/sched.h>
   9#include <linux/spinlock.h>
  10#include <linux/delay.h>
  11#include <linux/jiffies.h>
  12#include "client.h"
  13#include "hw-ish.h"
  14#include "hbm.h"
  15
  16/* For FW reset flow */
  17static struct work_struct fw_reset_work;
  18static struct ishtp_device *ishtp_dev;
  19
  20/**
  21 * ish_reg_read() - Read register
  22 * @dev: ISHTP device pointer
  23 * @offset: Register offset
  24 *
  25 * Read 32 bit register at a given offset
  26 *
  27 * Return: Read register value
  28 */
  29static inline uint32_t ish_reg_read(const struct ishtp_device *dev,
  30        unsigned long offset)
  31{
  32        struct ish_hw *hw = to_ish_hw(dev);
  33
  34        return readl(hw->mem_addr + offset);
  35}
  36
  37/**
  38 * ish_reg_write() - Write register
  39 * @dev: ISHTP device pointer
  40 * @offset: Register offset
  41 * @value: Value to write
  42 *
  43 * Writes 32 bit register at a give offset
  44 */
  45static inline void ish_reg_write(struct ishtp_device *dev,
  46                                 unsigned long offset,
  47                                 uint32_t value)
  48{
  49        struct ish_hw *hw = to_ish_hw(dev);
  50
  51        writel(value, hw->mem_addr + offset);
  52}
  53
  54/**
  55 * _ish_read_fw_sts_reg() - Read FW status register
  56 * @dev: ISHTP device pointer
  57 *
  58 * Read FW status register
  59 *
  60 * Return: Read register value
  61 */
  62static inline uint32_t _ish_read_fw_sts_reg(struct ishtp_device *dev)
  63{
  64        return ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
  65}
  66
  67/**
  68 * check_generated_interrupt() - Check if ISH interrupt
  69 * @dev: ISHTP device pointer
  70 *
  71 * Check if an interrupt was generated for ISH
  72 *
  73 * Return: Read true or false
  74 */
  75static bool check_generated_interrupt(struct ishtp_device *dev)
  76{
  77        bool interrupt_generated = true;
  78        uint32_t pisr_val = 0;
  79
  80        if (dev->pdev->device == CHV_DEVICE_ID) {
  81                pisr_val = ish_reg_read(dev, IPC_REG_PISR_CHV_AB);
  82                interrupt_generated =
  83                        IPC_INT_FROM_ISH_TO_HOST_CHV_AB(pisr_val);
  84        } else {
  85                pisr_val = ish_reg_read(dev, IPC_REG_PISR_BXT);
  86                interrupt_generated = !!pisr_val;
  87                /* only busy-clear bit is RW, others are RO */
  88                if (pisr_val)
  89                        ish_reg_write(dev, IPC_REG_PISR_BXT, pisr_val);
  90        }
  91
  92        return interrupt_generated;
  93}
  94
  95/**
  96 * ish_is_input_ready() - Check if FW ready for RX
  97 * @dev: ISHTP device pointer
  98 *
  99 * Check if ISH FW is ready for receiving data
 100 *
 101 * Return: Read true or false
 102 */
 103static bool ish_is_input_ready(struct ishtp_device *dev)
 104{
 105        uint32_t doorbell_val;
 106
 107        doorbell_val = ish_reg_read(dev, IPC_REG_HOST2ISH_DRBL);
 108        return !IPC_IS_BUSY(doorbell_val);
 109}
 110
 111/**
 112 * set_host_ready() - Indicate host ready
 113 * @dev: ISHTP device pointer
 114 *
 115 * Set host ready indication to FW
 116 */
 117static void set_host_ready(struct ishtp_device *dev)
 118{
 119        if (dev->pdev->device == CHV_DEVICE_ID) {
 120                if (dev->pdev->revision == REVISION_ID_CHT_A0 ||
 121                                (dev->pdev->revision & REVISION_ID_SI_MASK) ==
 122                                REVISION_ID_CHT_Ax_SI)
 123                        ish_reg_write(dev, IPC_REG_HOST_COMM, 0x81);
 124                else if (dev->pdev->revision == REVISION_ID_CHT_B0 ||
 125                                (dev->pdev->revision & REVISION_ID_SI_MASK) ==
 126                                REVISION_ID_CHT_Bx_SI ||
 127                                (dev->pdev->revision & REVISION_ID_SI_MASK) ==
 128                                REVISION_ID_CHT_Kx_SI ||
 129                                (dev->pdev->revision & REVISION_ID_SI_MASK) ==
 130                                REVISION_ID_CHT_Dx_SI) {
 131                        uint32_t host_comm_val;
 132
 133                        host_comm_val = ish_reg_read(dev, IPC_REG_HOST_COMM);
 134                        host_comm_val |= IPC_HOSTCOMM_INT_EN_BIT_CHV_AB | 0x81;
 135                        ish_reg_write(dev, IPC_REG_HOST_COMM, host_comm_val);
 136                }
 137        } else {
 138                        uint32_t host_pimr_val;
 139
 140                        host_pimr_val = ish_reg_read(dev, IPC_REG_PIMR_BXT);
 141                        host_pimr_val |= IPC_PIMR_INT_EN_BIT_BXT;
 142                        /*
 143                         * disable interrupt generated instead of
 144                         * RX_complete_msg
 145                         */
 146                        host_pimr_val &= ~IPC_HOST2ISH_BUSYCLEAR_MASK_BIT;
 147
 148                        ish_reg_write(dev, IPC_REG_PIMR_BXT, host_pimr_val);
 149        }
 150}
 151
 152/**
 153 * ishtp_fw_is_ready() - Check if FW ready
 154 * @dev: ISHTP device pointer
 155 *
 156 * Check if ISH FW is ready
 157 *
 158 * Return: Read true or false
 159 */
 160static bool ishtp_fw_is_ready(struct ishtp_device *dev)
 161{
 162        uint32_t ish_status = _ish_read_fw_sts_reg(dev);
 163
 164        return IPC_IS_ISH_ILUP(ish_status) &&
 165                IPC_IS_ISH_ISHTP_READY(ish_status);
 166}
 167
 168/**
 169 * ish_set_host_rdy() - Indicate host ready
 170 * @dev: ISHTP device pointer
 171 *
 172 * Set host ready indication to FW
 173 */
 174static void ish_set_host_rdy(struct ishtp_device *dev)
 175{
 176        uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);
 177
 178        IPC_SET_HOST_READY(host_status);
 179        ish_reg_write(dev, IPC_REG_HOST_COMM, host_status);
 180}
 181
 182/**
 183 * ish_clr_host_rdy() - Indicate host not ready
 184 * @dev: ISHTP device pointer
 185 *
 186 * Send host not ready indication to FW
 187 */
 188static void ish_clr_host_rdy(struct ishtp_device *dev)
 189{
 190        uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);
 191
 192        IPC_CLEAR_HOST_READY(host_status);
 193        ish_reg_write(dev, IPC_REG_HOST_COMM, host_status);
 194}
 195
 196/**
 197 * _ishtp_read_hdr() - Read message header
 198 * @dev: ISHTP device pointer
 199 *
 200 * Read header of 32bit length
 201 *
 202 * Return: Read register value
 203 */
 204static uint32_t _ishtp_read_hdr(const struct ishtp_device *dev)
 205{
 206        return ish_reg_read(dev, IPC_REG_ISH2HOST_MSG);
 207}
 208
 209/**
 210 * _ishtp_read - Read message
 211 * @dev: ISHTP device pointer
 212 * @buffer: message buffer
 213 * @buffer_length: length of message buffer
 214 *
 215 * Read message from FW
 216 *
 217 * Return: Always 0
 218 */
 219static int _ishtp_read(struct ishtp_device *dev, unsigned char *buffer,
 220        unsigned long buffer_length)
 221{
 222        uint32_t        i;
 223        uint32_t        *r_buf = (uint32_t *)buffer;
 224        uint32_t        msg_offs;
 225
 226        msg_offs = IPC_REG_ISH2HOST_MSG + sizeof(struct ishtp_msg_hdr);
 227        for (i = 0; i < buffer_length; i += sizeof(uint32_t))
 228                *r_buf++ = ish_reg_read(dev, msg_offs + i);
 229
 230        return 0;
 231}
 232
 233/**
 234 * write_ipc_from_queue() - try to write ipc msg from Tx queue to device
 235 * @dev: ishtp device pointer
 236 *
 237 * Check if DRBL is cleared. if it is - write the first IPC msg,  then call
 238 * the callback function (unless it's NULL)
 239 *
 240 * Return: 0 for success else failure code
 241 */
 242static int write_ipc_from_queue(struct ishtp_device *dev)
 243{
 244        struct wr_msg_ctl_info  *ipc_link;
 245        unsigned long   length;
 246        unsigned long   rem;
 247        unsigned long   flags;
 248        uint32_t        doorbell_val;
 249        uint32_t        *r_buf;
 250        uint32_t        reg_addr;
 251        int     i;
 252        void    (*ipc_send_compl)(void *);
 253        void    *ipc_send_compl_prm;
 254
 255        if (dev->dev_state == ISHTP_DEV_DISABLED)
 256                return -EINVAL;
 257
 258        spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
 259        if (!ish_is_input_ready(dev)) {
 260                spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
 261                return -EBUSY;
 262        }
 263
 264        /*
 265         * if tx send list is empty - return 0;
 266         * may happen, as RX_COMPLETE handler doesn't check list emptiness.
 267         */
 268        if (list_empty(&dev->wr_processing_list)) {
 269                spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
 270                return  0;
 271        }
 272
 273        ipc_link = list_first_entry(&dev->wr_processing_list,
 274                                    struct wr_msg_ctl_info, link);
 275        /* first 4 bytes of the data is the doorbell value (IPC header) */
 276        length = ipc_link->length - sizeof(uint32_t);
 277        doorbell_val = *(uint32_t *)ipc_link->inline_data;
 278        r_buf = (uint32_t *)(ipc_link->inline_data + sizeof(uint32_t));
 279
 280        /* If sending MNG_SYNC_FW_CLOCK, update clock again */
 281        if (IPC_HEADER_GET_PROTOCOL(doorbell_val) == IPC_PROTOCOL_MNG &&
 282                IPC_HEADER_GET_MNG_CMD(doorbell_val) == MNG_SYNC_FW_CLOCK) {
 283                uint64_t usec_system, usec_utc;
 284                struct ipc_time_update_msg time_update;
 285                struct time_sync_format ts_format;
 286
 287                usec_system = ktime_to_us(ktime_get_boottime());
 288                usec_utc = ktime_to_us(ktime_get_real());
 289                ts_format.ts1_source = HOST_SYSTEM_TIME_USEC;
 290                ts_format.ts2_source = HOST_UTC_TIME_USEC;
 291                ts_format.reserved = 0;
 292
 293                time_update.primary_host_time = usec_system;
 294                time_update.secondary_host_time = usec_utc;
 295                time_update.sync_info = ts_format;
 296
 297                memcpy(r_buf, &time_update,
 298                       sizeof(struct ipc_time_update_msg));
 299        }
 300
 301        for (i = 0, reg_addr = IPC_REG_HOST2ISH_MSG; i < length >> 2; i++,
 302                        reg_addr += 4)
 303                ish_reg_write(dev, reg_addr, r_buf[i]);
 304
 305        rem = length & 0x3;
 306        if (rem > 0) {
 307                uint32_t reg = 0;
 308
 309                memcpy(&reg, &r_buf[length >> 2], rem);
 310                ish_reg_write(dev, reg_addr, reg);
 311        }
 312        ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, doorbell_val);
 313
 314        /* Flush writes to msg registers and doorbell */
 315        ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
 316
 317        /* Update IPC counters */
 318        ++dev->ipc_tx_cnt;
 319        dev->ipc_tx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);
 320
 321        ipc_send_compl = ipc_link->ipc_send_compl;
 322        ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;
 323        list_del_init(&ipc_link->link);
 324        list_add(&ipc_link->link, &dev->wr_free_list);
 325        spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
 326
 327        /*
 328         * callback will be called out of spinlock,
 329         * after ipc_link returned to free list
 330         */
 331        if (ipc_send_compl)
 332                ipc_send_compl(ipc_send_compl_prm);
 333
 334        return 0;
 335}
 336
 337/**
 338 * write_ipc_to_queue() - write ipc msg to Tx queue
 339 * @dev: ishtp device instance
 340 * @ipc_send_compl: Send complete callback
 341 * @ipc_send_compl_prm: Parameter to send in complete callback
 342 * @msg: Pointer to message
 343 * @length: Length of message
 344 *
 345 * Recived msg with IPC (and upper protocol) header  and add it to the device
 346 *  Tx-to-write list then try to send the first IPC waiting msg
 347 *  (if DRBL is cleared)
 348 * This function returns negative value for failure (means free list
 349 *  is empty, or msg too long) and 0 for success.
 350 *
 351 * Return: 0 for success else failure code
 352 */
 353static int write_ipc_to_queue(struct ishtp_device *dev,
 354        void (*ipc_send_compl)(void *), void *ipc_send_compl_prm,
 355        unsigned char *msg, int length)
 356{
 357        struct wr_msg_ctl_info *ipc_link;
 358        unsigned long flags;
 359
 360        if (length > IPC_FULL_MSG_SIZE)
 361                return -EMSGSIZE;
 362
 363        spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
 364        if (list_empty(&dev->wr_free_list)) {
 365                spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
 366                return -ENOMEM;
 367        }
 368        ipc_link = list_first_entry(&dev->wr_free_list,
 369                                    struct wr_msg_ctl_info, link);
 370        list_del_init(&ipc_link->link);
 371
 372        ipc_link->ipc_send_compl = ipc_send_compl;
 373        ipc_link->ipc_send_compl_prm = ipc_send_compl_prm;
 374        ipc_link->length = length;
 375        memcpy(ipc_link->inline_data, msg, length);
 376
 377        list_add_tail(&ipc_link->link, &dev->wr_processing_list);
 378        spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
 379
 380        write_ipc_from_queue(dev);
 381
 382        return 0;
 383}
 384
 385/**
 386 * ipc_send_mng_msg() - Send management message
 387 * @dev: ishtp device instance
 388 * @msg_code: Message code
 389 * @msg: Pointer to message
 390 * @size: Length of message
 391 *
 392 * Send management message to FW
 393 *
 394 * Return: 0 for success else failure code
 395 */
 396static int ipc_send_mng_msg(struct ishtp_device *dev, uint32_t msg_code,
 397        void *msg, size_t size)
 398{
 399        unsigned char   ipc_msg[IPC_FULL_MSG_SIZE];
 400        uint32_t        drbl_val = IPC_BUILD_MNG_MSG(msg_code, size);
 401
 402        memcpy(ipc_msg, &drbl_val, sizeof(uint32_t));
 403        memcpy(ipc_msg + sizeof(uint32_t), msg, size);
 404        return  write_ipc_to_queue(dev, NULL, NULL, ipc_msg,
 405                sizeof(uint32_t) + size);
 406}
 407
 408#define WAIT_FOR_FW_RDY                 0x1
 409#define WAIT_FOR_INPUT_RDY              0x2
 410
 411/**
 412 * timed_wait_for_timeout() - wait special event with timeout
 413 * @dev: ISHTP device pointer
 414 * @condition: indicate the condition for waiting
 415 * @timeinc: time slice for every wait cycle, in ms
 416 * @timeout: time in ms for timeout
 417 *
 418 * This function will check special event to be ready in a loop, the loop
 419 * period is specificd in timeinc. Wait timeout will causes failure.
 420 *
 421 * Return: 0 for success else failure code
 422 */
 423static int timed_wait_for_timeout(struct ishtp_device *dev, int condition,
 424                                unsigned int timeinc, unsigned int timeout)
 425{
 426        bool complete = false;
 427        int ret;
 428
 429        do {
 430                if (condition == WAIT_FOR_FW_RDY) {
 431                        complete = ishtp_fw_is_ready(dev);
 432                } else if (condition == WAIT_FOR_INPUT_RDY) {
 433                        complete = ish_is_input_ready(dev);
 434                } else {
 435                        ret = -EINVAL;
 436                        goto out;
 437                }
 438
 439                if (!complete) {
 440                        unsigned long left_time;
 441
 442                        left_time = msleep_interruptible(timeinc);
 443                        timeout -= (timeinc - left_time);
 444                }
 445        } while (!complete && timeout > 0);
 446
 447        if (complete)
 448                ret = 0;
 449        else
 450                ret = -EBUSY;
 451
 452out:
 453        return ret;
 454}
 455
 456#define TIME_SLICE_FOR_FW_RDY_MS                100
 457#define TIME_SLICE_FOR_INPUT_RDY_MS             100
 458#define TIMEOUT_FOR_FW_RDY_MS                   2000
 459#define TIMEOUT_FOR_INPUT_RDY_MS                2000
 460
 461/**
 462 * ish_fw_reset_handler() - FW reset handler
 463 * @dev: ishtp device pointer
 464 *
 465 * Handle FW reset
 466 *
 467 * Return: 0 for success else failure code
 468 */
 469static int ish_fw_reset_handler(struct ishtp_device *dev)
 470{
 471        uint32_t        reset_id;
 472        unsigned long   flags;
 473
 474        /* Read reset ID */
 475        reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;
 476
 477        /* Clear IPC output queue */
 478        spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
 479        list_splice_init(&dev->wr_processing_list, &dev->wr_free_list);
 480        spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
 481
 482        /* ISHTP notification in IPC_RESET */
 483        ishtp_reset_handler(dev);
 484
 485        if (!ish_is_input_ready(dev))
 486                timed_wait_for_timeout(dev, WAIT_FOR_INPUT_RDY,
 487                        TIME_SLICE_FOR_INPUT_RDY_MS, TIMEOUT_FOR_INPUT_RDY_MS);
 488
 489        /* ISH FW is dead */
 490        if (!ish_is_input_ready(dev))
 491                return  -EPIPE;
 492        /*
 493         * Set HOST2ISH.ILUP. Apparently we need this BEFORE sending
 494         * RESET_NOTIFY_ACK - FW will be checking for it
 495         */
 496        ish_set_host_rdy(dev);
 497        /* Send RESET_NOTIFY_ACK (with reset_id) */
 498        ipc_send_mng_msg(dev, MNG_RESET_NOTIFY_ACK, &reset_id,
 499                         sizeof(uint32_t));
 500
 501        /* Wait for ISH FW'es ILUP and ISHTP_READY */
 502        timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY,
 503                        TIME_SLICE_FOR_FW_RDY_MS, TIMEOUT_FOR_FW_RDY_MS);
 504        if (!ishtp_fw_is_ready(dev)) {
 505                /* ISH FW is dead */
 506                uint32_t        ish_status;
 507
 508                ish_status = _ish_read_fw_sts_reg(dev);
 509                dev_err(dev->devc,
 510                        "[ishtp-ish]: completed reset, ISH is dead (FWSTS = %08X)\n",
 511                        ish_status);
 512                return -ENODEV;
 513        }
 514        return  0;
 515}
 516
 517#define TIMEOUT_FOR_HW_RDY_MS                   300
 518
 519/**
 520 * ish_fw_reset_work_fn() - FW reset worker function
 521 * @unused: not used
 522 *
 523 * Call ish_fw_reset_handler to complete FW reset
 524 */
 525static void fw_reset_work_fn(struct work_struct *unused)
 526{
 527        int     rv;
 528
 529        rv = ish_fw_reset_handler(ishtp_dev);
 530        if (!rv) {
 531                /* ISH is ILUP & ISHTP-ready. Restart ISHTP */
 532                msleep_interruptible(TIMEOUT_FOR_HW_RDY_MS);
 533                ishtp_dev->recvd_hw_ready = 1;
 534                wake_up_interruptible(&ishtp_dev->wait_hw_ready);
 535
 536                /* ISHTP notification in IPC_RESET sequence completion */
 537                ishtp_reset_compl_handler(ishtp_dev);
 538        } else
 539                dev_err(ishtp_dev->devc, "[ishtp-ish]: FW reset failed (%d)\n",
 540                        rv);
 541}
 542
 543/**
 544 * _ish_sync_fw_clock() -Sync FW clock with the OS clock
 545 * @dev: ishtp device pointer
 546 *
 547 * Sync FW and OS time
 548 */
 549static void _ish_sync_fw_clock(struct ishtp_device *dev)
 550{
 551        static unsigned long    prev_sync;
 552        uint64_t        usec;
 553
 554        if (prev_sync && jiffies - prev_sync < 20 * HZ)
 555                return;
 556
 557        prev_sync = jiffies;
 558        usec = ktime_to_us(ktime_get_boottime());
 559        ipc_send_mng_msg(dev, MNG_SYNC_FW_CLOCK, &usec, sizeof(uint64_t));
 560}
 561
 562/**
 563 * recv_ipc() - Receive and process IPC management messages
 564 * @dev: ishtp device instance
 565 * @doorbell_val: doorbell value
 566 *
 567 * This function runs in ISR context.
 568 * NOTE: Any other mng command than reset_notify and reset_notify_ack
 569 * won't wake BH handler
 570 */
 571static void     recv_ipc(struct ishtp_device *dev, uint32_t doorbell_val)
 572{
 573        uint32_t        mng_cmd;
 574
 575        mng_cmd = IPC_HEADER_GET_MNG_CMD(doorbell_val);
 576
 577        switch (mng_cmd) {
 578        default:
 579                break;
 580
 581        case MNG_RX_CMPL_INDICATION:
 582                if (dev->suspend_flag) {
 583                        dev->suspend_flag = 0;
 584                        wake_up_interruptible(&dev->suspend_wait);
 585                }
 586                if (dev->resume_flag) {
 587                        dev->resume_flag = 0;
 588                        wake_up_interruptible(&dev->resume_wait);
 589                }
 590
 591                write_ipc_from_queue(dev);
 592                break;
 593
 594        case MNG_RESET_NOTIFY:
 595                if (!ishtp_dev) {
 596                        ishtp_dev = dev;
 597                        INIT_WORK(&fw_reset_work, fw_reset_work_fn);
 598                }
 599                schedule_work(&fw_reset_work);
 600                break;
 601
 602        case MNG_RESET_NOTIFY_ACK:
 603                dev->recvd_hw_ready = 1;
 604                wake_up_interruptible(&dev->wait_hw_ready);
 605                break;
 606        }
 607}
 608
 609/**
 610 * ish_irq_handler() - ISH IRQ handler
 611 * @irq: irq number
 612 * @dev_id: ishtp device pointer
 613 *
 614 * ISH IRQ handler. If interrupt is generated and is for ISH it will process
 615 * the interrupt.
 616 */
 617irqreturn_t ish_irq_handler(int irq, void *dev_id)
 618{
 619        struct ishtp_device     *dev = dev_id;
 620        uint32_t        doorbell_val;
 621        bool    interrupt_generated;
 622
 623        /* Check that it's interrupt from ISH (may be shared) */
 624        interrupt_generated = check_generated_interrupt(dev);
 625
 626        if (!interrupt_generated)
 627                return IRQ_NONE;
 628
 629        doorbell_val = ish_reg_read(dev, IPC_REG_ISH2HOST_DRBL);
 630        if (!IPC_IS_BUSY(doorbell_val))
 631                return IRQ_HANDLED;
 632
 633        if (dev->dev_state == ISHTP_DEV_DISABLED)
 634                return  IRQ_HANDLED;
 635
 636        /* Sanity check: IPC dgram length in header */
 637        if (IPC_HEADER_GET_LENGTH(doorbell_val) > IPC_PAYLOAD_SIZE) {
 638                dev_err(dev->devc,
 639                        "IPC hdr - bad length: %u; dropped\n",
 640                        (unsigned int)IPC_HEADER_GET_LENGTH(doorbell_val));
 641                goto    eoi;
 642        }
 643
 644        switch (IPC_HEADER_GET_PROTOCOL(doorbell_val)) {
 645        default:
 646                break;
 647        case IPC_PROTOCOL_MNG:
 648                recv_ipc(dev, doorbell_val);
 649                break;
 650        case IPC_PROTOCOL_ISHTP:
 651                ishtp_recv(dev);
 652                break;
 653        }
 654
 655eoi:
 656        /* Update IPC counters */
 657        ++dev->ipc_rx_cnt;
 658        dev->ipc_rx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);
 659
 660        ish_reg_write(dev, IPC_REG_ISH2HOST_DRBL, 0);
 661        /* Flush write to doorbell */
 662        ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
 663
 664        return  IRQ_HANDLED;
 665}
 666
 667/**
 668 * ish_disable_dma() - disable dma communication between host and ISHFW
 669 * @dev: ishtp device pointer
 670 *
 671 * Clear the dma enable bit and wait for dma inactive.
 672 *
 673 * Return: 0 for success else error code.
 674 */
 675int ish_disable_dma(struct ishtp_device *dev)
 676{
 677        unsigned int    dma_delay;
 678
 679        /* Clear the dma enable bit */
 680        ish_reg_write(dev, IPC_REG_ISH_RMP2, 0);
 681
 682        /* wait for dma inactive */
 683        for (dma_delay = 0; dma_delay < MAX_DMA_DELAY &&
 684                _ish_read_fw_sts_reg(dev) & (IPC_ISH_IN_DMA);
 685                dma_delay += 5)
 686                mdelay(5);
 687
 688        if (dma_delay >= MAX_DMA_DELAY) {
 689                dev_err(dev->devc,
 690                        "Wait for DMA inactive timeout\n");
 691                return  -EBUSY;
 692        }
 693
 694        return 0;
 695}
 696
 697/**
 698 * ish_wakeup() - wakeup ishfw from waiting-for-host state
 699 * @dev: ishtp device pointer
 700 *
 701 * Set the dma enable bit and send a void message to FW,
 702 * it wil wakeup FW from waiting-for-host state.
 703 */
 704static void ish_wakeup(struct ishtp_device *dev)
 705{
 706        /* Set dma enable bit */
 707        ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED);
 708
 709        /*
 710         * Send 0 IPC message so that ISH FW wakes up if it was already
 711         * asleep.
 712         */
 713        ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT);
 714
 715        /* Flush writes to doorbell and REMAP2 */
 716        ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
 717}
 718
 719/**
 720 * _ish_hw_reset() - HW reset
 721 * @dev: ishtp device pointer
 722 *
 723 * Reset ISH HW to recover if any error
 724 *
 725 * Return: 0 for success else error fault code
 726 */
 727static int _ish_hw_reset(struct ishtp_device *dev)
 728{
 729        struct pci_dev *pdev = dev->pdev;
 730        int     rv;
 731        uint16_t csr;
 732
 733        if (!pdev)
 734                return  -ENODEV;
 735
 736        rv = pci_reset_function(pdev);
 737        if (!rv)
 738                dev->dev_state = ISHTP_DEV_RESETTING;
 739
 740        if (!pdev->pm_cap) {
 741                dev_err(&pdev->dev, "Can't reset - no PM caps\n");
 742                return  -EINVAL;
 743        }
 744
 745        /* Disable dma communication between FW and host */
 746        if (ish_disable_dma(dev)) {
 747                dev_err(&pdev->dev,
 748                        "Can't reset - stuck with DMA in-progress\n");
 749                return  -EBUSY;
 750        }
 751
 752        pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &csr);
 753
 754        csr &= ~PCI_PM_CTRL_STATE_MASK;
 755        csr |= PCI_D3hot;
 756        pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
 757
 758        mdelay(pdev->d3_delay);
 759
 760        csr &= ~PCI_PM_CTRL_STATE_MASK;
 761        csr |= PCI_D0;
 762        pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
 763
 764        /* Now we can enable ISH DMA operation and wakeup ISHFW */
 765        ish_wakeup(dev);
 766
 767        return  0;
 768}
 769
 770/**
 771 * _ish_ipc_reset() - IPC reset
 772 * @dev: ishtp device pointer
 773 *
 774 * Resets host and fw IPC and upper layers
 775 *
 776 * Return: 0 for success else error fault code
 777 */
 778static int _ish_ipc_reset(struct ishtp_device *dev)
 779{
 780        struct ipc_rst_payload_type ipc_mng_msg;
 781        int     rv = 0;
 782
 783        ipc_mng_msg.reset_id = 1;
 784        ipc_mng_msg.reserved = 0;
 785
 786        set_host_ready(dev);
 787
 788        /* Clear the incoming doorbell */
 789        ish_reg_write(dev, IPC_REG_ISH2HOST_DRBL, 0);
 790        /* Flush write to doorbell */
 791        ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
 792
 793        dev->recvd_hw_ready = 0;
 794
 795        /* send message */
 796        rv = ipc_send_mng_msg(dev, MNG_RESET_NOTIFY, &ipc_mng_msg,
 797                sizeof(struct ipc_rst_payload_type));
 798        if (rv) {
 799                dev_err(dev->devc, "Failed to send IPC MNG_RESET_NOTIFY\n");
 800                return  rv;
 801        }
 802
 803        wait_event_interruptible_timeout(dev->wait_hw_ready,
 804                                         dev->recvd_hw_ready, 2 * HZ);
 805        if (!dev->recvd_hw_ready) {
 806                dev_err(dev->devc, "Timed out waiting for HW ready\n");
 807                rv = -ENODEV;
 808        }
 809
 810        return rv;
 811}
 812
 813/**
 814 * ish_hw_start() -Start ISH HW
 815 * @dev: ishtp device pointer
 816 *
 817 * Set host to ready state and wait for FW reset
 818 *
 819 * Return: 0 for success else error fault code
 820 */
 821int ish_hw_start(struct ishtp_device *dev)
 822{
 823        ish_set_host_rdy(dev);
 824
 825        set_host_ready(dev);
 826
 827        /* After that we can enable ISH DMA operation and wakeup ISHFW */
 828        ish_wakeup(dev);
 829
 830        /* wait for FW-initiated reset flow */
 831        if (!dev->recvd_hw_ready)
 832                wait_event_interruptible_timeout(dev->wait_hw_ready,
 833                                                 dev->recvd_hw_ready,
 834                                                 10 * HZ);
 835
 836        if (!dev->recvd_hw_ready) {
 837                dev_err(dev->devc,
 838                        "[ishtp-ish]: Timed out waiting for FW-initiated reset\n");
 839                return  -ENODEV;
 840        }
 841
 842        return 0;
 843}
 844
 845/**
 846 * ish_ipc_get_header() -Get doorbell value
 847 * @dev: ishtp device pointer
 848 * @length: length of message
 849 * @busy: busy status
 850 *
 851 * Get door bell value from message header
 852 *
 853 * Return: door bell value
 854 */
 855static uint32_t ish_ipc_get_header(struct ishtp_device *dev, int length,
 856                                   int busy)
 857{
 858        uint32_t drbl_val;
 859
 860        drbl_val = IPC_BUILD_HEADER(length, IPC_PROTOCOL_ISHTP, busy);
 861
 862        return drbl_val;
 863}
 864
 865static const struct ishtp_hw_ops ish_hw_ops = {
 866        .hw_reset = _ish_hw_reset,
 867        .ipc_reset = _ish_ipc_reset,
 868        .ipc_get_header = ish_ipc_get_header,
 869        .ishtp_read = _ishtp_read,
 870        .write = write_ipc_to_queue,
 871        .get_fw_status = _ish_read_fw_sts_reg,
 872        .sync_fw_clock = _ish_sync_fw_clock,
 873        .ishtp_read_hdr = _ishtp_read_hdr
 874};
 875
 876/**
 877 * ish_dev_init() -Initialize ISH devoce
 878 * @pdev: PCI device
 879 *
 880 * Allocate ISHTP device and initialize IPC processing
 881 *
 882 * Return: ISHTP device instance on success else NULL
 883 */
 884struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
 885{
 886        struct ishtp_device *dev;
 887        int     i;
 888
 889        dev = devm_kzalloc(&pdev->dev,
 890                           sizeof(struct ishtp_device) + sizeof(struct ish_hw),
 891                           GFP_KERNEL);
 892        if (!dev)
 893                return NULL;
 894
 895        ishtp_device_init(dev);
 896
 897        init_waitqueue_head(&dev->wait_hw_ready);
 898
 899        spin_lock_init(&dev->wr_processing_spinlock);
 900
 901        /* Init IPC processing and free lists */
 902        INIT_LIST_HEAD(&dev->wr_processing_list);
 903        INIT_LIST_HEAD(&dev->wr_free_list);
 904        for (i = 0; i < IPC_TX_FIFO_SIZE; i++) {
 905                struct wr_msg_ctl_info  *tx_buf;
 906
 907                tx_buf = devm_kzalloc(&pdev->dev,
 908                                      sizeof(struct wr_msg_ctl_info),
 909                                      GFP_KERNEL);
 910                if (!tx_buf) {
 911                        /*
 912                         * IPC buffers may be limited or not available
 913                         * at all - although this shouldn't happen
 914                         */
 915                        dev_err(dev->devc,
 916                                "[ishtp-ish]: failure in Tx FIFO allocations (%d)\n",
 917                                i);
 918                        break;
 919                }
 920                list_add_tail(&tx_buf->link, &dev->wr_free_list);
 921        }
 922
 923        dev->ops = &ish_hw_ops;
 924        dev->devc = &pdev->dev;
 925        dev->mtu = IPC_PAYLOAD_SIZE - sizeof(struct ishtp_msg_hdr);
 926        return dev;
 927}
 928
 929/**
 930 * ish_device_disable() - Disable ISH device
 931 * @dev: ISHTP device pointer
 932 *
 933 * Disable ISH by clearing host ready to inform firmware.
 934 */
 935void    ish_device_disable(struct ishtp_device *dev)
 936{
 937        struct pci_dev *pdev = dev->pdev;
 938
 939        if (!pdev)
 940                return;
 941
 942        /* Disable dma communication between FW and host */
 943        if (ish_disable_dma(dev)) {
 944                dev_err(&pdev->dev,
 945                        "Can't reset - stuck with DMA in-progress\n");
 946                return;
 947        }
 948
 949        /* Put ISH to D3hot state for power saving */
 950        pci_set_power_state(pdev, PCI_D3hot);
 951
 952        dev->dev_state = ISHTP_DEV_DISABLED;
 953        ish_clr_host_rdy(dev);
 954}
 955