예제 #1
0
파일: i40e_adminq.c 프로젝트: sdnnfv/dpdk-1
/**
 *  i40e_asq_send_command - send command to Admin Queue
 *  @hw: pointer to the hw struct
 *  @desc: prefilled descriptor describing the command (non DMA mem)
 *  @buff: buffer to use for indirect commands
 *  @buff_size: size of buffer for indirect commands
 *  @cmd_details: pointer to command details structure
 *
 *  This is the main send command driver routine for the Admin Queue send
 *  queue.  It runs the queue, cleans the queue, etc
 **/
enum i40e_status_code i40e_asq_send_command(struct i40e_hw *hw,
        struct i40e_aq_desc *desc,
        void *buff, /* can be NULL */
        u16  buff_size,
        struct i40e_asq_cmd_details *cmd_details)
{
    enum i40e_status_code status = I40E_SUCCESS;
    struct i40e_dma_mem *dma_buff = NULL;
    struct i40e_asq_cmd_details *details;
    struct i40e_aq_desc *desc_on_ring;
    bool cmd_completed = false;
    u16  retval = 0;
    u32  val = 0;

    val = rd32(hw, hw->aq.asq.head);
    if (val >= hw->aq.num_asq_entries) {
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
                   "AQTX: head overrun at %d\n", val);
        status = I40E_ERR_QUEUE_EMPTY;
        goto asq_send_command_exit;
    }

    if (hw->aq.asq.count == 0) {
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
                   "AQTX: Admin queue not initialized.\n");
        status = I40E_ERR_QUEUE_EMPTY;
        goto asq_send_command_exit;
    }

#ifndef VF_DRIVER
    if (i40e_is_nvm_update_op(desc) && hw->aq.nvm_busy) {
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: NVM busy.\n");
        status = I40E_ERR_NVM;
        goto asq_send_command_exit;
    }

#endif
    details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use);
    if (cmd_details) {
        i40e_memcpy(details,
                    cmd_details,
                    sizeof(struct i40e_asq_cmd_details),
                    I40E_NONDMA_TO_NONDMA);

        /* If the cmd_details are defined copy the cookie.  The
         * CPU_TO_LE32 is not needed here because the data is ignored
         * by the FW, only used by the driver
         */
        if (details->cookie) {
            desc->cookie_high =
                CPU_TO_LE32(I40E_HI_DWORD(details->cookie));
            desc->cookie_low =
                CPU_TO_LE32(I40E_LO_DWORD(details->cookie));
        }
    } else {
        i40e_memset(details, 0,
                    sizeof(struct i40e_asq_cmd_details),
                    I40E_NONDMA_MEM);
    }

    /* clear requested flags and then set additional flags if defined */
    desc->flags &= ~CPU_TO_LE16(details->flags_dis);
    desc->flags |= CPU_TO_LE16(details->flags_ena);

    i40e_acquire_spinlock(&hw->aq.asq_spinlock);

    if (buff_size > hw->aq.asq_buf_size) {
        i40e_debug(hw,
                   I40E_DEBUG_AQ_MESSAGE,
                   "AQTX: Invalid buffer size: %d.\n",
                   buff_size);
        status = I40E_ERR_INVALID_SIZE;
        goto asq_send_command_error;
    }

    if (details->postpone && !details->async) {
        i40e_debug(hw,
                   I40E_DEBUG_AQ_MESSAGE,
                   "AQTX: Async flag not set along with postpone flag");
        status = I40E_ERR_PARAM;
        goto asq_send_command_error;
    }

    /* call clean and check queue available function to reclaim the
     * descriptors that were processed by FW, the function returns the
     * number of desc available
     */
    /* the clean function called here could be called in a separate thread
     * in case of asynchronous completions
     */
    if (i40e_clean_asq(hw) == 0) {
        i40e_debug(hw,
                   I40E_DEBUG_AQ_MESSAGE,
                   "AQTX: Error queue is full.\n");
        status = I40E_ERR_ADMIN_QUEUE_FULL;
        goto asq_send_command_error;
    }

    /* initialize the temp desc pointer with the right desc */
    desc_on_ring = I40E_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use);

    /* if the desc is available copy the temp desc to the right place */
    i40e_memcpy(desc_on_ring, desc, sizeof(struct i40e_aq_desc),
                I40E_NONDMA_TO_DMA);

    /* if buff is not NULL assume indirect command */
    if (buff != NULL) {
        dma_buff = &(hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use]);
        /* copy the user buff into the respective DMA buff */
        i40e_memcpy(dma_buff->va, buff, buff_size,
                    I40E_NONDMA_TO_DMA);
        desc_on_ring->datalen = CPU_TO_LE16(buff_size);

        /* Update the address values in the desc with the pa value
         * for respective buffer
         */
        desc_on_ring->params.external.addr_high =
            CPU_TO_LE32(I40E_HI_DWORD(dma_buff->pa));
        desc_on_ring->params.external.addr_low =
            CPU_TO_LE32(I40E_LO_DWORD(dma_buff->pa));
    }

    /* bump the tail */
    i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n");
    i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring,
                  buff, buff_size);
    (hw->aq.asq.next_to_use)++;
    if (hw->aq.asq.next_to_use == hw->aq.asq.count)
        hw->aq.asq.next_to_use = 0;
    if (!details->postpone)
        wr32(hw, hw->aq.asq.tail, hw->aq.asq.next_to_use);

    /* if cmd_details are not defined or async flag is not set,
     * we need to wait for desc write back
     */
    if (!details->async && !details->postpone) {
        u32 total_delay = 0;

        do {
            /* AQ designers suggest use of head for better
             * timing reliability than DD bit
             */
            if (i40e_asq_done(hw))
                break;
            /* ugh! delay while spin_lock */
            i40e_msec_delay(1);
            total_delay++;
        } while (total_delay < hw->aq.asq_cmd_timeout);
    }

    /* if ready, copy the desc back to temp */
    if (i40e_asq_done(hw)) {
        i40e_memcpy(desc, desc_on_ring, sizeof(struct i40e_aq_desc),
                    I40E_DMA_TO_NONDMA);
        if (buff != NULL)
            i40e_memcpy(buff, dma_buff->va, buff_size,
                        I40E_DMA_TO_NONDMA);
        retval = LE16_TO_CPU(desc->retval);
        if (retval != 0) {
            i40e_debug(hw,
                       I40E_DEBUG_AQ_MESSAGE,
                       "AQTX: Command completed with error 0x%X.\n",
                       retval);

            /* strip off FW internal code */
            retval &= 0xff;
        }
        cmd_completed = true;
        if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_OK)
            status = I40E_SUCCESS;
        else
            status = I40E_ERR_ADMIN_QUEUE_ERROR;
        hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
    }

    i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
               "AQTX: desc and buffer writeback:\n");
    i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size);

    /* update the error if time out occurred */
    if ((!cmd_completed) &&
            (!details->async && !details->postpone)) {
        i40e_debug(hw,
                   I40E_DEBUG_AQ_MESSAGE,
                   "AQTX: Writeback timeout.\n");
        status = I40E_ERR_ADMIN_QUEUE_TIMEOUT;
    }

#ifndef VF_DRIVER
    if (!status && i40e_is_nvm_update_op(desc))
        hw->aq.nvm_busy = true;

#endif /* VF_DRIVER */
asq_send_command_error:
    i40e_release_spinlock(&hw->aq.asq_spinlock);
asq_send_command_exit:
    return status;
}
예제 #2
0
파일: i40e_adminq.c 프로젝트: btw616/dpdk
/**
 *  i40e_init_adminq - main initialization routine for Admin Queue
 *  @hw: pointer to the hardware structure
 *
 *  Prior to calling this function, drivers *MUST* set the following fields
 *  in the hw->aq structure:
 *     - hw->aq.num_asq_entries
 *     - hw->aq.num_arq_entries
 *     - hw->aq.arq_buf_size
 *     - hw->aq.asq_buf_size
 **/
enum i40e_status_code i40e_init_adminq(struct i40e_hw *hw)
{
#ifdef PF_DRIVER
	u16 cfg_ptr, oem_hi, oem_lo;
	u16 eetrack_lo, eetrack_hi;
#endif
	enum i40e_status_code ret_code;
#ifdef PF_DRIVER
	int retry = 0;
#endif

	/* verify input for valid configuration */
	if ((hw->aq.num_arq_entries == 0) ||
	    (hw->aq.num_asq_entries == 0) ||
	    (hw->aq.arq_buf_size == 0) ||
	    (hw->aq.asq_buf_size == 0)) {
		ret_code = I40E_ERR_CONFIG;
		goto init_adminq_exit;
	}
	i40e_init_spinlock(&hw->aq.asq_spinlock);
	i40e_init_spinlock(&hw->aq.arq_spinlock);

	/* Set up register offsets */
	i40e_adminq_init_regs(hw);

	/* setup ASQ command write back timeout */
	hw->aq.asq_cmd_timeout = I40E_ASQ_CMD_TIMEOUT;

	/* allocate the ASQ */
	ret_code = i40e_init_asq(hw);
	if (ret_code != I40E_SUCCESS)
		goto init_adminq_destroy_spinlocks;

	/* allocate the ARQ */
	ret_code = i40e_init_arq(hw);
	if (ret_code != I40E_SUCCESS)
		goto init_adminq_free_asq;

#ifdef PF_DRIVER
#ifdef INTEGRATED_VF
	/* VF has no need of firmware */
	if (i40e_is_vf(hw))
		goto init_adminq_exit;
#endif
	/* There are some cases where the firmware may not be quite ready
	 * for AdminQ operations, so we retry the AdminQ setup a few times
	 * if we see timeouts in this first AQ call.
	 */
	do {
		ret_code = i40e_aq_get_firmware_version(hw,
							&hw->aq.fw_maj_ver,
							&hw->aq.fw_min_ver,
							&hw->aq.fw_build,
							&hw->aq.api_maj_ver,
							&hw->aq.api_min_ver,
							NULL);
		if (ret_code != I40E_ERR_ADMIN_QUEUE_TIMEOUT)
			break;
		retry++;
		i40e_msec_delay(100);
		i40e_resume_aq(hw);
	} while (retry < 10);
	if (ret_code != I40E_SUCCESS)
		goto init_adminq_free_arq;

	/* get the NVM version info */
	i40e_read_nvm_word(hw, I40E_SR_NVM_DEV_STARTER_VERSION,
			   &hw->nvm.version);
	i40e_read_nvm_word(hw, I40E_SR_NVM_EETRACK_LO, &eetrack_lo);
	i40e_read_nvm_word(hw, I40E_SR_NVM_EETRACK_HI, &eetrack_hi);
	hw->nvm.eetrack = (eetrack_hi << 16) | eetrack_lo;
	i40e_read_nvm_word(hw, I40E_SR_BOOT_CONFIG_PTR, &cfg_ptr);
	i40e_read_nvm_word(hw, (cfg_ptr + I40E_NVM_OEM_VER_OFF),
			   &oem_hi);
	i40e_read_nvm_word(hw, (cfg_ptr + (I40E_NVM_OEM_VER_OFF + 1)),
			   &oem_lo);
	hw->nvm.oem_ver = ((u32)oem_hi << 16) | oem_lo;

	/* The ability to RX (not drop) 802.1ad frames was added in API 1.7 */
	if ((hw->aq.api_maj_ver > 1) ||
	    ((hw->aq.api_maj_ver == 1) &&
	     (hw->aq.api_min_ver >= 7)))
		hw->flags |= I40E_HW_FLAG_802_1AD_CAPABLE;

	if (hw->mac.type == I40E_MAC_XL710 &&
	    hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
	    hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) {
		hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE;
		hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE;
	}
	if (hw->mac.type == I40E_MAC_X722 &&
	    hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
	    hw->aq.api_min_ver >= I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722) {
		hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE;
	}

	/* Newer versions of firmware require lock when reading the NVM */
	if ((hw->aq.api_maj_ver > 1) ||
	    ((hw->aq.api_maj_ver == 1) &&
	     (hw->aq.api_min_ver >= 5)))
		hw->flags |= I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK;

	if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) {
		ret_code = I40E_ERR_FIRMWARE_API_VERSION;
		goto init_adminq_free_arq;
	}

	/* pre-emptive resource lock release */
	i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
	hw->nvm_release_on_done = false;
	hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;

#endif /* PF_DRIVER */
	ret_code = I40E_SUCCESS;

	/* success! */
	goto init_adminq_exit;

#ifdef PF_DRIVER
init_adminq_free_arq:
	i40e_shutdown_arq(hw);
#endif
init_adminq_free_asq:
	i40e_shutdown_asq(hw);
init_adminq_destroy_spinlocks:
	i40e_destroy_spinlock(&hw->aq.asq_spinlock);
	i40e_destroy_spinlock(&hw->aq.arq_spinlock);

init_adminq_exit:
	return ret_code;
}
예제 #3
0
파일: i40e_adminq.c 프로젝트: sdnnfv/dpdk-1
/**
 *  i40e_init_adminq - main initialization routine for Admin Queue
 *  @hw: pointer to the hardware structure
 *
 *  Prior to calling this function, drivers *MUST* set the following fields
 *  in the hw->aq structure:
 *     - hw->aq.num_asq_entries
 *     - hw->aq.num_arq_entries
 *     - hw->aq.arq_buf_size
 *     - hw->aq.asq_buf_size
 **/
enum i40e_status_code i40e_init_adminq(struct i40e_hw *hw)
{
    enum i40e_status_code ret_code;
#ifndef VF_DRIVER
    u16 eetrack_lo, eetrack_hi;
    int retry = 0;
#endif

    /* verify input for valid configuration */
    if ((hw->aq.num_arq_entries == 0) ||
            (hw->aq.num_asq_entries == 0) ||
            (hw->aq.arq_buf_size == 0) ||
            (hw->aq.asq_buf_size == 0)) {
        ret_code = I40E_ERR_CONFIG;
        goto init_adminq_exit;
    }

    /* initialize spin locks */
    i40e_init_spinlock(&hw->aq.asq_spinlock);
    i40e_init_spinlock(&hw->aq.arq_spinlock);

    /* Set up register offsets */
    i40e_adminq_init_regs(hw);

    /* setup ASQ command write back timeout */
    hw->aq.asq_cmd_timeout = I40E_ASQ_CMD_TIMEOUT;

    /* allocate the ASQ */
    ret_code = i40e_init_asq(hw);
    if (ret_code != I40E_SUCCESS)
        goto init_adminq_destroy_spinlocks;

    /* allocate the ARQ */
    ret_code = i40e_init_arq(hw);
    if (ret_code != I40E_SUCCESS)
        goto init_adminq_free_asq;

#ifndef VF_DRIVER
    /* There are some cases where the firmware may not be quite ready
     * for AdminQ operations, so we retry the AdminQ setup a few times
     * if we see timeouts in this first AQ call.
     */
    do {
        ret_code = i40e_aq_get_firmware_version(hw,
                                                &hw->aq.fw_maj_ver,
                                                &hw->aq.fw_min_ver,
                                                &hw->aq.api_maj_ver,
                                                &hw->aq.api_min_ver,
                                                NULL);
        if (ret_code != I40E_ERR_ADMIN_QUEUE_TIMEOUT)
            break;
        retry++;
        i40e_msec_delay(100);
        i40e_resume_aq(hw);
    } while (retry < 10);
    if (ret_code != I40E_SUCCESS)
        goto init_adminq_free_arq;

    /* get the NVM version info */
    i40e_read_nvm_word(hw, I40E_SR_NVM_IMAGE_VERSION, &hw->nvm.version);
    i40e_read_nvm_word(hw, I40E_SR_NVM_EETRACK_LO, &eetrack_lo);
    i40e_read_nvm_word(hw, I40E_SR_NVM_EETRACK_HI, &eetrack_hi);
    hw->nvm.eetrack = (eetrack_hi << 16) | eetrack_lo;

    if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) {
        ret_code = I40E_ERR_FIRMWARE_API_VERSION;
        goto init_adminq_free_arq;
    }

    /* pre-emptive resource lock release */
    i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
    hw->aq.nvm_busy = false;

    ret_code = i40e_aq_set_hmc_resource_profile(hw,
               I40E_HMC_PROFILE_DEFAULT,
               0,
               NULL);
    ret_code = I40E_SUCCESS;

#endif /* VF_DRIVER */
    /* success! */
    goto init_adminq_exit;

#ifndef VF_DRIVER
init_adminq_free_arq:
    i40e_shutdown_arq(hw);
#endif
init_adminq_free_asq:
    i40e_shutdown_asq(hw);
init_adminq_destroy_spinlocks:
    i40e_destroy_spinlock(&hw->aq.asq_spinlock);
    i40e_destroy_spinlock(&hw->aq.arq_spinlock);

init_adminq_exit:
    return ret_code;
}