The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=68ba3eabd4869577bf11c03a6ec6f472502be07d
commit 68ba3eabd4869577bf11c03a6ec6f472502be07d Author: Jakub Chylkowski <jakubx.chylkow...@intel.com> AuthorDate: 2024-09-20 01:39:35 +0000 Commit: Kevin Bowling <kbowl...@freebsd.org> CommitDate: 2024-09-20 01:39:35 +0000 ixgbe: introduce new mailbox API DPDK commit message Current mailbox API does not work as described in documentation and is prone to errors (for example, it is doing locks on read). Introduce new mailbox API and provide compatibility functions with old API. New error codes have been introduced: - IXGBE_ERR_CONFIG - ixgbe_mbx_operations is not correctly set - IXGBE_ERR_TIMEOUT - mailbox operation, e.g. poll for message, timedout - IXGBE_ERR_MBX_NOMSG - no message available on read In addition, some refactoring has been done: mailbox structures were defined twice: in ixgbe_type.h and ixgbe_vf.h. Move them into ixgbe_mbx.h as this header is dedicated for mailbox. Signed-off-by: Jakub Chylkowski <jakubx.chylkow...@intel.com> Reviewed-by: Alice Michael <alice.mich...@intel.com> Reviewed-by: Piotr Pietruszewski <piotr.pietruszew...@intel.com> Tested-by: Alice Michael <alice.mich...@intel.com> Tested-by: Piotr Skajewski <piotrx.skajew...@intel.com> Obtained from: DPDK (6d243d2) MFC after: 1 week --- sys/dev/ixgbe/if_ix.c | 7 +- sys/dev/ixgbe/ixgbe_82599.c | 4 +- sys/dev/ixgbe/ixgbe_mbx.c | 839 ++++++++++++++++++++++++++++++++------------ sys/dev/ixgbe/ixgbe_type.h | 32 +- sys/dev/ixgbe/ixgbe_vf.c | 42 ++- sys/dev/ixgbe/ixgbe_x540.c | 4 +- 6 files changed, 650 insertions(+), 278 deletions(-) diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c index 17f1f73a526e..ed41f6b66e09 100644 --- a/sys/dev/ixgbe/if_ix.c +++ b/sys/dev/ixgbe/if_ix.c @@ -879,6 +879,7 @@ ixgbe_if_attach_pre(if_ctx_t ctx) struct ixgbe_hw *hw; int error = 0; u32 ctrl_ext; + size_t i; INIT_DEBUGOUT("ixgbe_attach: begin"); @@ -928,8 +929,10 @@ ixgbe_if_attach_pre(if_ctx_t ctx) goto err_pci; } - if (hw->mbx.ops.init_params) - hw->mbx.ops.init_params(hw); + if (hw->mbx.ops[0].init_params) { + for (i = 0; i < sc->num_vfs; i++) + hw->mbx.ops[i].init_params(hw); + } hw->allow_unsupported_sfp = allow_unsupported_sfp; diff --git a/sys/dev/ixgbe/ixgbe_82599.c b/sys/dev/ixgbe/ixgbe_82599.c index 8c3df0fd4f59..70b4cdc5c6ca 100644 --- a/sys/dev/ixgbe/ixgbe_82599.c +++ b/sys/dev/ixgbe/ixgbe_82599.c @@ -324,6 +324,7 @@ s32 ixgbe_init_ops_82599(struct ixgbe_hw *hw) struct ixgbe_phy_info *phy = &hw->phy; struct ixgbe_eeprom_info *eeprom = &hw->eeprom; s32 ret_val; + u16 i; DEBUGFUNC("ixgbe_init_ops_82599"); @@ -385,7 +386,8 @@ s32 ixgbe_init_ops_82599(struct ixgbe_hw *hw) mac->arc_subsystem_valid = !!(IXGBE_READ_REG(hw, IXGBE_FWSM_BY_MAC(hw)) & IXGBE_FWSM_MODE_MASK); - hw->mbx.ops.init_params = ixgbe_init_mbx_params_pf; + for (i = 0; i < 64; i++) + hw->mbx.ops[i].init_params = ixgbe_init_mbx_params_pf; /* EEPROM */ eeprom->ops.read = ixgbe_read_eeprom_82599; diff --git a/sys/dev/ixgbe/ixgbe_mbx.c b/sys/dev/ixgbe/ixgbe_mbx.c index c8f839fce85a..0a0c5abde157 100644 --- a/sys/dev/ixgbe/ixgbe_mbx.c +++ b/sys/dev/ixgbe/ixgbe_mbx.c @@ -35,6 +35,9 @@ #include "ixgbe_type.h" #include "ixgbe_mbx.h" +static s32 ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id); +static s32 ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id); + /** * ixgbe_read_mbx - Reads a message from the mailbox * @hw: pointer to the HW structure @@ -47,42 +50,91 @@ s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; DEBUGFUNC("ixgbe_read_mbx"); /* limit read to size of mailbox */ - if (size > mbx->size) + if (size > mbx->size) { + ERROR_REPORT3(IXGBE_ERROR_ARGUMENT, + "Invalid mailbox message size %u, changing to %u", + size, mbx->size); + size = mbx->size; + } + + if (mbx->ops[mbx_id].read) + return mbx->ops[mbx_id].read(hw, msg, size, mbx_id); + + return IXGBE_ERR_CONFIG; +} + +/** + * ixgbe_poll_mbx - Wait for message and read it from the mailbox + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * @mbx_id: id of mailbox to read + * + * returns SUCCESS if it successfully read message from buffer + **/ +s32 ixgbe_poll_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + s32 ret_val; + + DEBUGFUNC("ixgbe_poll_mbx"); + + if (!mbx->ops[mbx_id].read || !mbx->ops[mbx_id].check_for_msg || + !mbx->timeout) + return IXGBE_ERR_CONFIG; + + /* limit read to size of mailbox */ + if (size > mbx->size) { + ERROR_REPORT3(IXGBE_ERROR_ARGUMENT, + "Invalid mailbox message size %u, changing to %u", + size, mbx->size); size = mbx->size; + } - if (mbx->ops.read) - ret_val = mbx->ops.read(hw, msg, size, mbx_id); + ret_val = ixgbe_poll_for_msg(hw, mbx_id); + /* if ack received read message, otherwise we timed out */ + if (!ret_val) + return mbx->ops[mbx_id].read(hw, msg, size, mbx_id); return ret_val; } /** - * ixgbe_write_mbx - Write a message to the mailbox + * ixgbe_write_mbx - Write a message to the mailbox and wait for ACK * @hw: pointer to the HW structure * @msg: The message buffer * @size: Length of buffer * @mbx_id: id of mailbox to write * - * returns SUCCESS if it successfully copied message into the buffer + * returns SUCCESS if it successfully copied message into the buffer and + * received an ACK to that message within specified period **/ s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_SUCCESS; + s32 ret_val = IXGBE_ERR_MBX; DEBUGFUNC("ixgbe_write_mbx"); + /* + * exit if either we can't write, release + * or there is no timeout defined + */ + if (!mbx->ops[mbx_id].write || !mbx->ops[mbx_id].check_for_ack || + !mbx->ops[mbx_id].release || !mbx->timeout) + return IXGBE_ERR_CONFIG; + if (size > mbx->size) { - ret_val = IXGBE_ERR_MBX; + ret_val = IXGBE_ERR_PARAM; ERROR_REPORT2(IXGBE_ERROR_ARGUMENT, - "Invalid mailbox message size %d", size); - } else if (mbx->ops.write) - ret_val = mbx->ops.write(hw, msg, size, mbx_id); + "Invalid mailbox message size %u", size); + } else { + ret_val = mbx->ops[mbx_id].write(hw, msg, size, mbx_id); + } return ret_val; } @@ -97,12 +149,12 @@ s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; + s32 ret_val = IXGBE_ERR_CONFIG; DEBUGFUNC("ixgbe_check_for_msg"); - if (mbx->ops.check_for_msg) - ret_val = mbx->ops.check_for_msg(hw, mbx_id); + if (mbx->ops[mbx_id].check_for_msg) + ret_val = mbx->ops[mbx_id].check_for_msg(hw, mbx_id); return ret_val; } @@ -117,12 +169,12 @@ s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id) s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; + s32 ret_val = IXGBE_ERR_CONFIG; DEBUGFUNC("ixgbe_check_for_ack"); - if (mbx->ops.check_for_ack) - ret_val = mbx->ops.check_for_ack(hw, mbx_id); + if (mbx->ops[mbx_id].check_for_ack) + ret_val = mbx->ops[mbx_id].check_for_ack(hw, mbx_id); return ret_val; } @@ -137,12 +189,12 @@ s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id) s32 ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; + s32 ret_val = IXGBE_ERR_CONFIG; DEBUGFUNC("ixgbe_check_for_rst"); - if (mbx->ops.check_for_rst) - ret_val = mbx->ops.check_for_rst(hw, mbx_id); + if (mbx->ops[mbx_id].check_for_rst) + ret_val = mbx->ops[mbx_id].check_for_rst(hw, mbx_id); return ret_val; } @@ -161,22 +213,23 @@ static s32 ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id) DEBUGFUNC("ixgbe_poll_for_msg"); - if (!countdown || !mbx->ops.check_for_msg) - goto out; + if (!countdown || !mbx->ops[mbx_id].check_for_msg) + return IXGBE_ERR_CONFIG; - while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) { + while (countdown && mbx->ops[mbx_id].check_for_msg(hw, mbx_id)) { countdown--; if (!countdown) break; usec_delay(mbx->usec_delay); } - if (countdown == 0) + if (countdown == 0) { ERROR_REPORT2(IXGBE_ERROR_POLLING, - "Polling for VF%d mailbox message timedout", mbx_id); + "Polling for VF%u mailbox message timedout", mbx_id); + return IXGBE_ERR_TIMEOUT; + } -out: - return countdown ? IXGBE_SUCCESS : IXGBE_ERR_MBX; + return IXGBE_SUCCESS; } /** @@ -193,115 +246,71 @@ static s32 ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id) DEBUGFUNC("ixgbe_poll_for_ack"); - if (!countdown || !mbx->ops.check_for_ack) - goto out; + if (!countdown || !mbx->ops[mbx_id].check_for_ack) + return IXGBE_ERR_CONFIG; - while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) { + while (countdown && mbx->ops[mbx_id].check_for_ack(hw, mbx_id)) { countdown--; if (!countdown) break; usec_delay(mbx->usec_delay); } - if (countdown == 0) + if (countdown == 0) { ERROR_REPORT2(IXGBE_ERROR_POLLING, - "Polling for VF%d mailbox ack timedout", mbx_id); + "Polling for VF%u mailbox ack timedout", mbx_id); + return IXGBE_ERR_TIMEOUT; + } -out: - return countdown ? IXGBE_SUCCESS : IXGBE_ERR_MBX; + return IXGBE_SUCCESS; } /** - * ixgbe_read_posted_mbx - Wait for message notification and receive message + * ixgbe_read_mailbox_vf - read VF's mailbox register * @hw: pointer to the HW structure - * @msg: The message buffer - * @size: Length of buffer - * @mbx_id: id of mailbox to write * - * returns SUCCESS if it successfully received a message notification and - * copied it into the receive buffer. + * This function is used to read the mailbox register dedicated for VF without + * losing the read to clear status bits. **/ -s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, - u16 mbx_id) +static u32 ixgbe_read_mailbox_vf(struct ixgbe_hw *hw) { - struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; - - DEBUGFUNC("ixgbe_read_posted_mbx"); - - if (!mbx->ops.read) - goto out; + u32 vf_mailbox = IXGBE_READ_REG(hw, IXGBE_VFMAILBOX); - ret_val = ixgbe_poll_for_msg(hw, mbx_id); + vf_mailbox |= hw->mbx.vf_mailbox; + hw->mbx.vf_mailbox |= vf_mailbox % IXGBE_VFMAILBOX_R2C_BITS; - /* if ack received read message, otherwise we timed out */ - if (!ret_val) - ret_val = mbx->ops.read(hw, msg, size, mbx_id); -out: - return ret_val; + return vf_mailbox; } -/** - * ixgbe_write_posted_mbx - Write a message to the mailbox, wait for ack - * @hw: pointer to the HW structure - * @msg: The message buffer - * @size: Length of buffer - * @mbx_id: id of mailbox to write - * - * returns SUCCESS if it successfully copied message into the buffer and - * received an ack to that message within delay * timeout period - **/ -s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, - u16 mbx_id) +static void ixgbe_clear_msg_vf(struct ixgbe_hw *hw) { - struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; - - DEBUGFUNC("ixgbe_write_posted_mbx"); - - /* exit if either we can't write or there isn't a defined timeout */ - if (!mbx->ops.write || !mbx->timeout) - goto out; - - /* send msg */ - ret_val = mbx->ops.write(hw, msg, size, mbx_id); + u32 vf_mailbox = ixgbe_read_mailbox_vf(hw); - /* if msg sent wait until we receive an ack */ - if (!ret_val) - ret_val = ixgbe_poll_for_ack(hw, mbx_id); -out: - return ret_val; + if (vf_mailbox & IXGBE_VFMAILBOX_PFSTS) { + hw->mbx.stats.reqs++; + hw->mbx.vf_mailbox &= ~IXGBE_VFMAILBOX_PFSTS; + } } -/** - * ixgbe_init_mbx_ops_generic - Initialize MB function pointers - * @hw: pointer to the HW structure - * - * Setups up the mailbox read and write message function pointers - **/ -void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw) +static void ixgbe_clear_ack_vf(struct ixgbe_hw *hw) { - struct ixgbe_mbx_info *mbx = &hw->mbx; + u32 vf_mailbox = ixgbe_read_mailbox_vf(hw); - mbx->ops.read_posted = ixgbe_read_posted_mbx; - mbx->ops.write_posted = ixgbe_write_posted_mbx; + if (vf_mailbox & IXGBE_VFMAILBOX_PFACK) { + hw->mbx.stats.acks++; + hw->mbx.vf_mailbox &= ~IXGBE_VFMAILBOX_PFACK; + } } -/** - * ixgbe_read_v2p_mailbox - read v2p mailbox - * @hw: pointer to the HW structure - * - * This function is used to read the v2p mailbox without losing the read to - * clear status bits. - **/ -static u32 ixgbe_read_v2p_mailbox(struct ixgbe_hw *hw) +static void ixgbe_clear_rst_vf(struct ixgbe_hw *hw) { - u32 v2p_mailbox = IXGBE_READ_REG(hw, IXGBE_VFMAILBOX); - - v2p_mailbox |= hw->mbx.v2p_mailbox; - hw->mbx.v2p_mailbox |= v2p_mailbox & IXGBE_VFMAILBOX_R2C_BITS; + u32 vf_mailbox = ixgbe_read_mailbox_vf(hw); - return v2p_mailbox; + if (vf_mailbox & (IXGBE_VFMAILBOX_RSTI | IXGBE_VFMAILBOX_RSTD)) { + hw->mbx.stats.rsts++; + hw->mbx.vf_mailbox &= ~(IXGBE_VFMAILBOX_RSTI | + IXGBE_VFMAILBOX_RSTD); + } } /** @@ -314,15 +323,12 @@ static u32 ixgbe_read_v2p_mailbox(struct ixgbe_hw *hw) **/ static s32 ixgbe_check_for_bit_vf(struct ixgbe_hw *hw, u32 mask) { - u32 v2p_mailbox = ixgbe_read_v2p_mailbox(hw); - s32 ret_val = IXGBE_ERR_MBX; + u32 vf_mailbox = ixgbe_read_mailbox_vf(hw); - if (v2p_mailbox & mask) - ret_val = IXGBE_SUCCESS; + if (vf_mailbox & mask) + return IXGBE_SUCCESS; - hw->mbx.v2p_mailbox &= ~mask; - - return ret_val; + return IXGBE_ERR_MBX; } /** @@ -334,17 +340,13 @@ static s32 ixgbe_check_for_bit_vf(struct ixgbe_hw *hw, u32 mask) **/ static s32 ixgbe_check_for_msg_vf(struct ixgbe_hw *hw, u16 mbx_id) { - s32 ret_val = IXGBE_ERR_MBX; - UNREFERENCED_1PARAMETER(mbx_id); DEBUGFUNC("ixgbe_check_for_msg_vf"); - if (!ixgbe_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFSTS)) { - ret_val = IXGBE_SUCCESS; - hw->mbx.stats.reqs++; - } + if (!ixgbe_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFSTS)) + return IXGBE_SUCCESS; - return ret_val; + return IXGBE_ERR_MBX; } /** @@ -356,17 +358,16 @@ static s32 ixgbe_check_for_msg_vf(struct ixgbe_hw *hw, u16 mbx_id) **/ static s32 ixgbe_check_for_ack_vf(struct ixgbe_hw *hw, u16 mbx_id) { - s32 ret_val = IXGBE_ERR_MBX; - UNREFERENCED_1PARAMETER(mbx_id); DEBUGFUNC("ixgbe_check_for_ack_vf"); if (!ixgbe_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFACK)) { - ret_val = IXGBE_SUCCESS; - hw->mbx.stats.acks++; + /* TODO: should this be autocleared? */ + ixgbe_clear_ack_vf(hw); + return IXGBE_SUCCESS; } - return ret_val; + return IXGBE_ERR_MBX; } /** @@ -378,18 +379,17 @@ static s32 ixgbe_check_for_ack_vf(struct ixgbe_hw *hw, u16 mbx_id) **/ static s32 ixgbe_check_for_rst_vf(struct ixgbe_hw *hw, u16 mbx_id) { - s32 ret_val = IXGBE_ERR_MBX; - UNREFERENCED_1PARAMETER(mbx_id); DEBUGFUNC("ixgbe_check_for_rst_vf"); - if (!ixgbe_check_for_bit_vf(hw, (IXGBE_VFMAILBOX_RSTD | - IXGBE_VFMAILBOX_RSTI))) { - ret_val = IXGBE_SUCCESS; - hw->mbx.stats.rsts++; + if (!ixgbe_check_for_bit_vf(hw, IXGBE_VFMAILBOX_RSTI | + IXGBE_VFMAILBOX_RSTD)) { + /* TODO: should this be autocleared? */ + ixgbe_clear_rst_vf(hw); + return IXGBE_SUCCESS; } - return ret_val; + return IXGBE_ERR_MBX; } /** @@ -400,20 +400,114 @@ static s32 ixgbe_check_for_rst_vf(struct ixgbe_hw *hw, u16 mbx_id) **/ static s32 ixgbe_obtain_mbx_lock_vf(struct ixgbe_hw *hw) { + struct ixgbe_mbx_info *mbx = &hw->mbx; + int countdown = mbx->timeout; s32 ret_val = IXGBE_ERR_MBX; + u32 vf_mailbox; DEBUGFUNC("ixgbe_obtain_mbx_lock_vf"); - /* Take ownership of the buffer */ - IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_VFU); + if (!mbx->timeout) + return IXGBE_ERR_CONFIG; - /* reserve mailbox for vf use */ - if (ixgbe_read_v2p_mailbox(hw) & IXGBE_VFMAILBOX_VFU) - ret_val = IXGBE_SUCCESS; + while (countdown--) { + /* Reserve mailbox for VF use */ + vf_mailbox = ixgbe_read_mailbox_vf(hw); + vf_mailbox |= IXGBE_VFMAILBOX_VFU; + IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox); + + /* Verify that VF is the owner of the lock */ + if (ixgbe_read_mailbox_vf(hw) & IXGBE_VFMAILBOX_VFU) { + ret_val = IXGBE_SUCCESS; + break; + } + + /* Wait a bit before trying again */ + usec_delay(mbx->usec_delay); + } + + if (ret_val != IXGBE_SUCCESS) { + ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE, + "Failed to obtain mailbox lock"); + ret_val = IXGBE_ERR_TIMEOUT; + } return ret_val; } +/** + * ixgbe_release_mbx_lock_dummy - release mailbox lock + * @hw: pointer to the HW structure + * @mbx_id: id of mailbox to read + **/ +static void ixgbe_release_mbx_lock_dummy(struct ixgbe_hw *hw, u16 mbx_id) +{ + UNREFERENCED_2PARAMETER(hw, mbx_id); + + DEBUGFUNC("ixgbe_release_mbx_lock_dummy"); +} + +/** + * ixgbe_release_mbx_lock_vf - release mailbox lock + * @hw: pointer to the HW structure + * @mbx_id: id of mailbox to read + **/ +static void ixgbe_release_mbx_lock_vf(struct ixgbe_hw *hw, u16 mbx_id) +{ + u32 vf_mailbox; + + UNREFERENCED_1PARAMETER(mbx_id); + + DEBUGFUNC("ixgbe_release_mbx_lock_vf"); + + /* Return ownership of the buffer */ + vf_mailbox = ixgbe_read_mailbox_vf(hw); + vf_mailbox &= ~IXGBE_VFMAILBOX_VFU; + IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox); +} + +/** + * ixgbe_write_mbx_vf_legacy - Write a message to the mailbox + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * @mbx_id: id of mailbox to write + * + * returns SUCCESS if it successfully copied message into the buffer + **/ +static s32 ixgbe_write_mbx_vf_legacy(struct ixgbe_hw *hw, u32 *msg, u16 size, + u16 mbx_id) +{ + s32 ret_val; + u16 i; + + UNREFERENCED_1PARAMETER(mbx_id); + DEBUGFUNC("ixgbe_write_mbx_vf_legacy"); + + /* lock the mailbox to prevent pf/vf race condition */ + ret_val = ixgbe_obtain_mbx_lock_vf(hw); + if (ret_val) + return ret_val; + + /* flush msg and acks as we are overwriting the message buffer */ + ixgbe_check_for_msg_vf(hw, 0); + ixgbe_clear_msg_vf(hw); + ixgbe_check_for_ack_vf(hw, 0); + ixgbe_clear_ack_vf(hw); + + /* copy the caller specified message to the mailbox memory buffer */ + for (i = 0; i < size; i++) + IXGBE_WRITE_REG_ARRAY(hw, IXGBE_VFMBMEM, i, msg[i]); + + /* update stats */ + hw->mbx.stats.msgs_tx++; + + /* interrupt the PF to tell it a message has been sent */ + IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_REQ); + + return IXGBE_SUCCESS; +} + /** * ixgbe_write_mbx_vf - Write a message to the mailbox * @hw: pointer to the HW structure @@ -426,6 +520,7 @@ static s32 ixgbe_obtain_mbx_lock_vf(struct ixgbe_hw *hw) static s32 ixgbe_write_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) { + u32 vf_mailbox; s32 ret_val; u16 i; @@ -436,11 +531,11 @@ static s32 ixgbe_write_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size, /* lock the mailbox to prevent pf/vf race condition */ ret_val = ixgbe_obtain_mbx_lock_vf(hw); if (ret_val) - goto out_no_write; + goto out; /* flush msg and acks as we are overwriting the message buffer */ - ixgbe_check_for_msg_vf(hw, 0); - ixgbe_check_for_ack_vf(hw, 0); + ixgbe_clear_msg_vf(hw); + ixgbe_clear_ack_vf(hw); /* copy the caller specified message to the mailbox memory buffer */ for (i = 0; i < size; i++) @@ -449,15 +544,22 @@ static s32 ixgbe_write_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size, /* update stats */ hw->mbx.stats.msgs_tx++; - /* Drop VFU and interrupt the PF to tell it a message has been sent */ - IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_REQ); + /* interrupt the PF to tell it a message has been sent */ + vf_mailbox = ixgbe_read_mailbox_vf(hw); + vf_mailbox |= IXGBE_VFMAILBOX_REQ; + IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox); + + /* if msg sent wait until we receive an ack */ + ixgbe_poll_for_ack(hw, mbx_id); + +out: + hw->mbx.ops[mbx_id].release(hw, mbx_id); -out_no_write: return ret_val; } /** - * ixgbe_read_mbx_vf - Reads a message from the inbox intended for vf + * ixgbe_read_mbx_vf_legacy - Reads a message from the inbox intended for vf * @hw: pointer to the HW structure * @msg: The message buffer * @size: Length of buffer @@ -465,19 +567,19 @@ out_no_write: * * returns SUCCESS if it successfully read message from buffer **/ -static s32 ixgbe_read_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size, - u16 mbx_id) +static s32 ixgbe_read_mbx_vf_legacy(struct ixgbe_hw *hw, u32 *msg, u16 size, + u16 mbx_id) { - s32 ret_val = IXGBE_SUCCESS; + s32 ret_val; u16 i; - DEBUGFUNC("ixgbe_read_mbx_vf"); + DEBUGFUNC("ixgbe_read_mbx_vf_legacy"); UNREFERENCED_1PARAMETER(mbx_id); /* lock the mailbox to prevent pf/vf race condition */ ret_val = ixgbe_obtain_mbx_lock_vf(hw); if (ret_val) - goto out_no_read; + return ret_val; /* copy the message from the mailbox memory buffer */ for (i = 0; i < size; i++) @@ -489,34 +591,73 @@ static s32 ixgbe_read_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size, /* update stats */ hw->mbx.stats.msgs_rx++; -out_no_read: - return ret_val; + return IXGBE_SUCCESS; +} + +/** + * ixgbe_read_mbx_vf - Reads a message from the inbox intended for vf + * @hw: pointer to the HW structure + * @msg: The message buffer + * @size: Length of buffer + * @mbx_id: id of mailbox to read + * + * returns SUCCESS if it successfully read message from buffer + **/ +static s32 ixgbe_read_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size, + u16 mbx_id) +{ + u32 vf_mailbox; + s32 ret_val; + u16 i; + + DEBUGFUNC("ixgbe_read_mbx_vf"); + UNREFERENCED_1PARAMETER(mbx_id); + + /* check if there is a message from PF */ + ret_val = ixgbe_check_for_msg_vf(hw, 0); + if (ret_val != IXGBE_SUCCESS) + return IXGBE_ERR_MBX_NOMSG; + + ixgbe_clear_msg_vf(hw); + + /* copy the message from the mailbox memory buffer */ + for (i = 0; i < size; i++) + msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_VFMBMEM, i); + + /* Acknowledge receipt */ + vf_mailbox = ixgbe_read_mailbox_vf(hw); + vf_mailbox |= IXGBE_VFMAILBOX_ACK; + IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, vf_mailbox); + + /* update stats */ + hw->mbx.stats.msgs_rx++; + + return IXGBE_SUCCESS; } /** * ixgbe_init_mbx_params_vf - set initial values for vf mailbox * @hw: pointer to the HW structure * - * Initializes the hw->mbx struct to correct values for vf mailbox + * Initializes single set the hw->mbx struct to correct values for vf mailbox + * Set of legacy functions is being used here */ void ixgbe_init_mbx_params_vf(struct ixgbe_hw *hw) { struct ixgbe_mbx_info *mbx = &hw->mbx; - /* start mailbox as timed out and let the reset_hw call set the timeout - * value to begin communications */ - mbx->timeout = 0; + mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT; mbx->usec_delay = IXGBE_VF_MBX_INIT_DELAY; mbx->size = IXGBE_VFMAILBOX_SIZE; - mbx->ops.read = ixgbe_read_mbx_vf; - mbx->ops.write = ixgbe_write_mbx_vf; - mbx->ops.read_posted = ixgbe_read_posted_mbx; - mbx->ops.write_posted = ixgbe_write_posted_mbx; - mbx->ops.check_for_msg = ixgbe_check_for_msg_vf; - mbx->ops.check_for_ack = ixgbe_check_for_ack_vf; - mbx->ops.check_for_rst = ixgbe_check_for_rst_vf; + /* VF has only one mailbox connection, no need for more IDs */ + mbx->ops[0].release = ixgbe_release_mbx_lock_dummy; + mbx->ops[0].read = ixgbe_read_mbx_vf_legacy; + mbx->ops[0].write = ixgbe_write_mbx_vf_legacy; + mbx->ops[0].check_for_msg = ixgbe_check_for_msg_vf; + mbx->ops[0].check_for_ack = ixgbe_check_for_ack_vf; + mbx->ops[0].check_for_rst = ixgbe_check_for_rst_vf; mbx->stats.msgs_tx = 0; mbx->stats.msgs_rx = 0; @@ -525,54 +666,110 @@ void ixgbe_init_mbx_params_vf(struct ixgbe_hw *hw) mbx->stats.rsts = 0; } +/** + * ixgbe_upgrade_mbx_params_vf - set initial values for vf mailbox + * @hw: pointer to the HW structure + * + * Initializes the hw->mbx struct to correct values for vf mailbox + */ +void ixgbe_upgrade_mbx_params_vf(struct ixgbe_hw *hw) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + + mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT; + mbx->usec_delay = IXGBE_VF_MBX_INIT_DELAY; + + mbx->size = IXGBE_VFMAILBOX_SIZE; + + /* VF has only one mailbox connection, no need for more IDs */ + mbx->ops[0].release = ixgbe_release_mbx_lock_vf; + mbx->ops[0].read = ixgbe_read_mbx_vf; + mbx->ops[0].write = ixgbe_write_mbx_vf; + mbx->ops[0].check_for_msg = ixgbe_check_for_msg_vf; + mbx->ops[0].check_for_ack = ixgbe_check_for_ack_vf; + mbx->ops[0].check_for_rst = ixgbe_check_for_rst_vf; + mbx->ops[0].clear = NULL; + + mbx->stats.msgs_tx = 0; + mbx->stats.msgs_rx = 0; + mbx->stats.reqs = 0; + mbx->stats.acks = 0; + mbx->stats.rsts = 0; +} + +static void ixgbe_clear_msg_pf(struct ixgbe_hw *hw, u16 vf_id) +{ + u32 vf_shift = IXGBE_PFMBICR_SHIFT(vf_id); + s32 index = IXGBE_PFMBICR_INDEX(vf_id); + u32 pfmbicr; + + pfmbicr = IXGBE_READ_REG(hw, IXGBE_PFMBICR(index)); + + if (pfmbicr & (IXGBE_PFMBICR_VFREQ_VF1 << vf_shift)) + hw->mbx.stats.reqs++; + + IXGBE_WRITE_REG(hw, IXGBE_PFMBICR(index), + IXGBE_PFMBICR_VFREQ_VF1 << vf_shift); +} + +static void ixgbe_clear_ack_pf(struct ixgbe_hw *hw, u16 vf_id) +{ + u32 vf_shift = IXGBE_PFMBICR_SHIFT(vf_id); + s32 index = IXGBE_PFMBICR_INDEX(vf_id); + u32 pfmbicr; + + pfmbicr = IXGBE_READ_REG(hw, IXGBE_PFMBICR(index)); + + if (pfmbicr & (IXGBE_PFMBICR_VFACK_VF1 << vf_shift)) + hw->mbx.stats.acks++; + + IXGBE_WRITE_REG(hw, IXGBE_PFMBICR(index), + IXGBE_PFMBICR_VFACK_VF1 << vf_shift); +} + static s32 ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index) { u32 pfmbicr = IXGBE_READ_REG(hw, IXGBE_PFMBICR(index)); - s32 ret_val = IXGBE_ERR_MBX; if (pfmbicr & mask) { - ret_val = IXGBE_SUCCESS; - IXGBE_WRITE_REG(hw, IXGBE_PFMBICR(index), mask); + return IXGBE_SUCCESS; } - return ret_val; + return IXGBE_ERR_MBX; } /** * ixgbe_check_for_msg_pf - checks to see if the VF has sent mail * @hw: pointer to the HW structure - * @vf_number: the VF index + * @vf_id: the VF index * * returns SUCCESS if the VF has set the Status bit or else ERR_MBX **/ -static s32 ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number) +static s32 ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_id) { - u32 vf_shift = IXGBE_PFMBICR_SHIFT(vf_number); - s32 index = IXGBE_PFMBICR_INDEX(vf_number); - s32 ret_val = IXGBE_ERR_MBX; + u32 vf_shift = IXGBE_PFMBICR_SHIFT(vf_id); + s32 index = IXGBE_PFMBICR_INDEX(vf_id); DEBUGFUNC("ixgbe_check_for_msg_pf"); if (!ixgbe_check_for_bit_pf(hw, IXGBE_PFMBICR_VFREQ_VF1 << vf_shift, - index)) { - ret_val = IXGBE_SUCCESS; - hw->mbx.stats.reqs++; - } + index)) + return IXGBE_SUCCESS; - return ret_val; + return IXGBE_ERR_MBX; } /** * ixgbe_check_for_ack_pf - checks to see if the VF has ACKed * @hw: pointer to the HW structure - * @vf_number: the VF index + * @vf_id: the VF index * * returns SUCCESS if the VF has set the Status bit or else ERR_MBX **/ -static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number) +static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_id) { - u32 vf_shift = IXGBE_PFMBICR_SHIFT(vf_number); - s32 index = IXGBE_PFMBICR_INDEX(vf_number); + u32 vf_shift = IXGBE_PFMBICR_SHIFT(vf_id); + s32 index = IXGBE_PFMBICR_INDEX(vf_id); s32 ret_val = IXGBE_ERR_MBX; DEBUGFUNC("ixgbe_check_for_ack_pf"); @@ -580,7 +777,8 @@ static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number) if (!ixgbe_check_for_bit_pf(hw, IXGBE_PFMBICR_VFACK_VF1 << vf_shift, index)) { ret_val = IXGBE_SUCCESS; - hw->mbx.stats.acks++; + /* TODO: should this be autocleared? */ + ixgbe_clear_ack_pf(hw, vf_id); } return ret_val; @@ -589,14 +787,14 @@ static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number) /** * ixgbe_check_for_rst_pf - checks to see if the VF has reset * @hw: pointer to the HW structure - * @vf_number: the VF index + * @vf_id: the VF index * * returns SUCCESS if the VF has set the Status bit or else ERR_MBX **/ -static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number) +static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_id) { - u32 vf_shift = IXGBE_PFVFLRE_SHIFT(vf_number); - u32 index = IXGBE_PFVFLRE_INDEX(vf_number); + u32 vf_shift = IXGBE_PFVFLRE_SHIFT(vf_id); + u32 index = IXGBE_PFVFLRE_INDEX(vf_id); s32 ret_val = IXGBE_ERR_MBX; u32 vflre = 0; @@ -628,121 +826,268 @@ static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number) /** * ixgbe_obtain_mbx_lock_pf - obtain mailbox lock * @hw: pointer to the HW structure - * @vf_number: the VF index + * @vf_id: the VF index * * return SUCCESS if we obtained the mailbox lock **/ -static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number) +static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_id) { + struct ixgbe_mbx_info *mbx = &hw->mbx; + int countdown = mbx->timeout; s32 ret_val = IXGBE_ERR_MBX; - u32 p2v_mailbox; + u32 pf_mailbox; DEBUGFUNC("ixgbe_obtain_mbx_lock_pf"); *** 576 LINES SKIPPED ***