brintos

brintos / linux-shallow public Read only

0
0
Text · 24.7 KiB · 3cd53fc Raw
1018 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * H/W layer of ISHTP provider device (ISH)4 *5 * Copyright (c) 2014-2016, Intel Corporation.6 */7 8#include <linux/devm-helpers.h>9#include <linux/sched.h>10#include <linux/spinlock.h>11#include <linux/delay.h>12#include <linux/jiffies.h>13#include "client.h"14#include "hw-ish.h"15#include "hbm.h"16 17/* For FW reset flow */18static struct work_struct fw_reset_work;19static struct ishtp_device *ishtp_dev;20 21/**22 * ish_reg_read() - Read register23 * @dev: ISHTP device pointer24 * @offset: Register offset25 *26 * Read 32 bit register at a given offset27 *28 * Return: Read register value29 */30static inline uint32_t ish_reg_read(const struct ishtp_device *dev,31	unsigned long offset)32{33	struct ish_hw *hw = to_ish_hw(dev);34 35	return readl(hw->mem_addr + offset);36}37 38/**39 * ish_reg_write() - Write register40 * @dev: ISHTP device pointer41 * @offset: Register offset42 * @value: Value to write43 *44 * Writes 32 bit register at a give offset45 */46static inline void ish_reg_write(struct ishtp_device *dev,47				 unsigned long offset,48				 uint32_t value)49{50	struct ish_hw *hw = to_ish_hw(dev);51 52	writel(value, hw->mem_addr + offset);53}54 55/**56 * _ish_read_fw_sts_reg() - Read FW status register57 * @dev: ISHTP device pointer58 *59 * Read FW status register60 *61 * Return: Read register value62 */63static inline uint32_t _ish_read_fw_sts_reg(struct ishtp_device *dev)64{65	return ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);66}67 68/**69 * check_generated_interrupt() - Check if ISH interrupt70 * @dev: ISHTP device pointer71 *72 * Check if an interrupt was generated for ISH73 *74 * Return: Read true or false75 */76static bool check_generated_interrupt(struct ishtp_device *dev)77{78	bool interrupt_generated = true;79	uint32_t pisr_val = 0;80 81	if (dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV) {82		pisr_val = ish_reg_read(dev, IPC_REG_PISR_CHV_AB);83		interrupt_generated =84			IPC_INT_FROM_ISH_TO_HOST_CHV_AB(pisr_val);85	} else {86		pisr_val = ish_reg_read(dev, IPC_REG_PISR_BXT);87		interrupt_generated = !!pisr_val;88		/* only busy-clear bit is RW, others are RO */89		if (pisr_val)90			ish_reg_write(dev, IPC_REG_PISR_BXT, pisr_val);91	}92 93	return interrupt_generated;94}95 96/**97 * ish_is_input_ready() - Check if FW ready for RX98 * @dev: ISHTP device pointer99 *100 * Check if ISH FW is ready for receiving data101 *102 * Return: Read true or false103 */104static bool ish_is_input_ready(struct ishtp_device *dev)105{106	uint32_t doorbell_val;107 108	doorbell_val = ish_reg_read(dev, IPC_REG_HOST2ISH_DRBL);109	return !IPC_IS_BUSY(doorbell_val);110}111 112/**113 * set_host_ready() - Indicate host ready114 * @dev: ISHTP device pointer115 *116 * Set host ready indication to FW117 */118static void set_host_ready(struct ishtp_device *dev)119{120	if (dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV) {121		if (dev->pdev->revision == REVISION_ID_CHT_A0 ||122				(dev->pdev->revision & REVISION_ID_SI_MASK) ==123				REVISION_ID_CHT_Ax_SI)124			ish_reg_write(dev, IPC_REG_HOST_COMM, 0x81);125		else if (dev->pdev->revision == REVISION_ID_CHT_B0 ||126				(dev->pdev->revision & REVISION_ID_SI_MASK) ==127				REVISION_ID_CHT_Bx_SI ||128				(dev->pdev->revision & REVISION_ID_SI_MASK) ==129				REVISION_ID_CHT_Kx_SI ||130				(dev->pdev->revision & REVISION_ID_SI_MASK) ==131				REVISION_ID_CHT_Dx_SI) {132			uint32_t host_comm_val;133 134			host_comm_val = ish_reg_read(dev, IPC_REG_HOST_COMM);135			host_comm_val |= IPC_HOSTCOMM_INT_EN_BIT_CHV_AB | 0x81;136			ish_reg_write(dev, IPC_REG_HOST_COMM, host_comm_val);137		}138	} else {139			uint32_t host_pimr_val;140 141			host_pimr_val = ish_reg_read(dev, IPC_REG_PIMR_BXT);142			host_pimr_val |= IPC_PIMR_INT_EN_BIT_BXT;143			/*144			 * disable interrupt generated instead of145			 * RX_complete_msg146			 */147			host_pimr_val &= ~IPC_HOST2ISH_BUSYCLEAR_MASK_BIT;148 149			ish_reg_write(dev, IPC_REG_PIMR_BXT, host_pimr_val);150	}151}152 153/**154 * ishtp_fw_is_ready() - Check if FW ready155 * @dev: ISHTP device pointer156 *157 * Check if ISH FW is ready158 *159 * Return: Read true or false160 */161static bool ishtp_fw_is_ready(struct ishtp_device *dev)162{163	uint32_t ish_status = _ish_read_fw_sts_reg(dev);164 165	return IPC_IS_ISH_ILUP(ish_status) &&166		IPC_IS_ISH_ISHTP_READY(ish_status);167}168 169/**170 * ish_set_host_rdy() - Indicate host ready171 * @dev: ISHTP device pointer172 *173 * Set host ready indication to FW174 */175static void ish_set_host_rdy(struct ishtp_device *dev)176{177	uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);178 179	IPC_SET_HOST_READY(host_status);180	ish_reg_write(dev, IPC_REG_HOST_COMM, host_status);181}182 183/**184 * ish_clr_host_rdy() - Indicate host not ready185 * @dev: ISHTP device pointer186 *187 * Send host not ready indication to FW188 */189static void ish_clr_host_rdy(struct ishtp_device *dev)190{191	uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);192 193	IPC_CLEAR_HOST_READY(host_status);194	ish_reg_write(dev, IPC_REG_HOST_COMM, host_status);195}196 197static bool ish_chk_host_rdy(struct ishtp_device *dev)198{199	uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);200 201	return (host_status & IPC_HOSTCOMM_READY_BIT);202}203 204/**205 * ish_set_host_ready() - reconfig ipc host registers206 * @dev: ishtp device pointer207 *208 * Set host to ready state209 * This API is called in some case:210 *    fw is still on, but ipc is powered down.211 *    such as OOB case.212 *213 * Return: 0 for success else error fault code214 */215void ish_set_host_ready(struct ishtp_device *dev)216{217	if (ish_chk_host_rdy(dev))218		return;219 220	ish_set_host_rdy(dev);221	set_host_ready(dev);222}223 224/**225 * _ishtp_read_hdr() - Read message header226 * @dev: ISHTP device pointer227 *228 * Read header of 32bit length229 *230 * Return: Read register value231 */232static uint32_t _ishtp_read_hdr(const struct ishtp_device *dev)233{234	return ish_reg_read(dev, IPC_REG_ISH2HOST_MSG);235}236 237/**238 * _ishtp_read - Read message239 * @dev: ISHTP device pointer240 * @buffer: message buffer241 * @buffer_length: length of message buffer242 *243 * Read message from FW244 *245 * Return: Always 0246 */247static int _ishtp_read(struct ishtp_device *dev, unsigned char *buffer,248	unsigned long buffer_length)249{250	uint32_t	i;251	uint32_t	*r_buf = (uint32_t *)buffer;252	uint32_t	msg_offs;253 254	msg_offs = IPC_REG_ISH2HOST_MSG + sizeof(struct ishtp_msg_hdr);255	for (i = 0; i < buffer_length; i += sizeof(uint32_t))256		*r_buf++ = ish_reg_read(dev, msg_offs + i);257 258	return 0;259}260 261/**262 * write_ipc_from_queue() - try to write ipc msg from Tx queue to device263 * @dev: ishtp device pointer264 *265 * Check if DRBL is cleared. if it is - write the first IPC msg,  then call266 * the callback function (unless it's NULL)267 *268 * Return: 0 for success else failure code269 */270static int write_ipc_from_queue(struct ishtp_device *dev)271{272	struct wr_msg_ctl_info	*ipc_link;273	unsigned long	length;274	unsigned long	rem;275	unsigned long	flags;276	uint32_t	doorbell_val;277	uint32_t	*r_buf;278	uint32_t	reg_addr;279	int	i;280	void	(*ipc_send_compl)(void *);281	void	*ipc_send_compl_prm;282 283	if (dev->dev_state == ISHTP_DEV_DISABLED)284		return -EINVAL;285 286	spin_lock_irqsave(&dev->wr_processing_spinlock, flags);287	if (!ish_is_input_ready(dev)) {288		spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);289		return -EBUSY;290	}291 292	/*293	 * if tx send list is empty - return 0;294	 * may happen, as RX_COMPLETE handler doesn't check list emptiness.295	 */296	if (list_empty(&dev->wr_processing_list)) {297		spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);298		return	0;299	}300 301	ipc_link = list_first_entry(&dev->wr_processing_list,302				    struct wr_msg_ctl_info, link);303	/* first 4 bytes of the data is the doorbell value (IPC header) */304	length = ipc_link->length - sizeof(uint32_t);305	doorbell_val = *(uint32_t *)ipc_link->inline_data;306	r_buf = (uint32_t *)(ipc_link->inline_data + sizeof(uint32_t));307 308	/* If sending MNG_SYNC_FW_CLOCK, update clock again */309	if (IPC_HEADER_GET_PROTOCOL(doorbell_val) == IPC_PROTOCOL_MNG &&310		IPC_HEADER_GET_MNG_CMD(doorbell_val) == MNG_SYNC_FW_CLOCK) {311		uint64_t usec_system, usec_utc;312		struct ipc_time_update_msg time_update;313		struct time_sync_format ts_format;314 315		usec_system = ktime_to_us(ktime_get_boottime());316		usec_utc = ktime_to_us(ktime_get_real());317		ts_format.ts1_source = HOST_SYSTEM_TIME_USEC;318		ts_format.ts2_source = HOST_UTC_TIME_USEC;319		ts_format.reserved = 0;320 321		time_update.primary_host_time = usec_system;322		time_update.secondary_host_time = usec_utc;323		time_update.sync_info = ts_format;324 325		memcpy(r_buf, &time_update,326		       sizeof(struct ipc_time_update_msg));327	}328 329	for (i = 0, reg_addr = IPC_REG_HOST2ISH_MSG; i < length >> 2; i++,330			reg_addr += 4)331		ish_reg_write(dev, reg_addr, r_buf[i]);332 333	rem = length & 0x3;334	if (rem > 0) {335		uint32_t reg = 0;336 337		memcpy(&reg, &r_buf[length >> 2], rem);338		ish_reg_write(dev, reg_addr, reg);339	}340	ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, doorbell_val);341 342	/* Flush writes to msg registers and doorbell */343	ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);344 345	/* Update IPC counters */346	++dev->ipc_tx_cnt;347	dev->ipc_tx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);348 349	ipc_send_compl = ipc_link->ipc_send_compl;350	ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;351	list_del_init(&ipc_link->link);352	list_add(&ipc_link->link, &dev->wr_free_list);353	spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);354 355	/*356	 * callback will be called out of spinlock,357	 * after ipc_link returned to free list358	 */359	if (ipc_send_compl)360		ipc_send_compl(ipc_send_compl_prm);361 362	return 0;363}364 365/**366 * write_ipc_to_queue() - write ipc msg to Tx queue367 * @dev: ishtp device instance368 * @ipc_send_compl: Send complete callback369 * @ipc_send_compl_prm:	Parameter to send in complete callback370 * @msg: Pointer to message371 * @length: Length of message372 *373 * Recived msg with IPC (and upper protocol) header  and add it to the device374 *  Tx-to-write list then try to send the first IPC waiting msg375 *  (if DRBL is cleared)376 * This function returns negative value for failure (means free list377 *  is empty, or msg too long) and 0 for success.378 *379 * Return: 0 for success else failure code380 */381static int write_ipc_to_queue(struct ishtp_device *dev,382	void (*ipc_send_compl)(void *), void *ipc_send_compl_prm,383	unsigned char *msg, int length)384{385	struct wr_msg_ctl_info *ipc_link;386	unsigned long flags;387 388	if (length > IPC_FULL_MSG_SIZE)389		return -EMSGSIZE;390 391	spin_lock_irqsave(&dev->wr_processing_spinlock, flags);392	if (list_empty(&dev->wr_free_list)) {393		spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);394		return -ENOMEM;395	}396	ipc_link = list_first_entry(&dev->wr_free_list,397				    struct wr_msg_ctl_info, link);398	list_del_init(&ipc_link->link);399 400	ipc_link->ipc_send_compl = ipc_send_compl;401	ipc_link->ipc_send_compl_prm = ipc_send_compl_prm;402	ipc_link->length = length;403	memcpy(ipc_link->inline_data, msg, length);404 405	list_add_tail(&ipc_link->link, &dev->wr_processing_list);406	spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);407 408	write_ipc_from_queue(dev);409 410	return 0;411}412 413/**414 * ipc_send_mng_msg() - Send management message415 * @dev: ishtp device instance416 * @msg_code: Message code417 * @msg: Pointer to message418 * @size: Length of message419 *420 * Send management message to FW421 *422 * Return: 0 for success else failure code423 */424static int ipc_send_mng_msg(struct ishtp_device *dev, uint32_t msg_code,425	void *msg, size_t size)426{427	unsigned char	ipc_msg[IPC_FULL_MSG_SIZE];428	uint32_t	drbl_val = IPC_BUILD_MNG_MSG(msg_code, size);429 430	memcpy(ipc_msg, &drbl_val, sizeof(uint32_t));431	memcpy(ipc_msg + sizeof(uint32_t), msg, size);432	return	write_ipc_to_queue(dev, NULL, NULL, ipc_msg,433		sizeof(uint32_t) + size);434}435 436#define WAIT_FOR_FW_RDY			0x1437#define WAIT_FOR_INPUT_RDY		0x2438 439/**440 * timed_wait_for_timeout() - wait special event with timeout441 * @dev: ISHTP device pointer442 * @condition: indicate the condition for waiting443 * @timeinc: time slice for every wait cycle, in ms444 * @timeout: time in ms for timeout445 *446 * This function will check special event to be ready in a loop, the loop447 * period is specificd in timeinc. Wait timeout will causes failure.448 *449 * Return: 0 for success else failure code450 */451static int timed_wait_for_timeout(struct ishtp_device *dev, int condition,452				unsigned int timeinc, unsigned int timeout)453{454	bool complete = false;455	int ret;456 457	do {458		if (condition == WAIT_FOR_FW_RDY) {459			complete = ishtp_fw_is_ready(dev);460		} else if (condition == WAIT_FOR_INPUT_RDY) {461			complete = ish_is_input_ready(dev);462		} else {463			ret = -EINVAL;464			goto out;465		}466 467		if (!complete) {468			unsigned long left_time;469 470			left_time = msleep_interruptible(timeinc);471			timeout -= (timeinc - left_time);472		}473	} while (!complete && timeout > 0);474 475	if (complete)476		ret = 0;477	else478		ret = -EBUSY;479 480out:481	return ret;482}483 484#define TIME_SLICE_FOR_FW_RDY_MS		100485#define TIME_SLICE_FOR_INPUT_RDY_MS		100486#define TIMEOUT_FOR_FW_RDY_MS			2000487#define TIMEOUT_FOR_INPUT_RDY_MS		2000488 489/**490 * ish_fw_reset_handler() - FW reset handler491 * @dev: ishtp device pointer492 *493 * Handle FW reset494 *495 * Return: 0 for success else failure code496 */497static int ish_fw_reset_handler(struct ishtp_device *dev)498{499	uint32_t	reset_id;500	unsigned long	flags;501 502	/* Read reset ID */503	reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;504 505	/* Clear IPC output queue */506	spin_lock_irqsave(&dev->wr_processing_spinlock, flags);507	list_splice_init(&dev->wr_processing_list, &dev->wr_free_list);508	spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);509 510	/* ISHTP notification in IPC_RESET */511	ishtp_reset_handler(dev);512 513	if (!ish_is_input_ready(dev))514		timed_wait_for_timeout(dev, WAIT_FOR_INPUT_RDY,515			TIME_SLICE_FOR_INPUT_RDY_MS, TIMEOUT_FOR_INPUT_RDY_MS);516 517	/* ISH FW is dead */518	if (!ish_is_input_ready(dev))519		return	-EPIPE;520	/*521	 * Set HOST2ISH.ILUP. Apparently we need this BEFORE sending522	 * RESET_NOTIFY_ACK - FW will be checking for it523	 */524	ish_set_host_rdy(dev);525	/* Send RESET_NOTIFY_ACK (with reset_id) */526	ipc_send_mng_msg(dev, MNG_RESET_NOTIFY_ACK, &reset_id,527			 sizeof(uint32_t));528 529	/* Wait for ISH FW'es ILUP and ISHTP_READY */530	timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY,531			TIME_SLICE_FOR_FW_RDY_MS, TIMEOUT_FOR_FW_RDY_MS);532	if (!ishtp_fw_is_ready(dev)) {533		/* ISH FW is dead */534		uint32_t	ish_status;535 536		ish_status = _ish_read_fw_sts_reg(dev);537		dev_err(dev->devc,538			"[ishtp-ish]: completed reset, ISH is dead (FWSTS = %08X)\n",539			ish_status);540		return -ENODEV;541	}542	return	0;543}544 545#define TIMEOUT_FOR_HW_RDY_MS			300546 547/**548 * fw_reset_work_fn() - FW reset worker function549 * @work: Work item550 *551 * Call ish_fw_reset_handler to complete FW reset552 */553static void fw_reset_work_fn(struct work_struct *work)554{555	int	rv;556 557	rv = ish_fw_reset_handler(ishtp_dev);558	if (!rv) {559		/* ISH is ILUP & ISHTP-ready. Restart ISHTP */560		msleep_interruptible(TIMEOUT_FOR_HW_RDY_MS);561		ishtp_dev->recvd_hw_ready = 1;562		wake_up_interruptible(&ishtp_dev->wait_hw_ready);563 564		/* ISHTP notification in IPC_RESET sequence completion */565		if (!work_pending(work))566			ishtp_reset_compl_handler(ishtp_dev);567	} else568		dev_err(ishtp_dev->devc, "[ishtp-ish]: FW reset failed (%d)\n",569			rv);570}571 572/**573 * _ish_sync_fw_clock() -Sync FW clock with the OS clock574 * @dev: ishtp device pointer575 *576 * Sync FW and OS time577 */578static void _ish_sync_fw_clock(struct ishtp_device *dev)579{580	static unsigned long	prev_sync;581	uint64_t	usec;582 583	if (prev_sync && time_before(jiffies, prev_sync + 20 * HZ))584		return;585 586	prev_sync = jiffies;587	usec = ktime_to_us(ktime_get_boottime());588	ipc_send_mng_msg(dev, MNG_SYNC_FW_CLOCK, &usec, sizeof(uint64_t));589}590 591/**592 * recv_ipc() - Receive and process IPC management messages593 * @dev: ishtp device instance594 * @doorbell_val: doorbell value595 *596 * This function runs in ISR context.597 * NOTE: Any other mng command than reset_notify and reset_notify_ack598 * won't wake BH handler599 */600static void	recv_ipc(struct ishtp_device *dev, uint32_t doorbell_val)601{602	uint32_t	mng_cmd;603 604	mng_cmd = IPC_HEADER_GET_MNG_CMD(doorbell_val);605 606	switch (mng_cmd) {607	default:608		break;609 610	case MNG_RX_CMPL_INDICATION:611		if (dev->suspend_flag) {612			dev->suspend_flag = 0;613			wake_up_interruptible(&dev->suspend_wait);614		}615		if (dev->resume_flag) {616			dev->resume_flag = 0;617			wake_up_interruptible(&dev->resume_wait);618		}619 620		write_ipc_from_queue(dev);621		break;622 623	case MNG_RESET_NOTIFY:624		if (!ishtp_dev) {625			ishtp_dev = dev;626		}627		schedule_work(&fw_reset_work);628		break;629 630	case MNG_RESET_NOTIFY_ACK:631		dev->recvd_hw_ready = 1;632		wake_up_interruptible(&dev->wait_hw_ready);633		break;634	}635}636 637/**638 * ish_irq_handler() - ISH IRQ handler639 * @irq: irq number640 * @dev_id: ishtp device pointer641 *642 * ISH IRQ handler. If interrupt is generated and is for ISH it will process643 * the interrupt.644 */645irqreturn_t ish_irq_handler(int irq, void *dev_id)646{647	struct ishtp_device	*dev = dev_id;648	uint32_t	doorbell_val;649	bool	interrupt_generated;650 651	/* Check that it's interrupt from ISH (may be shared) */652	interrupt_generated = check_generated_interrupt(dev);653 654	if (!interrupt_generated)655		return IRQ_NONE;656 657	doorbell_val = ish_reg_read(dev, IPC_REG_ISH2HOST_DRBL);658	if (!IPC_IS_BUSY(doorbell_val))659		return IRQ_HANDLED;660 661	if (dev->dev_state == ISHTP_DEV_DISABLED)662		return	IRQ_HANDLED;663 664	/* Sanity check: IPC dgram length in header */665	if (IPC_HEADER_GET_LENGTH(doorbell_val) > IPC_PAYLOAD_SIZE) {666		dev_err(dev->devc,667			"IPC hdr - bad length: %u; dropped\n",668			(unsigned int)IPC_HEADER_GET_LENGTH(doorbell_val));669		goto	eoi;670	}671 672	switch (IPC_HEADER_GET_PROTOCOL(doorbell_val)) {673	default:674		break;675	case IPC_PROTOCOL_MNG:676		recv_ipc(dev, doorbell_val);677		break;678	case IPC_PROTOCOL_ISHTP:679		ishtp_recv(dev);680		break;681	}682 683eoi:684	/* Update IPC counters */685	++dev->ipc_rx_cnt;686	dev->ipc_rx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);687 688	ish_reg_write(dev, IPC_REG_ISH2HOST_DRBL, 0);689	/* Flush write to doorbell */690	ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);691 692	return	IRQ_HANDLED;693}694 695/**696 * ish_disable_dma() - disable dma communication between host and ISHFW697 * @dev: ishtp device pointer698 *699 * Clear the dma enable bit and wait for dma inactive.700 *701 * Return: 0 for success else error code.702 */703int ish_disable_dma(struct ishtp_device *dev)704{705	unsigned int	dma_delay;706 707	/* Clear the dma enable bit */708	ish_reg_write(dev, IPC_REG_ISH_RMP2, 0);709 710	/* wait for dma inactive */711	for (dma_delay = 0; dma_delay < MAX_DMA_DELAY &&712		_ish_read_fw_sts_reg(dev) & (IPC_ISH_IN_DMA);713		dma_delay += 5)714		mdelay(5);715 716	if (dma_delay >= MAX_DMA_DELAY) {717		dev_err(dev->devc,718			"Wait for DMA inactive timeout\n");719		return	-EBUSY;720	}721 722	return 0;723}724 725/**726 * ish_wakeup() - wakeup ishfw from waiting-for-host state727 * @dev: ishtp device pointer728 *729 * Set the dma enable bit and send a void message to FW,730 * it wil wakeup FW from waiting-for-host state.731 */732static void ish_wakeup(struct ishtp_device *dev)733{734	/* Set dma enable bit */735	ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED);736 737	/*738	 * Send 0 IPC message so that ISH FW wakes up if it was already739	 * asleep.740	 */741	ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT);742 743	/* Flush writes to doorbell and REMAP2 */744	ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);745}746 747/**748 * _ish_hw_reset() - HW reset749 * @dev: ishtp device pointer750 *751 * Reset ISH HW to recover if any error752 *753 * Return: 0 for success else error fault code754 */755static int _ish_hw_reset(struct ishtp_device *dev)756{757	struct pci_dev *pdev = dev->pdev;758	int	rv;759	uint16_t csr;760 761	if (!pdev)762		return	-ENODEV;763 764	rv = pci_reset_function(pdev);765	if (!rv)766		dev->dev_state = ISHTP_DEV_RESETTING;767 768	if (!pdev->pm_cap) {769		dev_err(&pdev->dev, "Can't reset - no PM caps\n");770		return	-EINVAL;771	}772 773	/* Disable dma communication between FW and host */774	if (ish_disable_dma(dev)) {775		dev_err(&pdev->dev,776			"Can't reset - stuck with DMA in-progress\n");777		return	-EBUSY;778	}779 780	pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &csr);781 782	csr &= ~PCI_PM_CTRL_STATE_MASK;783	csr |= PCI_D3hot;784	pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);785 786	mdelay(pdev->d3hot_delay);787 788	csr &= ~PCI_PM_CTRL_STATE_MASK;789	csr |= PCI_D0;790	pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);791 792	/* Now we can enable ISH DMA operation and wakeup ISHFW */793	ish_wakeup(dev);794 795	return	0;796}797 798/**799 * _ish_ipc_reset() - IPC reset800 * @dev: ishtp device pointer801 *802 * Resets host and fw IPC and upper layers803 *804 * Return: 0 for success else error fault code805 */806static int _ish_ipc_reset(struct ishtp_device *dev)807{808	struct ipc_rst_payload_type ipc_mng_msg;809	int	rv = 0;810 811	ipc_mng_msg.reset_id = 1;812	ipc_mng_msg.reserved = 0;813 814	set_host_ready(dev);815 816	/* Clear the incoming doorbell */817	ish_reg_write(dev, IPC_REG_ISH2HOST_DRBL, 0);818	/* Flush write to doorbell */819	ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);820 821	dev->recvd_hw_ready = 0;822 823	/* send message */824	rv = ipc_send_mng_msg(dev, MNG_RESET_NOTIFY, &ipc_mng_msg,825		sizeof(struct ipc_rst_payload_type));826	if (rv) {827		dev_err(dev->devc, "Failed to send IPC MNG_RESET_NOTIFY\n");828		return	rv;829	}830 831	wait_event_interruptible_timeout(dev->wait_hw_ready,832					 dev->recvd_hw_ready, 2 * HZ);833	if (!dev->recvd_hw_ready) {834		dev_err(dev->devc, "Timed out waiting for HW ready\n");835		rv = -ENODEV;836	}837 838	return rv;839}840 841/**842 * ish_hw_start() -Start ISH HW843 * @dev: ishtp device pointer844 *845 * Set host to ready state and wait for FW reset846 *847 * Return: 0 for success else error fault code848 */849int ish_hw_start(struct ishtp_device *dev)850{851	ish_set_host_rdy(dev);852 853	set_host_ready(dev);854 855	/* After that we can enable ISH DMA operation and wakeup ISHFW */856	ish_wakeup(dev);857 858	/* wait for FW-initiated reset flow */859	if (!dev->recvd_hw_ready)860		wait_event_interruptible_timeout(dev->wait_hw_ready,861						 dev->recvd_hw_ready,862						 10 * HZ);863 864	if (!dev->recvd_hw_ready) {865		dev_err(dev->devc,866			"[ishtp-ish]: Timed out waiting for FW-initiated reset\n");867		return	-ENODEV;868	}869 870	return 0;871}872 873/**874 * ish_ipc_get_header() -Get doorbell value875 * @dev: ishtp device pointer876 * @length: length of message877 * @busy: busy status878 *879 * Get door bell value from message header880 *881 * Return: door bell value882 */883static uint32_t ish_ipc_get_header(struct ishtp_device *dev, int length,884				   int busy)885{886	uint32_t drbl_val;887 888	drbl_val = IPC_BUILD_HEADER(length, IPC_PROTOCOL_ISHTP, busy);889 890	return drbl_val;891}892 893/**894 * _dma_no_cache_snooping()895 *896 * Check on current platform, DMA supports cache snooping or not.897 * This callback is used to notify uplayer driver if manully cache898 * flush is needed when do DMA operation.899 *900 * Please pay attention to this callback implementation, if declare901 * having cache snooping on a cache snooping not supported platform902 * will cause uplayer driver receiving mismatched data; and if903 * declare no cache snooping on a cache snooping supported platform904 * will cause cache be flushed twice and performance hit.905 *906 * @dev: ishtp device pointer907 *908 * Return: false - has cache snooping capability909 *         true - no cache snooping, need manually cache flush910 */911static bool _dma_no_cache_snooping(struct ishtp_device *dev)912{913	return (dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_EHL_Ax ||914		dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_TGL_LP ||915		dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_TGL_H ||916		dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_ADL_S ||917		dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_ADL_P);918}919 920static const struct ishtp_hw_ops ish_hw_ops = {921	.hw_reset = _ish_hw_reset,922	.ipc_reset = _ish_ipc_reset,923	.ipc_get_header = ish_ipc_get_header,924	.ishtp_read = _ishtp_read,925	.write = write_ipc_to_queue,926	.get_fw_status = _ish_read_fw_sts_reg,927	.sync_fw_clock = _ish_sync_fw_clock,928	.ishtp_read_hdr = _ishtp_read_hdr,929	.dma_no_cache_snooping = _dma_no_cache_snooping930};931 932/**933 * ish_dev_init() -Initialize ISH devoce934 * @pdev: PCI device935 *936 * Allocate ISHTP device and initialize IPC processing937 *938 * Return: ISHTP device instance on success else NULL939 */940struct ishtp_device *ish_dev_init(struct pci_dev *pdev)941{942	struct ishtp_device *dev;943	int	i;944	int	ret;945 946	dev = devm_kzalloc(&pdev->dev,947			   sizeof(struct ishtp_device) + sizeof(struct ish_hw),948			   GFP_KERNEL);949	if (!dev)950		return NULL;951 952	dev->devc = &pdev->dev;953	ishtp_device_init(dev);954 955	init_waitqueue_head(&dev->wait_hw_ready);956 957	spin_lock_init(&dev->wr_processing_spinlock);958 959	/* Init IPC processing and free lists */960	INIT_LIST_HEAD(&dev->wr_processing_list);961	INIT_LIST_HEAD(&dev->wr_free_list);962	for (i = 0; i < IPC_TX_FIFO_SIZE; i++) {963		struct wr_msg_ctl_info	*tx_buf;964 965		tx_buf = devm_kzalloc(&pdev->dev,966				      sizeof(struct wr_msg_ctl_info),967				      GFP_KERNEL);968		if (!tx_buf) {969			/*970			 * IPC buffers may be limited or not available971			 * at all - although this shouldn't happen972			 */973			dev_err(dev->devc,974				"[ishtp-ish]: failure in Tx FIFO allocations (%d)\n",975				i);976			break;977		}978		list_add_tail(&tx_buf->link, &dev->wr_free_list);979	}980 981	ret = devm_work_autocancel(&pdev->dev, &fw_reset_work, fw_reset_work_fn);982	if (ret) {983		dev_err(dev->devc, "Failed to initialise FW reset work\n");984		return NULL;985	}986 987	dev->ops = &ish_hw_ops;988	dev->mtu = IPC_PAYLOAD_SIZE - sizeof(struct ishtp_msg_hdr);989	return dev;990}991 992/**993 * ish_device_disable() - Disable ISH device994 * @dev: ISHTP device pointer995 *996 * Disable ISH by clearing host ready to inform firmware.997 */998void	ish_device_disable(struct ishtp_device *dev)999{1000	struct pci_dev *pdev = dev->pdev;1001 1002	if (!pdev)1003		return;1004 1005	/* Disable dma communication between FW and host */1006	if (ish_disable_dma(dev)) {1007		dev_err(&pdev->dev,1008			"Can't reset - stuck with DMA in-progress\n");1009		return;1010	}1011 1012	/* Put ISH to D3hot state for power saving */1013	pci_set_power_state(pdev, PCI_D3hot);1014 1015	dev->dev_state = ISHTP_DEV_DISABLED;1016	ish_clr_host_rdy(dev);1017}1018