cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ipc.c (25022B)


      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
    196static bool ish_chk_host_rdy(struct ishtp_device *dev)
    197{
    198	uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);
    199
    200	return (host_status & IPC_HOSTCOMM_READY_BIT);
    201}
    202
    203/**
    204 * ish_set_host_ready() - reconfig ipc host registers
    205 * @dev: ishtp device pointer
    206 *
    207 * Set host to ready state
    208 * This API is called in some case:
    209 *    fw is still on, but ipc is powered down.
    210 *    such as OOB case.
    211 *
    212 * Return: 0 for success else error fault code
    213 */
    214void ish_set_host_ready(struct ishtp_device *dev)
    215{
    216	if (ish_chk_host_rdy(dev))
    217		return;
    218
    219	ish_set_host_rdy(dev);
    220	set_host_ready(dev);
    221}
    222
    223/**
    224 * _ishtp_read_hdr() - Read message header
    225 * @dev: ISHTP device pointer
    226 *
    227 * Read header of 32bit length
    228 *
    229 * Return: Read register value
    230 */
    231static uint32_t _ishtp_read_hdr(const struct ishtp_device *dev)
    232{
    233	return ish_reg_read(dev, IPC_REG_ISH2HOST_MSG);
    234}
    235
    236/**
    237 * _ishtp_read - Read message
    238 * @dev: ISHTP device pointer
    239 * @buffer: message buffer
    240 * @buffer_length: length of message buffer
    241 *
    242 * Read message from FW
    243 *
    244 * Return: Always 0
    245 */
    246static int _ishtp_read(struct ishtp_device *dev, unsigned char *buffer,
    247	unsigned long buffer_length)
    248{
    249	uint32_t	i;
    250	uint32_t	*r_buf = (uint32_t *)buffer;
    251	uint32_t	msg_offs;
    252
    253	msg_offs = IPC_REG_ISH2HOST_MSG + sizeof(struct ishtp_msg_hdr);
    254	for (i = 0; i < buffer_length; i += sizeof(uint32_t))
    255		*r_buf++ = ish_reg_read(dev, msg_offs + i);
    256
    257	return 0;
    258}
    259
    260/**
    261 * write_ipc_from_queue() - try to write ipc msg from Tx queue to device
    262 * @dev: ishtp device pointer
    263 *
    264 * Check if DRBL is cleared. if it is - write the first IPC msg,  then call
    265 * the callback function (unless it's NULL)
    266 *
    267 * Return: 0 for success else failure code
    268 */
    269static int write_ipc_from_queue(struct ishtp_device *dev)
    270{
    271	struct wr_msg_ctl_info	*ipc_link;
    272	unsigned long	length;
    273	unsigned long	rem;
    274	unsigned long	flags;
    275	uint32_t	doorbell_val;
    276	uint32_t	*r_buf;
    277	uint32_t	reg_addr;
    278	int	i;
    279	void	(*ipc_send_compl)(void *);
    280	void	*ipc_send_compl_prm;
    281
    282	if (dev->dev_state == ISHTP_DEV_DISABLED)
    283		return -EINVAL;
    284
    285	spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
    286	if (!ish_is_input_ready(dev)) {
    287		spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
    288		return -EBUSY;
    289	}
    290
    291	/*
    292	 * if tx send list is empty - return 0;
    293	 * may happen, as RX_COMPLETE handler doesn't check list emptiness.
    294	 */
    295	if (list_empty(&dev->wr_processing_list)) {
    296		spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
    297		return	0;
    298	}
    299
    300	ipc_link = list_first_entry(&dev->wr_processing_list,
    301				    struct wr_msg_ctl_info, link);
    302	/* first 4 bytes of the data is the doorbell value (IPC header) */
    303	length = ipc_link->length - sizeof(uint32_t);
    304	doorbell_val = *(uint32_t *)ipc_link->inline_data;
    305	r_buf = (uint32_t *)(ipc_link->inline_data + sizeof(uint32_t));
    306
    307	/* If sending MNG_SYNC_FW_CLOCK, update clock again */
    308	if (IPC_HEADER_GET_PROTOCOL(doorbell_val) == IPC_PROTOCOL_MNG &&
    309		IPC_HEADER_GET_MNG_CMD(doorbell_val) == MNG_SYNC_FW_CLOCK) {
    310		uint64_t usec_system, usec_utc;
    311		struct ipc_time_update_msg time_update;
    312		struct time_sync_format ts_format;
    313
    314		usec_system = ktime_to_us(ktime_get_boottime());
    315		usec_utc = ktime_to_us(ktime_get_real());
    316		ts_format.ts1_source = HOST_SYSTEM_TIME_USEC;
    317		ts_format.ts2_source = HOST_UTC_TIME_USEC;
    318		ts_format.reserved = 0;
    319
    320		time_update.primary_host_time = usec_system;
    321		time_update.secondary_host_time = usec_utc;
    322		time_update.sync_info = ts_format;
    323
    324		memcpy(r_buf, &time_update,
    325		       sizeof(struct ipc_time_update_msg));
    326	}
    327
    328	for (i = 0, reg_addr = IPC_REG_HOST2ISH_MSG; i < length >> 2; i++,
    329			reg_addr += 4)
    330		ish_reg_write(dev, reg_addr, r_buf[i]);
    331
    332	rem = length & 0x3;
    333	if (rem > 0) {
    334		uint32_t reg = 0;
    335
    336		memcpy(&reg, &r_buf[length >> 2], rem);
    337		ish_reg_write(dev, reg_addr, reg);
    338	}
    339	ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, doorbell_val);
    340
    341	/* Flush writes to msg registers and doorbell */
    342	ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
    343
    344	/* Update IPC counters */
    345	++dev->ipc_tx_cnt;
    346	dev->ipc_tx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);
    347
    348	ipc_send_compl = ipc_link->ipc_send_compl;
    349	ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;
    350	list_del_init(&ipc_link->link);
    351	list_add(&ipc_link->link, &dev->wr_free_list);
    352	spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
    353
    354	/*
    355	 * callback will be called out of spinlock,
    356	 * after ipc_link returned to free list
    357	 */
    358	if (ipc_send_compl)
    359		ipc_send_compl(ipc_send_compl_prm);
    360
    361	return 0;
    362}
    363
    364/**
    365 * write_ipc_to_queue() - write ipc msg to Tx queue
    366 * @dev: ishtp device instance
    367 * @ipc_send_compl: Send complete callback
    368 * @ipc_send_compl_prm:	Parameter to send in complete callback
    369 * @msg: Pointer to message
    370 * @length: Length of message
    371 *
    372 * Recived msg with IPC (and upper protocol) header  and add it to the device
    373 *  Tx-to-write list then try to send the first IPC waiting msg
    374 *  (if DRBL is cleared)
    375 * This function returns negative value for failure (means free list
    376 *  is empty, or msg too long) and 0 for success.
    377 *
    378 * Return: 0 for success else failure code
    379 */
    380static int write_ipc_to_queue(struct ishtp_device *dev,
    381	void (*ipc_send_compl)(void *), void *ipc_send_compl_prm,
    382	unsigned char *msg, int length)
    383{
    384	struct wr_msg_ctl_info *ipc_link;
    385	unsigned long flags;
    386
    387	if (length > IPC_FULL_MSG_SIZE)
    388		return -EMSGSIZE;
    389
    390	spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
    391	if (list_empty(&dev->wr_free_list)) {
    392		spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
    393		return -ENOMEM;
    394	}
    395	ipc_link = list_first_entry(&dev->wr_free_list,
    396				    struct wr_msg_ctl_info, link);
    397	list_del_init(&ipc_link->link);
    398
    399	ipc_link->ipc_send_compl = ipc_send_compl;
    400	ipc_link->ipc_send_compl_prm = ipc_send_compl_prm;
    401	ipc_link->length = length;
    402	memcpy(ipc_link->inline_data, msg, length);
    403
    404	list_add_tail(&ipc_link->link, &dev->wr_processing_list);
    405	spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
    406
    407	write_ipc_from_queue(dev);
    408
    409	return 0;
    410}
    411
    412/**
    413 * ipc_send_mng_msg() - Send management message
    414 * @dev: ishtp device instance
    415 * @msg_code: Message code
    416 * @msg: Pointer to message
    417 * @size: Length of message
    418 *
    419 * Send management message to FW
    420 *
    421 * Return: 0 for success else failure code
    422 */
    423static int ipc_send_mng_msg(struct ishtp_device *dev, uint32_t msg_code,
    424	void *msg, size_t size)
    425{
    426	unsigned char	ipc_msg[IPC_FULL_MSG_SIZE];
    427	uint32_t	drbl_val = IPC_BUILD_MNG_MSG(msg_code, size);
    428
    429	memcpy(ipc_msg, &drbl_val, sizeof(uint32_t));
    430	memcpy(ipc_msg + sizeof(uint32_t), msg, size);
    431	return	write_ipc_to_queue(dev, NULL, NULL, ipc_msg,
    432		sizeof(uint32_t) + size);
    433}
    434
    435#define WAIT_FOR_FW_RDY			0x1
    436#define WAIT_FOR_INPUT_RDY		0x2
    437
    438/**
    439 * timed_wait_for_timeout() - wait special event with timeout
    440 * @dev: ISHTP device pointer
    441 * @condition: indicate the condition for waiting
    442 * @timeinc: time slice for every wait cycle, in ms
    443 * @timeout: time in ms for timeout
    444 *
    445 * This function will check special event to be ready in a loop, the loop
    446 * period is specificd in timeinc. Wait timeout will causes failure.
    447 *
    448 * Return: 0 for success else failure code
    449 */
    450static int timed_wait_for_timeout(struct ishtp_device *dev, int condition,
    451				unsigned int timeinc, unsigned int timeout)
    452{
    453	bool complete = false;
    454	int ret;
    455
    456	do {
    457		if (condition == WAIT_FOR_FW_RDY) {
    458			complete = ishtp_fw_is_ready(dev);
    459		} else if (condition == WAIT_FOR_INPUT_RDY) {
    460			complete = ish_is_input_ready(dev);
    461		} else {
    462			ret = -EINVAL;
    463			goto out;
    464		}
    465
    466		if (!complete) {
    467			unsigned long left_time;
    468
    469			left_time = msleep_interruptible(timeinc);
    470			timeout -= (timeinc - left_time);
    471		}
    472	} while (!complete && timeout > 0);
    473
    474	if (complete)
    475		ret = 0;
    476	else
    477		ret = -EBUSY;
    478
    479out:
    480	return ret;
    481}
    482
    483#define TIME_SLICE_FOR_FW_RDY_MS		100
    484#define TIME_SLICE_FOR_INPUT_RDY_MS		100
    485#define TIMEOUT_FOR_FW_RDY_MS			2000
    486#define TIMEOUT_FOR_INPUT_RDY_MS		2000
    487
    488/**
    489 * ish_fw_reset_handler() - FW reset handler
    490 * @dev: ishtp device pointer
    491 *
    492 * Handle FW reset
    493 *
    494 * Return: 0 for success else failure code
    495 */
    496static int ish_fw_reset_handler(struct ishtp_device *dev)
    497{
    498	uint32_t	reset_id;
    499	unsigned long	flags;
    500
    501	/* Read reset ID */
    502	reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;
    503
    504	/* Clear IPC output queue */
    505	spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
    506	list_splice_init(&dev->wr_processing_list, &dev->wr_free_list);
    507	spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
    508
    509	/* ISHTP notification in IPC_RESET */
    510	ishtp_reset_handler(dev);
    511
    512	if (!ish_is_input_ready(dev))
    513		timed_wait_for_timeout(dev, WAIT_FOR_INPUT_RDY,
    514			TIME_SLICE_FOR_INPUT_RDY_MS, TIMEOUT_FOR_INPUT_RDY_MS);
    515
    516	/* ISH FW is dead */
    517	if (!ish_is_input_ready(dev))
    518		return	-EPIPE;
    519	/*
    520	 * Set HOST2ISH.ILUP. Apparently we need this BEFORE sending
    521	 * RESET_NOTIFY_ACK - FW will be checking for it
    522	 */
    523	ish_set_host_rdy(dev);
    524	/* Send RESET_NOTIFY_ACK (with reset_id) */
    525	ipc_send_mng_msg(dev, MNG_RESET_NOTIFY_ACK, &reset_id,
    526			 sizeof(uint32_t));
    527
    528	/* Wait for ISH FW'es ILUP and ISHTP_READY */
    529	timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY,
    530			TIME_SLICE_FOR_FW_RDY_MS, TIMEOUT_FOR_FW_RDY_MS);
    531	if (!ishtp_fw_is_ready(dev)) {
    532		/* ISH FW is dead */
    533		uint32_t	ish_status;
    534
    535		ish_status = _ish_read_fw_sts_reg(dev);
    536		dev_err(dev->devc,
    537			"[ishtp-ish]: completed reset, ISH is dead (FWSTS = %08X)\n",
    538			ish_status);
    539		return -ENODEV;
    540	}
    541	return	0;
    542}
    543
    544#define TIMEOUT_FOR_HW_RDY_MS			300
    545
    546/**
    547 * fw_reset_work_fn() - FW reset worker function
    548 * @unused: not used
    549 *
    550 * Call ish_fw_reset_handler to complete FW reset
    551 */
    552static void fw_reset_work_fn(struct work_struct *unused)
    553{
    554	int	rv;
    555
    556	rv = ish_fw_reset_handler(ishtp_dev);
    557	if (!rv) {
    558		/* ISH is ILUP & ISHTP-ready. Restart ISHTP */
    559		msleep_interruptible(TIMEOUT_FOR_HW_RDY_MS);
    560		ishtp_dev->recvd_hw_ready = 1;
    561		wake_up_interruptible(&ishtp_dev->wait_hw_ready);
    562
    563		/* ISHTP notification in IPC_RESET sequence completion */
    564		ishtp_reset_compl_handler(ishtp_dev);
    565	} else
    566		dev_err(ishtp_dev->devc, "[ishtp-ish]: FW reset failed (%d)\n",
    567			rv);
    568}
    569
    570/**
    571 * _ish_sync_fw_clock() -Sync FW clock with the OS clock
    572 * @dev: ishtp device pointer
    573 *
    574 * Sync FW and OS time
    575 */
    576static void _ish_sync_fw_clock(struct ishtp_device *dev)
    577{
    578	static unsigned long	prev_sync;
    579	uint64_t	usec;
    580
    581	if (prev_sync && jiffies - prev_sync < 20 * HZ)
    582		return;
    583
    584	prev_sync = jiffies;
    585	usec = ktime_to_us(ktime_get_boottime());
    586	ipc_send_mng_msg(dev, MNG_SYNC_FW_CLOCK, &usec, sizeof(uint64_t));
    587}
    588
    589/**
    590 * recv_ipc() - Receive and process IPC management messages
    591 * @dev: ishtp device instance
    592 * @doorbell_val: doorbell value
    593 *
    594 * This function runs in ISR context.
    595 * NOTE: Any other mng command than reset_notify and reset_notify_ack
    596 * won't wake BH handler
    597 */
    598static void	recv_ipc(struct ishtp_device *dev, uint32_t doorbell_val)
    599{
    600	uint32_t	mng_cmd;
    601
    602	mng_cmd = IPC_HEADER_GET_MNG_CMD(doorbell_val);
    603
    604	switch (mng_cmd) {
    605	default:
    606		break;
    607
    608	case MNG_RX_CMPL_INDICATION:
    609		if (dev->suspend_flag) {
    610			dev->suspend_flag = 0;
    611			wake_up_interruptible(&dev->suspend_wait);
    612		}
    613		if (dev->resume_flag) {
    614			dev->resume_flag = 0;
    615			wake_up_interruptible(&dev->resume_wait);
    616		}
    617
    618		write_ipc_from_queue(dev);
    619		break;
    620
    621	case MNG_RESET_NOTIFY:
    622		if (!ishtp_dev) {
    623			ishtp_dev = dev;
    624			INIT_WORK(&fw_reset_work, fw_reset_work_fn);
    625		}
    626		schedule_work(&fw_reset_work);
    627		break;
    628
    629	case MNG_RESET_NOTIFY_ACK:
    630		dev->recvd_hw_ready = 1;
    631		wake_up_interruptible(&dev->wait_hw_ready);
    632		break;
    633	}
    634}
    635
    636/**
    637 * ish_irq_handler() - ISH IRQ handler
    638 * @irq: irq number
    639 * @dev_id: ishtp device pointer
    640 *
    641 * ISH IRQ handler. If interrupt is generated and is for ISH it will process
    642 * the interrupt.
    643 */
    644irqreturn_t ish_irq_handler(int irq, void *dev_id)
    645{
    646	struct ishtp_device	*dev = dev_id;
    647	uint32_t	doorbell_val;
    648	bool	interrupt_generated;
    649
    650	/* Check that it's interrupt from ISH (may be shared) */
    651	interrupt_generated = check_generated_interrupt(dev);
    652
    653	if (!interrupt_generated)
    654		return IRQ_NONE;
    655
    656	doorbell_val = ish_reg_read(dev, IPC_REG_ISH2HOST_DRBL);
    657	if (!IPC_IS_BUSY(doorbell_val))
    658		return IRQ_HANDLED;
    659
    660	if (dev->dev_state == ISHTP_DEV_DISABLED)
    661		return	IRQ_HANDLED;
    662
    663	/* Sanity check: IPC dgram length in header */
    664	if (IPC_HEADER_GET_LENGTH(doorbell_val) > IPC_PAYLOAD_SIZE) {
    665		dev_err(dev->devc,
    666			"IPC hdr - bad length: %u; dropped\n",
    667			(unsigned int)IPC_HEADER_GET_LENGTH(doorbell_val));
    668		goto	eoi;
    669	}
    670
    671	switch (IPC_HEADER_GET_PROTOCOL(doorbell_val)) {
    672	default:
    673		break;
    674	case IPC_PROTOCOL_MNG:
    675		recv_ipc(dev, doorbell_val);
    676		break;
    677	case IPC_PROTOCOL_ISHTP:
    678		ishtp_recv(dev);
    679		break;
    680	}
    681
    682eoi:
    683	/* Update IPC counters */
    684	++dev->ipc_rx_cnt;
    685	dev->ipc_rx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);
    686
    687	ish_reg_write(dev, IPC_REG_ISH2HOST_DRBL, 0);
    688	/* Flush write to doorbell */
    689	ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
    690
    691	return	IRQ_HANDLED;
    692}
    693
    694/**
    695 * ish_disable_dma() - disable dma communication between host and ISHFW
    696 * @dev: ishtp device pointer
    697 *
    698 * Clear the dma enable bit and wait for dma inactive.
    699 *
    700 * Return: 0 for success else error code.
    701 */
    702int ish_disable_dma(struct ishtp_device *dev)
    703{
    704	unsigned int	dma_delay;
    705
    706	/* Clear the dma enable bit */
    707	ish_reg_write(dev, IPC_REG_ISH_RMP2, 0);
    708
    709	/* wait for dma inactive */
    710	for (dma_delay = 0; dma_delay < MAX_DMA_DELAY &&
    711		_ish_read_fw_sts_reg(dev) & (IPC_ISH_IN_DMA);
    712		dma_delay += 5)
    713		mdelay(5);
    714
    715	if (dma_delay >= MAX_DMA_DELAY) {
    716		dev_err(dev->devc,
    717			"Wait for DMA inactive timeout\n");
    718		return	-EBUSY;
    719	}
    720
    721	return 0;
    722}
    723
    724/**
    725 * ish_wakeup() - wakeup ishfw from waiting-for-host state
    726 * @dev: ishtp device pointer
    727 *
    728 * Set the dma enable bit and send a void message to FW,
    729 * it wil wakeup FW from waiting-for-host state.
    730 */
    731static void ish_wakeup(struct ishtp_device *dev)
    732{
    733	/* Set dma enable bit */
    734	ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED);
    735
    736	/*
    737	 * Send 0 IPC message so that ISH FW wakes up if it was already
    738	 * asleep.
    739	 */
    740	ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT);
    741
    742	/* Flush writes to doorbell and REMAP2 */
    743	ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
    744}
    745
    746/**
    747 * _ish_hw_reset() - HW reset
    748 * @dev: ishtp device pointer
    749 *
    750 * Reset ISH HW to recover if any error
    751 *
    752 * Return: 0 for success else error fault code
    753 */
    754static int _ish_hw_reset(struct ishtp_device *dev)
    755{
    756	struct pci_dev *pdev = dev->pdev;
    757	int	rv;
    758	uint16_t csr;
    759
    760	if (!pdev)
    761		return	-ENODEV;
    762
    763	rv = pci_reset_function(pdev);
    764	if (!rv)
    765		dev->dev_state = ISHTP_DEV_RESETTING;
    766
    767	if (!pdev->pm_cap) {
    768		dev_err(&pdev->dev, "Can't reset - no PM caps\n");
    769		return	-EINVAL;
    770	}
    771
    772	/* Disable dma communication between FW and host */
    773	if (ish_disable_dma(dev)) {
    774		dev_err(&pdev->dev,
    775			"Can't reset - stuck with DMA in-progress\n");
    776		return	-EBUSY;
    777	}
    778
    779	pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &csr);
    780
    781	csr &= ~PCI_PM_CTRL_STATE_MASK;
    782	csr |= PCI_D3hot;
    783	pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
    784
    785	mdelay(pdev->d3hot_delay);
    786
    787	csr &= ~PCI_PM_CTRL_STATE_MASK;
    788	csr |= PCI_D0;
    789	pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
    790
    791	/* Now we can enable ISH DMA operation and wakeup ISHFW */
    792	ish_wakeup(dev);
    793
    794	return	0;
    795}
    796
    797/**
    798 * _ish_ipc_reset() - IPC reset
    799 * @dev: ishtp device pointer
    800 *
    801 * Resets host and fw IPC and upper layers
    802 *
    803 * Return: 0 for success else error fault code
    804 */
    805static int _ish_ipc_reset(struct ishtp_device *dev)
    806{
    807	struct ipc_rst_payload_type ipc_mng_msg;
    808	int	rv = 0;
    809
    810	ipc_mng_msg.reset_id = 1;
    811	ipc_mng_msg.reserved = 0;
    812
    813	set_host_ready(dev);
    814
    815	/* Clear the incoming doorbell */
    816	ish_reg_write(dev, IPC_REG_ISH2HOST_DRBL, 0);
    817	/* Flush write to doorbell */
    818	ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
    819
    820	dev->recvd_hw_ready = 0;
    821
    822	/* send message */
    823	rv = ipc_send_mng_msg(dev, MNG_RESET_NOTIFY, &ipc_mng_msg,
    824		sizeof(struct ipc_rst_payload_type));
    825	if (rv) {
    826		dev_err(dev->devc, "Failed to send IPC MNG_RESET_NOTIFY\n");
    827		return	rv;
    828	}
    829
    830	wait_event_interruptible_timeout(dev->wait_hw_ready,
    831					 dev->recvd_hw_ready, 2 * HZ);
    832	if (!dev->recvd_hw_ready) {
    833		dev_err(dev->devc, "Timed out waiting for HW ready\n");
    834		rv = -ENODEV;
    835	}
    836
    837	return rv;
    838}
    839
    840/**
    841 * ish_hw_start() -Start ISH HW
    842 * @dev: ishtp device pointer
    843 *
    844 * Set host to ready state and wait for FW reset
    845 *
    846 * Return: 0 for success else error fault code
    847 */
    848int ish_hw_start(struct ishtp_device *dev)
    849{
    850	ish_set_host_rdy(dev);
    851
    852	set_host_ready(dev);
    853
    854	/* After that we can enable ISH DMA operation and wakeup ISHFW */
    855	ish_wakeup(dev);
    856
    857	/* wait for FW-initiated reset flow */
    858	if (!dev->recvd_hw_ready)
    859		wait_event_interruptible_timeout(dev->wait_hw_ready,
    860						 dev->recvd_hw_ready,
    861						 10 * HZ);
    862
    863	if (!dev->recvd_hw_ready) {
    864		dev_err(dev->devc,
    865			"[ishtp-ish]: Timed out waiting for FW-initiated reset\n");
    866		return	-ENODEV;
    867	}
    868
    869	return 0;
    870}
    871
    872/**
    873 * ish_ipc_get_header() -Get doorbell value
    874 * @dev: ishtp device pointer
    875 * @length: length of message
    876 * @busy: busy status
    877 *
    878 * Get door bell value from message header
    879 *
    880 * Return: door bell value
    881 */
    882static uint32_t ish_ipc_get_header(struct ishtp_device *dev, int length,
    883				   int busy)
    884{
    885	uint32_t drbl_val;
    886
    887	drbl_val = IPC_BUILD_HEADER(length, IPC_PROTOCOL_ISHTP, busy);
    888
    889	return drbl_val;
    890}
    891
    892/**
    893 * _dma_no_cache_snooping()
    894 *
    895 * Check on current platform, DMA supports cache snooping or not.
    896 * This callback is used to notify uplayer driver if manully cache
    897 * flush is needed when do DMA operation.
    898 *
    899 * Please pay attention to this callback implementation, if declare
    900 * having cache snooping on a cache snooping not supported platform
    901 * will cause uplayer driver receiving mismatched data; and if
    902 * declare no cache snooping on a cache snooping supported platform
    903 * will cause cache be flushed twice and performance hit.
    904 *
    905 * @dev: ishtp device pointer
    906 *
    907 * Return: false - has cache snooping capability
    908 *         true - no cache snooping, need manually cache flush
    909 */
    910static bool _dma_no_cache_snooping(struct ishtp_device *dev)
    911{
    912	return (dev->pdev->device == EHL_Ax_DEVICE_ID ||
    913		dev->pdev->device == TGL_LP_DEVICE_ID ||
    914		dev->pdev->device == TGL_H_DEVICE_ID ||
    915		dev->pdev->device == ADL_S_DEVICE_ID ||
    916		dev->pdev->device == ADL_P_DEVICE_ID);
    917}
    918
    919static const struct ishtp_hw_ops ish_hw_ops = {
    920	.hw_reset = _ish_hw_reset,
    921	.ipc_reset = _ish_ipc_reset,
    922	.ipc_get_header = ish_ipc_get_header,
    923	.ishtp_read = _ishtp_read,
    924	.write = write_ipc_to_queue,
    925	.get_fw_status = _ish_read_fw_sts_reg,
    926	.sync_fw_clock = _ish_sync_fw_clock,
    927	.ishtp_read_hdr = _ishtp_read_hdr,
    928	.dma_no_cache_snooping = _dma_no_cache_snooping
    929};
    930
    931/**
    932 * ish_dev_init() -Initialize ISH devoce
    933 * @pdev: PCI device
    934 *
    935 * Allocate ISHTP device and initialize IPC processing
    936 *
    937 * Return: ISHTP device instance on success else NULL
    938 */
    939struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
    940{
    941	struct ishtp_device *dev;
    942	int	i;
    943
    944	dev = devm_kzalloc(&pdev->dev,
    945			   sizeof(struct ishtp_device) + sizeof(struct ish_hw),
    946			   GFP_KERNEL);
    947	if (!dev)
    948		return NULL;
    949
    950	ishtp_device_init(dev);
    951
    952	init_waitqueue_head(&dev->wait_hw_ready);
    953
    954	spin_lock_init(&dev->wr_processing_spinlock);
    955
    956	/* Init IPC processing and free lists */
    957	INIT_LIST_HEAD(&dev->wr_processing_list);
    958	INIT_LIST_HEAD(&dev->wr_free_list);
    959	for (i = 0; i < IPC_TX_FIFO_SIZE; i++) {
    960		struct wr_msg_ctl_info	*tx_buf;
    961
    962		tx_buf = devm_kzalloc(&pdev->dev,
    963				      sizeof(struct wr_msg_ctl_info),
    964				      GFP_KERNEL);
    965		if (!tx_buf) {
    966			/*
    967			 * IPC buffers may be limited or not available
    968			 * at all - although this shouldn't happen
    969			 */
    970			dev_err(dev->devc,
    971				"[ishtp-ish]: failure in Tx FIFO allocations (%d)\n",
    972				i);
    973			break;
    974		}
    975		list_add_tail(&tx_buf->link, &dev->wr_free_list);
    976	}
    977
    978	dev->ops = &ish_hw_ops;
    979	dev->devc = &pdev->dev;
    980	dev->mtu = IPC_PAYLOAD_SIZE - sizeof(struct ishtp_msg_hdr);
    981	return dev;
    982}
    983
    984/**
    985 * ish_device_disable() - Disable ISH device
    986 * @dev: ISHTP device pointer
    987 *
    988 * Disable ISH by clearing host ready to inform firmware.
    989 */
    990void	ish_device_disable(struct ishtp_device *dev)
    991{
    992	struct pci_dev *pdev = dev->pdev;
    993
    994	if (!pdev)
    995		return;
    996
    997	/* Disable dma communication between FW and host */
    998	if (ish_disable_dma(dev)) {
    999		dev_err(&pdev->dev,
   1000			"Can't reset - stuck with DMA in-progress\n");
   1001		return;
   1002	}
   1003
   1004	/* Put ISH to D3hot state for power saving */
   1005	pci_set_power_state(pdev, PCI_D3hot);
   1006
   1007	dev->dev_state = ISHTP_DEV_DISABLED;
   1008	ish_clr_host_rdy(dev);
   1009}