162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 2009 - 2018 Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include "mbx.h"
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci/**
762306a36Sopenharmony_ci *  e1000_poll_for_msg - Wait for message notification
862306a36Sopenharmony_ci *  @hw: pointer to the HW structure
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  returns SUCCESS if it successfully received a message notification
1162306a36Sopenharmony_ci **/
1262306a36Sopenharmony_cistatic s32 e1000_poll_for_msg(struct e1000_hw *hw)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	struct e1000_mbx_info *mbx = &hw->mbx;
1562306a36Sopenharmony_ci	int countdown = mbx->timeout;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	if (!mbx->ops.check_for_msg)
1862306a36Sopenharmony_ci		goto out;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	while (countdown && mbx->ops.check_for_msg(hw)) {
2162306a36Sopenharmony_ci		countdown--;
2262306a36Sopenharmony_ci		udelay(mbx->usec_delay);
2362306a36Sopenharmony_ci	}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	/* if we failed, all future posted messages fail until reset */
2662306a36Sopenharmony_ci	if (!countdown)
2762306a36Sopenharmony_ci		mbx->timeout = 0;
2862306a36Sopenharmony_ciout:
2962306a36Sopenharmony_ci	return countdown ? E1000_SUCCESS : -E1000_ERR_MBX;
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/**
3362306a36Sopenharmony_ci *  e1000_poll_for_ack - Wait for message acknowledgment
3462306a36Sopenharmony_ci *  @hw: pointer to the HW structure
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci *  returns SUCCESS if it successfully received a message acknowledgment
3762306a36Sopenharmony_ci **/
3862306a36Sopenharmony_cistatic s32 e1000_poll_for_ack(struct e1000_hw *hw)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct e1000_mbx_info *mbx = &hw->mbx;
4162306a36Sopenharmony_ci	int countdown = mbx->timeout;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (!mbx->ops.check_for_ack)
4462306a36Sopenharmony_ci		goto out;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	while (countdown && mbx->ops.check_for_ack(hw)) {
4762306a36Sopenharmony_ci		countdown--;
4862306a36Sopenharmony_ci		udelay(mbx->usec_delay);
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* if we failed, all future posted messages fail until reset */
5262306a36Sopenharmony_ci	if (!countdown)
5362306a36Sopenharmony_ci		mbx->timeout = 0;
5462306a36Sopenharmony_ciout:
5562306a36Sopenharmony_ci	return countdown ? E1000_SUCCESS : -E1000_ERR_MBX;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/**
5962306a36Sopenharmony_ci *  e1000_read_posted_mbx - Wait for message notification and receive message
6062306a36Sopenharmony_ci *  @hw: pointer to the HW structure
6162306a36Sopenharmony_ci *  @msg: The message buffer
6262306a36Sopenharmony_ci *  @size: Length of buffer
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci *  returns SUCCESS if it successfully received a message notification and
6562306a36Sopenharmony_ci *  copied it into the receive buffer.
6662306a36Sopenharmony_ci **/
6762306a36Sopenharmony_cistatic s32 e1000_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct e1000_mbx_info *mbx = &hw->mbx;
7062306a36Sopenharmony_ci	s32 ret_val = -E1000_ERR_MBX;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (!mbx->ops.read)
7362306a36Sopenharmony_ci		goto out;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	ret_val = e1000_poll_for_msg(hw);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* if ack received read message, otherwise we timed out */
7862306a36Sopenharmony_ci	if (!ret_val)
7962306a36Sopenharmony_ci		ret_val = mbx->ops.read(hw, msg, size);
8062306a36Sopenharmony_ciout:
8162306a36Sopenharmony_ci	return ret_val;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/**
8562306a36Sopenharmony_ci *  e1000_write_posted_mbx - Write a message to the mailbox, wait for ack
8662306a36Sopenharmony_ci *  @hw: pointer to the HW structure
8762306a36Sopenharmony_ci *  @msg: The message buffer
8862306a36Sopenharmony_ci *  @size: Length of buffer
8962306a36Sopenharmony_ci *
9062306a36Sopenharmony_ci *  returns SUCCESS if it successfully copied message into the buffer and
9162306a36Sopenharmony_ci *  received an ack to that message within delay * timeout period
9262306a36Sopenharmony_ci **/
9362306a36Sopenharmony_cistatic s32 e1000_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct e1000_mbx_info *mbx = &hw->mbx;
9662306a36Sopenharmony_ci	s32 ret_val = -E1000_ERR_MBX;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/* exit if we either can't write or there isn't a defined timeout */
9962306a36Sopenharmony_ci	if (!mbx->ops.write || !mbx->timeout)
10062306a36Sopenharmony_ci		goto out;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	/* send msg*/
10362306a36Sopenharmony_ci	ret_val = mbx->ops.write(hw, msg, size);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* if msg sent wait until we receive an ack */
10662306a36Sopenharmony_ci	if (!ret_val)
10762306a36Sopenharmony_ci		ret_val = e1000_poll_for_ack(hw);
10862306a36Sopenharmony_ciout:
10962306a36Sopenharmony_ci	return ret_val;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/**
11362306a36Sopenharmony_ci *  e1000_read_v2p_mailbox - read v2p mailbox
11462306a36Sopenharmony_ci *  @hw: pointer to the HW structure
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci *  This function is used to read the v2p mailbox without losing the read to
11762306a36Sopenharmony_ci *  clear status bits.
11862306a36Sopenharmony_ci **/
11962306a36Sopenharmony_cistatic u32 e1000_read_v2p_mailbox(struct e1000_hw *hw)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	u32 v2p_mailbox = er32(V2PMAILBOX(0));
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	v2p_mailbox |= hw->dev_spec.vf.v2p_mailbox;
12462306a36Sopenharmony_ci	hw->dev_spec.vf.v2p_mailbox |= v2p_mailbox & E1000_V2PMAILBOX_R2C_BITS;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return v2p_mailbox;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/**
13062306a36Sopenharmony_ci *  e1000_check_for_bit_vf - Determine if a status bit was set
13162306a36Sopenharmony_ci *  @hw: pointer to the HW structure
13262306a36Sopenharmony_ci *  @mask: bitmask for bits to be tested and cleared
13362306a36Sopenharmony_ci *
13462306a36Sopenharmony_ci *  This function is used to check for the read to clear bits within
13562306a36Sopenharmony_ci *  the V2P mailbox.
13662306a36Sopenharmony_ci **/
13762306a36Sopenharmony_cistatic s32 e1000_check_for_bit_vf(struct e1000_hw *hw, u32 mask)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	u32 v2p_mailbox = e1000_read_v2p_mailbox(hw);
14062306a36Sopenharmony_ci	s32 ret_val = -E1000_ERR_MBX;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (v2p_mailbox & mask)
14362306a36Sopenharmony_ci		ret_val = E1000_SUCCESS;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	hw->dev_spec.vf.v2p_mailbox &= ~mask;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return ret_val;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/**
15162306a36Sopenharmony_ci *  e1000_check_for_msg_vf - checks to see if the PF has sent mail
15262306a36Sopenharmony_ci *  @hw: pointer to the HW structure
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci *  returns SUCCESS if the PF has set the Status bit or else ERR_MBX
15562306a36Sopenharmony_ci **/
15662306a36Sopenharmony_cistatic s32 e1000_check_for_msg_vf(struct e1000_hw *hw)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	s32 ret_val = -E1000_ERR_MBX;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (!e1000_check_for_bit_vf(hw, E1000_V2PMAILBOX_PFSTS)) {
16162306a36Sopenharmony_ci		ret_val = E1000_SUCCESS;
16262306a36Sopenharmony_ci		hw->mbx.stats.reqs++;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return ret_val;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/**
16962306a36Sopenharmony_ci *  e1000_check_for_ack_vf - checks to see if the PF has ACK'd
17062306a36Sopenharmony_ci *  @hw: pointer to the HW structure
17162306a36Sopenharmony_ci *
17262306a36Sopenharmony_ci *  returns SUCCESS if the PF has set the ACK bit or else ERR_MBX
17362306a36Sopenharmony_ci **/
17462306a36Sopenharmony_cistatic s32 e1000_check_for_ack_vf(struct e1000_hw *hw)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	s32 ret_val = -E1000_ERR_MBX;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	if (!e1000_check_for_bit_vf(hw, E1000_V2PMAILBOX_PFACK)) {
17962306a36Sopenharmony_ci		ret_val = E1000_SUCCESS;
18062306a36Sopenharmony_ci		hw->mbx.stats.acks++;
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	return ret_val;
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/**
18762306a36Sopenharmony_ci *  e1000_check_for_rst_vf - checks to see if the PF has reset
18862306a36Sopenharmony_ci *  @hw: pointer to the HW structure
18962306a36Sopenharmony_ci *
19062306a36Sopenharmony_ci *  returns true if the PF has set the reset done bit or else false
19162306a36Sopenharmony_ci **/
19262306a36Sopenharmony_cistatic s32 e1000_check_for_rst_vf(struct e1000_hw *hw)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	s32 ret_val = -E1000_ERR_MBX;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (!e1000_check_for_bit_vf(hw, (E1000_V2PMAILBOX_RSTD |
19762306a36Sopenharmony_ci					 E1000_V2PMAILBOX_RSTI))) {
19862306a36Sopenharmony_ci		ret_val = E1000_SUCCESS;
19962306a36Sopenharmony_ci		hw->mbx.stats.rsts++;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return ret_val;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci/**
20662306a36Sopenharmony_ci *  e1000_obtain_mbx_lock_vf - obtain mailbox lock
20762306a36Sopenharmony_ci *  @hw: pointer to the HW structure
20862306a36Sopenharmony_ci *
20962306a36Sopenharmony_ci *  return SUCCESS if we obtained the mailbox lock
21062306a36Sopenharmony_ci **/
21162306a36Sopenharmony_cistatic s32 e1000_obtain_mbx_lock_vf(struct e1000_hw *hw)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	s32 ret_val = -E1000_ERR_MBX;
21462306a36Sopenharmony_ci	int count = 10;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	do {
21762306a36Sopenharmony_ci		/* Take ownership of the buffer */
21862306a36Sopenharmony_ci		ew32(V2PMAILBOX(0), E1000_V2PMAILBOX_VFU);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		/* reserve mailbox for VF use */
22162306a36Sopenharmony_ci		if (e1000_read_v2p_mailbox(hw) & E1000_V2PMAILBOX_VFU) {
22262306a36Sopenharmony_ci			ret_val = 0;
22362306a36Sopenharmony_ci			break;
22462306a36Sopenharmony_ci		}
22562306a36Sopenharmony_ci		udelay(1000);
22662306a36Sopenharmony_ci	} while (count-- > 0);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	return ret_val;
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci/**
23262306a36Sopenharmony_ci *  e1000_write_mbx_vf - Write a message to the mailbox
23362306a36Sopenharmony_ci *  @hw: pointer to the HW structure
23462306a36Sopenharmony_ci *  @msg: The message buffer
23562306a36Sopenharmony_ci *  @size: Length of buffer
23662306a36Sopenharmony_ci *
23762306a36Sopenharmony_ci *  returns SUCCESS if it successfully copied message into the buffer
23862306a36Sopenharmony_ci **/
23962306a36Sopenharmony_cistatic s32 e1000_write_mbx_vf(struct e1000_hw *hw, u32 *msg, u16 size)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	s32 err;
24262306a36Sopenharmony_ci	u16 i;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	lockdep_assert_held(&hw->mbx_lock);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* lock the mailbox to prevent pf/vf race condition */
24762306a36Sopenharmony_ci	err = e1000_obtain_mbx_lock_vf(hw);
24862306a36Sopenharmony_ci	if (err)
24962306a36Sopenharmony_ci		goto out_no_write;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* flush any ack or msg as we are going to overwrite mailbox */
25262306a36Sopenharmony_ci	e1000_check_for_ack_vf(hw);
25362306a36Sopenharmony_ci	e1000_check_for_msg_vf(hw);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/* copy the caller specified message to the mailbox memory buffer */
25662306a36Sopenharmony_ci	for (i = 0; i < size; i++)
25762306a36Sopenharmony_ci		array_ew32(VMBMEM(0), i, msg[i]);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/* update stats */
26062306a36Sopenharmony_ci	hw->mbx.stats.msgs_tx++;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Drop VFU and interrupt the PF to tell it a message has been sent */
26362306a36Sopenharmony_ci	ew32(V2PMAILBOX(0), E1000_V2PMAILBOX_REQ);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ciout_no_write:
26662306a36Sopenharmony_ci	return err;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/**
27062306a36Sopenharmony_ci *  e1000_read_mbx_vf - Reads a message from the inbox intended for VF
27162306a36Sopenharmony_ci *  @hw: pointer to the HW structure
27262306a36Sopenharmony_ci *  @msg: The message buffer
27362306a36Sopenharmony_ci *  @size: Length of buffer
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci *  returns SUCCESS if it successfully read message from buffer
27662306a36Sopenharmony_ci **/
27762306a36Sopenharmony_cistatic s32 e1000_read_mbx_vf(struct e1000_hw *hw, u32 *msg, u16 size)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	s32 err;
28062306a36Sopenharmony_ci	u16 i;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	lockdep_assert_held(&hw->mbx_lock);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* lock the mailbox to prevent pf/vf race condition */
28562306a36Sopenharmony_ci	err = e1000_obtain_mbx_lock_vf(hw);
28662306a36Sopenharmony_ci	if (err)
28762306a36Sopenharmony_ci		goto out_no_read;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/* copy the message from the mailbox memory buffer */
29062306a36Sopenharmony_ci	for (i = 0; i < size; i++)
29162306a36Sopenharmony_ci		msg[i] = array_er32(VMBMEM(0), i);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/* Acknowledge receipt and release mailbox, then we're done */
29462306a36Sopenharmony_ci	ew32(V2PMAILBOX(0), E1000_V2PMAILBOX_ACK);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* update stats */
29762306a36Sopenharmony_ci	hw->mbx.stats.msgs_rx++;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ciout_no_read:
30062306a36Sopenharmony_ci	return err;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci/**
30462306a36Sopenharmony_ci *  e1000_init_mbx_params_vf - set initial values for VF mailbox
30562306a36Sopenharmony_ci *  @hw: pointer to the HW structure
30662306a36Sopenharmony_ci *
30762306a36Sopenharmony_ci *  Initializes the hw->mbx struct to correct values for VF mailbox
30862306a36Sopenharmony_ci */
30962306a36Sopenharmony_cis32 e1000_init_mbx_params_vf(struct e1000_hw *hw)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct e1000_mbx_info *mbx = &hw->mbx;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* start mailbox as timed out and let the reset_hw call set the timeout
31462306a36Sopenharmony_ci	 * value to being communications
31562306a36Sopenharmony_ci	 */
31662306a36Sopenharmony_ci	mbx->timeout = 0;
31762306a36Sopenharmony_ci	mbx->usec_delay = E1000_VF_MBX_INIT_DELAY;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	mbx->size = E1000_VFMAILBOX_SIZE;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	mbx->ops.read = e1000_read_mbx_vf;
32262306a36Sopenharmony_ci	mbx->ops.write = e1000_write_mbx_vf;
32362306a36Sopenharmony_ci	mbx->ops.read_posted = e1000_read_posted_mbx;
32462306a36Sopenharmony_ci	mbx->ops.write_posted = e1000_write_posted_mbx;
32562306a36Sopenharmony_ci	mbx->ops.check_for_msg = e1000_check_for_msg_vf;
32662306a36Sopenharmony_ci	mbx->ops.check_for_ack = e1000_check_for_ack_vf;
32762306a36Sopenharmony_ci	mbx->ops.check_for_rst = e1000_check_for_rst_vf;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	mbx->stats.msgs_tx = 0;
33062306a36Sopenharmony_ci	mbx->stats.msgs_rx = 0;
33162306a36Sopenharmony_ci	mbx->stats.reqs = 0;
33262306a36Sopenharmony_ci	mbx->stats.acks = 0;
33362306a36Sopenharmony_ci	mbx->stats.rsts = 0;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	return E1000_SUCCESS;
33662306a36Sopenharmony_ci}
337