Exemple #1
0
	__checkReturn	efx_rc_t
siena_nic_register_test(
	__in		efx_nic_t *enp)
{
	efx_register_set_t *rsp;
	const uint32_t *dwordp;
	unsigned int nitems;
	unsigned int count;
	efx_rc_t rc;

	/* Fill out the register mask entries */
	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_register_masks)
		    == EFX_ARRAY_SIZE(__siena_registers) * 4);

	nitems = EFX_ARRAY_SIZE(__siena_registers);
	dwordp = __siena_register_masks;
	for (count = 0; count < nitems; ++count) {
		rsp = __siena_registers + count;
		rsp->mask.eo_u32[0] = *dwordp++;
		rsp->mask.eo_u32[1] = *dwordp++;
		rsp->mask.eo_u32[2] = *dwordp++;
		rsp->mask.eo_u32[3] = *dwordp++;
	}

	/* Fill out the register table entries */
	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_table_masks)
		    == EFX_ARRAY_SIZE(__siena_tables) * 4);

	nitems = EFX_ARRAY_SIZE(__siena_tables);
	dwordp = __siena_table_masks;
	for (count = 0; count < nitems; ++count) {
		rsp = __siena_tables + count;
		rsp->mask.eo_u32[0] = *dwordp++;
		rsp->mask.eo_u32[1] = *dwordp++;
		rsp->mask.eo_u32[2] = *dwordp++;
		rsp->mask.eo_u32[3] = *dwordp++;
	}

	if ((rc = efx_nic_test_registers(enp, __siena_registers,
	    EFX_ARRAY_SIZE(__siena_registers))) != 0)
		goto fail1;

	if ((rc = efx_nic_test_tables(enp, __siena_tables,
	    EFX_PATTERN_BYTE_ALTERNATE,
	    EFX_ARRAY_SIZE(__siena_tables))) != 0)
		goto fail2;

	if ((rc = efx_nic_test_tables(enp, __siena_tables,
	    EFX_PATTERN_BYTE_CHANGING,
	    EFX_ARRAY_SIZE(__siena_tables))) != 0)
		goto fail3;

	if ((rc = efx_nic_test_tables(enp, __siena_tables,
	    EFX_PATTERN_BIT_SWEEP, EFX_ARRAY_SIZE(__siena_tables))) != 0)
		goto fail4;

	return (0);

fail4:
	EFSYS_PROBE(fail4);
fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
Exemple #2
0
	__checkReturn	efx_rc_t
siena_phy_reconfigure(
	__in		efx_nic_t *enp)
{
	efx_port_t *epp = &(enp->en_port);
	efx_mcdi_req_t req;
	uint8_t payload[MAX(MAX(MC_CMD_SET_ID_LED_IN_LEN,
				MC_CMD_SET_ID_LED_OUT_LEN),
			    MAX(MC_CMD_SET_LINK_IN_LEN,
				MC_CMD_SET_LINK_OUT_LEN))];
	uint32_t cap_mask;
	unsigned int led_mode;
	unsigned int speed;
	efx_rc_t rc;

	(void) memset(payload, 0, sizeof (payload));
	req.emr_cmd = MC_CMD_SET_LINK;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
	req.emr_out_buf = payload;
	req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;

	cap_mask = epp->ep_adv_cap_mask;
	MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
		PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
		PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
		PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
		PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
		PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
		PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
		PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
		PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
		PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
		PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);

#if EFSYS_OPT_LOOPBACK
	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
		    epp->ep_loopback_type);
	switch (epp->ep_loopback_link_mode) {
	case EFX_LINK_100FDX:
		speed = 100;
		break;
	case EFX_LINK_1000FDX:
		speed = 1000;
		break;
	case EFX_LINK_10000FDX:
		speed = 10000;
		break;
	default:
		speed = 0;
	}
#else
	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
	speed = 0;
#endif	/* EFSYS_OPT_LOOPBACK */
	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);

#if EFSYS_OPT_PHY_FLAGS
	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
#else
	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
#endif	/* EFSYS_OPT_PHY_FLAGS */

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail1;
	}

	/* And set the blink mode */
	(void) memset(payload, 0, sizeof (payload));
	req.emr_cmd = MC_CMD_SET_ID_LED;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
	req.emr_out_buf = payload;
	req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;

#if EFSYS_OPT_PHY_LED_CONTROL
	switch (epp->ep_phy_led_mode) {
	case EFX_PHY_LED_DEFAULT:
		led_mode = MC_CMD_LED_DEFAULT;
		break;
	case EFX_PHY_LED_OFF:
		led_mode = MC_CMD_LED_OFF;
		break;
	case EFX_PHY_LED_ON:
		led_mode = MC_CMD_LED_ON;
		break;
	default:
		EFSYS_ASSERT(0);
		led_mode = MC_CMD_LED_DEFAULT;
	}

	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
#else
	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
#endif	/* EFSYS_OPT_PHY_LED_CONTROL */

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail2;
	}

	return (0);

fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
	__checkReturn	efx_rc_t
medford_board_cfg(
	__in		efx_nic_t *enp)
{
	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
	uint32_t sysclk, dpcpu_clk;
	uint32_t end_padding;
	uint32_t bandwidth;
	efx_rc_t rc;

	/*
	 * Enable firmware workarounds for hardware errata.
	 * Expected responses are:
	 *  - 0 (zero):
	 *	Success: workaround enabled or disabled as requested.
	 *  - MC_CMD_ERR_ENOSYS (reported as ENOTSUP):
	 *	Firmware does not support the MC_CMD_WORKAROUND request.
	 *	(assume that the workaround is not supported).
	 *  - MC_CMD_ERR_ENOENT (reported as ENOENT):
	 *	Firmware does not support the requested workaround.
	 *  - MC_CMD_ERR_EPERM  (reported as EACCES):
	 *	Unprivileged function cannot enable/disable workarounds.
	 *
	 * See efx_mcdi_request_errcode() for MCDI error translations.
	 */


	if (EFX_PCI_FUNCTION_IS_VF(encp)) {
		/*
		 * Interrupt testing does not work for VFs. See bug50084 and
		 * bug71432 comment 21.
		 */
		encp->enc_bug41750_workaround = B_TRUE;
	}

	/* Chained multicast is always enabled on Medford */
	encp->enc_bug26807_workaround = B_TRUE;

	/*
	 * If the bug61265 workaround is enabled, then interrupt holdoff timers
	 * cannot be controlled by timer table writes, so MCDI must be used
	 * (timer table writes can still be used for wakeup timers).
	 */
	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG61265, B_TRUE,
	    NULL);
	if ((rc == 0) || (rc == EACCES))
		encp->enc_bug61265_workaround = B_TRUE;
	else if ((rc == ENOTSUP) || (rc == ENOENT))
		encp->enc_bug61265_workaround = B_FALSE;
	else
		goto fail1;

	/* Checksums for TSO sends can be incorrect on Medford. */
	encp->enc_bug61297_workaround = B_TRUE;

	/* Get clock frequencies (in MHz). */
	if ((rc = efx_mcdi_get_clock(enp, &sysclk, &dpcpu_clk)) != 0)
		goto fail2;

	/*
	 * The Medford timer quantum is 1536 dpcpu_clk cycles, documented for
	 * the EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units.
	 */
	encp->enc_evq_timer_quantum_ns = 1536000UL / dpcpu_clk; /* 1536 cycles */
	encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
		    FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;

	/* Alignment for receive packet DMA buffers */
	encp->enc_rx_buf_align_start = 1;

	/* Get the RX DMA end padding alignment configuration */
	if ((rc = efx_mcdi_get_rxdp_config(enp, &end_padding)) != 0) {
		if (rc != EACCES)
			goto fail3;

		/* Assume largest tail padding size supported by hardware */
		end_padding = 256;
	}
	encp->enc_rx_buf_align_end = end_padding;

	/*
	 * The maximum supported transmit queue size is 2048. TXQs with 4096
	 * descriptors are not supported as the top bit is used for vfifo
	 * stuffing.
	 */
	encp->enc_txq_max_ndescs = 2048;

	EFX_STATIC_ASSERT(MEDFORD_PIOBUF_NBUFS <= EF10_MAX_PIOBUF_NBUFS);
	encp->enc_piobuf_limit = MEDFORD_PIOBUF_NBUFS;
	encp->enc_piobuf_size = MEDFORD_PIOBUF_SIZE;
	encp->enc_piobuf_min_alloc_size = MEDFORD_MIN_PIO_ALLOC_SIZE;

	/*
	 * Medford stores a single global copy of VPD, not per-PF as on
	 * Huntington.
	 */
	encp->enc_vpd_is_global = B_TRUE;

	rc = medford_nic_get_required_pcie_bandwidth(enp, &bandwidth);
	if (rc != 0)
		goto fail4;
	encp->enc_required_pcie_bandwidth_mbps = bandwidth;
	encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN3;

	return (0);

fail4:
	EFSYS_PROBE(fail4);
fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
Exemple #4
0
	__checkReturn	int
hunt_phy_get_link(
	__in		efx_nic_t *enp,
	__out		hunt_link_state_t *hlsp)
{
	/*
	 * TBD: consider common Siena/Hunt function: Hunt is very similar
	 * (at least for now; not clear that the loopbacks should necessarily
	 * be quite the same...)
	 */

	efx_mcdi_req_t req;
	uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN,
			    MC_CMD_GET_LINK_OUT_LEN)];
	int rc;

	(void) memset(payload, 0, sizeof (payload));
	req.emr_cmd = MC_CMD_GET_LINK;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
	req.emr_out_buf = payload;
	req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN;

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail1;
	}

	if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
		rc = EMSGSIZE;
		goto fail2;
	}

	hunt_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
			    &hlsp->hls_adv_cap_mask);
	hunt_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
			    &hlsp->hls_lp_cap_mask);

	hunt_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
			    MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
			    MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
			    &hlsp->hls_link_mode, &hlsp->hls_fcntl);

#if EFSYS_OPT_LOOPBACK
	/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);

	hlsp->hls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
#endif	/* EFSYS_OPT_LOOPBACK */

	hlsp->hls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;

	return (0);

fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, int, rc);

	return (rc);
}
Exemple #5
0
	__checkReturn	efx_rc_t
efx_nic_biu_test(
	__in		efx_nic_t *enp)
{
	efx_oword_t oword;
	efx_rc_t rc;

	/*
	 * Write magic values to scratch registers 0 and 1, then
	 * verify that the values were written correctly.  Interleave
	 * the accesses to ensure that the BIU is not just reading
	 * back the cached value that was last written.
	 */
	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);

	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);

	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
		rc = EIO;
		goto fail1;
	}

	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
		rc = EIO;
		goto fail2;
	}

	/*
	 * Perform the same test, with the values swapped.  This
	 * ensures that subsequent tests don't start with the correct
	 * values already written into the scratch registers.
	 */
	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);

	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);

	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
		rc = EIO;
		goto fail3;
	}

	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
		rc = EIO;
		goto fail4;
	}

	return (0);

fail4:
	EFSYS_PROBE(fail4);
fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
Exemple #6
0
static	__checkReturn	int
efx_mcdi_init_evq(
    __in		efx_nic_t *enp,
    __in		unsigned int instance,
    __in		efsys_mem_t *esmp,
    __in		size_t nevs,
    __in		uint32_t irq,
    __out_opt	uint32_t *irqp)
{
    efx_mcdi_req_t req;
    uint8_t payload[
        MAX(MC_CMD_INIT_EVQ_IN_LEN(EFX_EVQ_NBUFS(EFX_EVQ_MAXNEVS)),
            MC_CMD_INIT_EVQ_OUT_LEN)];
    efx_qword_t *dma_addr;
    uint64_t addr;
    int npages;
    int i;
    int supports_rx_batching;
    int rc;

    npages = EFX_EVQ_NBUFS(nevs);
    if (MC_CMD_INIT_EVQ_IN_LEN(npages) > MC_CMD_INIT_EVQ_IN_LENMAX) {
        rc = EINVAL;
        goto fail1;
    }

    (void) memset(payload, 0, sizeof (payload));
    req.emr_cmd = MC_CMD_INIT_EVQ;
    req.emr_in_buf = payload;
    req.emr_in_length = MC_CMD_INIT_EVQ_IN_LEN(npages);
    req.emr_out_buf = payload;
    req.emr_out_length = MC_CMD_INIT_EVQ_OUT_LEN;

    MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_SIZE, nevs);
    MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_INSTANCE, instance);
    MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_IRQ_NUM, irq);

    /*
     * On Huntington RX and TX event batching can only be requested
     * together (even if the datapath firmware doesn't actually support RX
     * batching).
     * Cut through is incompatible with RX batching and so enabling cut
     * through disables RX batching (but it does not affect TX batching).
     *
     * So always enable RX and TX event batching, and enable cut through
     * if RX event batching isn't supported (i.e. on low latency firmware).
     */
    supports_rx_batching = enp->en_nic_cfg.enc_rx_batching_enabled ? 1 : 0;
    MCDI_IN_POPULATE_DWORD_6(req, INIT_EVQ_IN_FLAGS,
                             INIT_EVQ_IN_FLAG_INTERRUPTING, 1,
                             INIT_EVQ_IN_FLAG_RPTR_DOS, 0,
                             INIT_EVQ_IN_FLAG_INT_ARMD, 0,
                             INIT_EVQ_IN_FLAG_CUT_THRU, !supports_rx_batching,
                             INIT_EVQ_IN_FLAG_RX_MERGE, 1,
                             INIT_EVQ_IN_FLAG_TX_MERGE, 1);

    MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_MODE,
                      MC_CMD_INIT_EVQ_IN_TMR_MODE_DIS);
    MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_LOAD, 0);
    MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_RELOAD, 0);

    MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_MODE,
                      MC_CMD_INIT_EVQ_IN_COUNT_MODE_DIS);
    MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_THRSHLD, 0);

    dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_IN_DMA_ADDR);
    addr = EFSYS_MEM_ADDR(esmp);

    for (i = 0; i < npages; i++) {
        EFX_POPULATE_QWORD_2(*dma_addr,
                             EFX_DWORD_1, (uint32_t)(addr >> 32),
                             EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));

        dma_addr++;
        addr += EFX_BUF_SIZE;
    }

    efx_mcdi_execute(enp, &req);

    if (req.emr_rc != 0) {
        rc = req.emr_rc;
        goto fail2;
    }

    if (req.emr_out_length_used < MC_CMD_INIT_EVQ_OUT_LEN) {
        rc = EMSGSIZE;
        goto fail3;
    }

    if (irqp != NULL)
        *irqp = MCDI_OUT_DWORD(req, INIT_EVQ_OUT_IRQ);

    return (0);

fail3:
    EFSYS_PROBE(fail3);
fail2:
    EFSYS_PROBE(fail2);
fail1:
    EFSYS_PROBE1(fail1, int, rc);

    return (rc);
}
Exemple #7
0
	__checkReturn	int
efx_tx_init(
	__in		efx_nic_t *enp)
{
	efx_oword_t oword;
	int rc;

	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);

	if (!(enp->en_mod_flags & EFX_MOD_EV)) {
		rc = EINVAL;
		goto fail1;
	}

	if (enp->en_mod_flags & EFX_MOD_TX) {
		rc = EINVAL;
		goto fail2;
	}

	EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);

	/*
	 * Disable the timer-based TX DMA backoff and allow TX DMA to be
	 * controlled by the RX FIFO fill level (although always allow a
	 * minimal trickle).
	 */
	EFX_BAR_READO(enp, FR_AZ_TX_RESERVED_REG, &oword);
	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER, 0xfe);
	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER_EN, 1);
	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PUSH_EN, 0);
	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DIS_NON_IP_EV, 1);
	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_THRESHOLD, 2);
	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff);

	/*
	 * Filter all packets less than 14 bytes to avoid parsing
	 * errors.
	 */
	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
	EFX_BAR_WRITEO(enp, FR_AZ_TX_RESERVED_REG, &oword);

	/*
	 * Do not set TX_NO_EOP_DISC_EN, since it limits packets to 16
	 * descriptors (which is bad).
	 */
	EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_NO_EOP_DISC_EN, 0);
	EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);

	enp->en_mod_flags |= EFX_MOD_TX;
	return (0);

fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, int, rc);

	return (rc);
}
Exemple #8
0
	__checkReturn	efx_rc_t
siena_sram_test(
	__in		efx_nic_t *enp,
	__in		efx_sram_pattern_fn_t func)
{
	efx_oword_t oword;
	efx_qword_t qword;
	efx_qword_t verify;
	size_t rows;
	unsigned int wptr;
	unsigned int rptr;
	efx_rc_t rc;

	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);

	/* Reconfigure into HALF buffer table mode */
	EFX_POPULATE_OWORD_1(oword, FRF_AZ_BUF_TBL_MODE, 0);
	EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_CFG_REG, &oword);

	/*
	 * Move the descriptor caches up to the top of SRAM, and test
	 * all of SRAM below them. We only miss out one row here.
	 */
	rows = SIENA_SRAM_ROWS - 1;
	EFX_POPULATE_OWORD_1(oword, FRF_AZ_SRM_RX_DC_BASE_ADR, rows);
	EFX_BAR_WRITEO(enp, FR_AZ_SRM_RX_DC_CFG_REG, &oword);

	EFX_POPULATE_OWORD_1(oword, FRF_AZ_SRM_TX_DC_BASE_ADR, rows + 1);
	EFX_BAR_WRITEO(enp, FR_AZ_SRM_TX_DC_CFG_REG, &oword);

	/*
	 * Write the pattern through BUF_HALF_TBL. Write
	 * in 64 entry batches, waiting 1us in between each batch
	 * to guarantee not to overflow the SRAM fifo
	 */
	for (wptr = 0, rptr = 0; wptr < rows; ++wptr) {
		func(wptr, B_FALSE, &qword);
		EFX_BAR_TBL_WRITEQ(enp, FR_AZ_BUF_HALF_TBL, wptr, &qword);

		if ((wptr - rptr) < 64 && wptr < rows - 1)
			continue;

		EFSYS_SPIN(1);

		for (; rptr <= wptr; ++rptr) {
			func(rptr, B_FALSE, &qword);
			EFX_BAR_TBL_READQ(enp, FR_AZ_BUF_HALF_TBL, rptr,
			    &verify);

			if (!EFX_QWORD_IS_EQUAL(verify, qword)) {
				rc = EFAULT;
				goto fail1;
			}
		}
	}

	/* And do the same negated */
	for (wptr = 0, rptr = 0; wptr < rows; ++wptr) {
		func(wptr, B_TRUE, &qword);
		EFX_BAR_TBL_WRITEQ(enp, FR_AZ_BUF_HALF_TBL, wptr, &qword);

		if ((wptr - rptr) < 64 && wptr < rows - 1)
			continue;

		EFSYS_SPIN(1);

		for (; rptr <= wptr; ++rptr) {
			func(rptr, B_TRUE, &qword);
			EFX_BAR_TBL_READQ(enp, FR_AZ_BUF_HALF_TBL, rptr,
			    &verify);

			if (!EFX_QWORD_IS_EQUAL(verify, qword)) {
				rc = EFAULT;
				goto fail2;
			}
		}
	}

	/* Restore back to FULL buffer table mode */
	EFX_POPULATE_OWORD_1(oword, FRF_AZ_BUF_TBL_MODE, 1);
	EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_CFG_REG, &oword);

	/*
	 * We don't need to reconfigure SRAM again because the API
	 * requires efx_nic_fini() to be called after an sram test.
	 */
	return (0);

fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	/* Restore back to FULL buffer table mode */
	EFX_POPULATE_OWORD_1(oword, FRF_AZ_BUF_TBL_MODE, 1);
	EFX_BAR_WRITEO(enp, FR_AZ_BUF_TBL_CFG_REG, &oword);

	return (rc);
}
Exemple #9
0
	__checkReturn	efx_rc_t
efx_mcdi_init(
	__in		efx_nic_t *enp,
	__in		const efx_mcdi_transport_t *emtp)
{
	efx_mcdi_ops_t *emcop;
	efx_rc_t rc;

	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
	EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);

	switch (enp->en_family) {
#if EFSYS_OPT_FALCON
	case EFX_FAMILY_FALCON:
		emcop = NULL;
		emtp = NULL;
		break;
#endif	/* EFSYS_OPT_FALCON */

#if EFSYS_OPT_SIENA
	case EFX_FAMILY_SIENA:
		emcop = (efx_mcdi_ops_t *)&__efx_mcdi_siena_ops;
		break;
#endif	/* EFSYS_OPT_SIENA */

#if EFSYS_OPT_HUNTINGTON
	case EFX_FAMILY_HUNTINGTON:
		emcop = (efx_mcdi_ops_t *)&__efx_mcdi_hunt_ops;
		break;
#endif	/* EFSYS_OPT_HUNTINGTON */

	default:
		EFSYS_ASSERT(0);
		rc = ENOTSUP;
		goto fail1;
	}

	if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
		/* MCDI requires a DMA buffer in host memory */
		if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
			rc = EINVAL;
			goto fail2;
		}
	}
	enp->en_mcdi.em_emtp = emtp;

	if (emcop != NULL && emcop->emco_init != NULL) {
		if ((rc = emcop->emco_init(enp, emtp)) != 0)
			goto fail3;
	}

	enp->en_mcdi.em_emcop = emcop;
	enp->en_mod_flags |= EFX_MOD_MCDI;

	return (0);

fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	enp->en_mcdi.em_emcop = NULL;
	enp->en_mcdi.em_emtp = NULL;
	enp->en_mod_flags &= ~EFX_MOD_MCDI;

	return (rc);
}
Exemple #10
0
static	__checkReturn	efx_rc_t
efx_mcdi_init_txq(
	__in		efx_nic_t *enp,
	__in		uint32_t size,
	__in		uint32_t target_evq,
	__in		uint32_t label,
	__in		uint32_t instance,
	__in		uint16_t flags,
	__in		efsys_mem_t *esmp)
{
	efx_mcdi_req_t req;
	uint8_t payload[MAX(MC_CMD_INIT_TXQ_IN_LEN(EFX_TXQ_MAX_BUFS),
			    MC_CMD_INIT_TXQ_OUT_LEN)];
	efx_qword_t *dma_addr;
	uint64_t addr;
	int npages;
	int i;
	efx_rc_t rc;

	EFSYS_ASSERT(EFX_TXQ_MAX_BUFS >=
	    EFX_TXQ_NBUFS(enp->en_nic_cfg.enc_txq_max_ndescs));

	npages = EFX_TXQ_NBUFS(size);
	if (npages > MC_CMD_INIT_TXQ_IN_DMA_ADDR_MAXNUM) {
		rc = EINVAL;
		goto fail1;
	}

	(void) memset(payload, 0, sizeof (payload));
	req.emr_cmd = MC_CMD_INIT_TXQ;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_INIT_TXQ_IN_LEN(npages);
	req.emr_out_buf = payload;
	req.emr_out_length = MC_CMD_INIT_TXQ_OUT_LEN;

	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_SIZE, size);
	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_TARGET_EVQ, target_evq);
	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_LABEL, label);
	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_INSTANCE, instance);

	MCDI_IN_POPULATE_DWORD_7(req, INIT_TXQ_IN_FLAGS,
	    INIT_TXQ_IN_FLAG_BUFF_MODE, 0,
	    INIT_TXQ_IN_FLAG_IP_CSUM_DIS,
	    (flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1,
	    INIT_TXQ_IN_FLAG_TCP_CSUM_DIS,
	    (flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1,
	    INIT_TXQ_EXT_IN_FLAG_TSOV2_EN, (flags & EFX_TXQ_FATSOV2) ? 1 : 0,
	    INIT_TXQ_IN_FLAG_TCP_UDP_ONLY, 0,
	    INIT_TXQ_IN_CRC_MODE, 0,
	    INIT_TXQ_IN_FLAG_TIMESTAMP, 0);

	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_OWNER_ID, 0);
	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);

	dma_addr = MCDI_IN2(req, efx_qword_t, INIT_TXQ_IN_DMA_ADDR);
	addr = EFSYS_MEM_ADDR(esmp);

	for (i = 0; i < npages; i++) {
		EFX_POPULATE_QWORD_2(*dma_addr,
		    EFX_DWORD_1, (uint32_t)(addr >> 32),
		    EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));

		dma_addr++;
		addr += EFX_BUF_SIZE;
	}

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail2;
	}

	return (0);

fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
Exemple #11
0
	__checkReturn	efx_rc_t
hunt_board_cfg(
	__in		efx_nic_t *enp)
{
	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
	efx_port_t *epp = &(enp->en_port);
	uint32_t flags;
	uint32_t sysclk, dpcpu_clk;
	uint32_t bandwidth;
	efx_rc_t rc;

	/*
	 * Enable firmware workarounds for hardware errata.
	 * Expected responses are:
	 *  - 0 (zero):
	 *	Success: workaround enabled or disabled as requested.
	 *  - MC_CMD_ERR_ENOSYS (reported as ENOTSUP):
	 *	Firmware does not support the MC_CMD_WORKAROUND request.
	 *	(assume that the workaround is not supported).
	 *  - MC_CMD_ERR_ENOENT (reported as ENOENT):
	 *	Firmware does not support the requested workaround.
	 *  - MC_CMD_ERR_EPERM  (reported as EACCES):
	 *	Unprivileged function cannot enable/disable workarounds.
	 *
	 * See efx_mcdi_request_errcode() for MCDI error translations.
	 */

	/*
	 * If the bug35388 workaround is enabled, then use an indirect access
	 * method to avoid unsafe EVQ writes.
	 */
	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG35388, B_TRUE,
	    NULL);
	if ((rc == 0) || (rc == EACCES))
		encp->enc_bug35388_workaround = B_TRUE;
	else if ((rc == ENOTSUP) || (rc == ENOENT))
		encp->enc_bug35388_workaround = B_FALSE;
	else
		goto fail1;

	/*
	 * If the bug41750 workaround is enabled, then do not test interrupts,
	 * as the test will fail (seen with Greenport controllers).
	 */
	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG41750, B_TRUE,
	    NULL);
	if (rc == 0) {
		encp->enc_bug41750_workaround = B_TRUE;
	} else if (rc == EACCES) {
		/* Assume a controller with 40G ports needs the workaround. */
		if (epp->ep_default_adv_cap_mask & EFX_PHY_CAP_40000FDX)
			encp->enc_bug41750_workaround = B_TRUE;
		else
			encp->enc_bug41750_workaround = B_FALSE;
	} else if ((rc == ENOTSUP) || (rc == ENOENT)) {
		encp->enc_bug41750_workaround = B_FALSE;
	} else {
		goto fail2;
	}
	if (EFX_PCI_FUNCTION_IS_VF(encp)) {
		/* Interrupt testing does not work for VFs. See bug50084. */
		encp->enc_bug41750_workaround = B_TRUE;
	}

	/*
	 * If the bug26807 workaround is enabled, then firmware has enabled
	 * support for chained multicast filters. Firmware will reset (FLR)
	 * functions which have filters in the hardware filter table when the
	 * workaround is enabled/disabled.
	 *
	 * We must recheck if the workaround is enabled after inserting the
	 * first hardware filter, in case it has been changed since this check.
	 */
	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG26807,
	    B_TRUE, &flags);
	if (rc == 0) {
		encp->enc_bug26807_workaround = B_TRUE;
		if (flags & (1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN)) {
			/*
			 * Other functions had installed filters before the
			 * workaround was enabled, and they have been reset
			 * by firmware.
			 */
			EFSYS_PROBE(bug26807_workaround_flr_done);
			/* FIXME: bump MC warm boot count ? */
		}
	} else if (rc == EACCES) {
		/*
		 * Unprivileged functions cannot enable the workaround in older
		 * firmware.
		 */
		encp->enc_bug26807_workaround = B_FALSE;
	} else if ((rc == ENOTSUP) || (rc == ENOENT)) {
		encp->enc_bug26807_workaround = B_FALSE;
	} else {
		goto fail3;
	}

	/* Get clock frequencies (in MHz). */
	if ((rc = efx_mcdi_get_clock(enp, &sysclk, &dpcpu_clk)) != 0)
		goto fail4;

	/*
	 * The Huntington timer quantum is 1536 sysclk cycles, documented for
	 * the EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units.
	 */
	encp->enc_evq_timer_quantum_ns = 1536000UL / sysclk; /* 1536 cycles */
	if (encp->enc_bug35388_workaround) {
		encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
		ERF_DD_EVQ_IND_TIMER_VAL_WIDTH) / 1000;
	} else {
		encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
		FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;
	}

	encp->enc_bug61265_workaround = B_FALSE; /* Medford only */

	/* Checksums for TSO sends can be incorrect on Huntington. */
	encp->enc_bug61297_workaround = B_TRUE;

	/* Alignment for receive packet DMA buffers */
	encp->enc_rx_buf_align_start = 1;
	encp->enc_rx_buf_align_end = 64; /* RX DMA end padding */

	/*
	 * The workaround for bug35388 uses the top bit of transmit queue
	 * descriptor writes, preventing the use of 4096 descriptor TXQs.
	 */
	encp->enc_txq_max_ndescs = encp->enc_bug35388_workaround ? 2048 : 4096;

	EFX_STATIC_ASSERT(HUNT_PIOBUF_NBUFS <= EF10_MAX_PIOBUF_NBUFS);
	encp->enc_piobuf_limit = HUNT_PIOBUF_NBUFS;
	encp->enc_piobuf_size = HUNT_PIOBUF_SIZE;
	encp->enc_piobuf_min_alloc_size = HUNT_MIN_PIO_ALLOC_SIZE;

	if ((rc = hunt_nic_get_required_pcie_bandwidth(enp, &bandwidth)) != 0)
		goto fail5;
	encp->enc_required_pcie_bandwidth_mbps = bandwidth;

	/* All Huntington devices have a PCIe Gen3, 8 lane connector */
	encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN3;

	return (0);

fail5:
	EFSYS_PROBE(fail5);
fail4:
	EFSYS_PROBE(fail4);
fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
Exemple #12
0
	__checkReturn	efx_rc_t
hunt_board_cfg(
	__in		efx_nic_t *enp)
{
	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
	uint8_t mac_addr[6];
	uint32_t board_type = 0;
	ef10_link_state_t els;
	efx_port_t *epp = &(enp->en_port);
	uint32_t port;
	uint32_t pf;
	uint32_t vf;
	uint32_t mask;
	uint32_t flags;
	uint32_t sysclk, dpcpu_clk;
	uint32_t base, nvec;
	uint32_t bandwidth;
	efx_rc_t rc;

	if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0)
		goto fail1;

	/*
	 * NOTE: The MCDI protocol numbers ports from zero.
	 * The common code MCDI interface numbers ports from one.
	 */
	emip->emi_port = port + 1;

	if ((rc = ef10_external_port_mapping(enp, port,
		    &encp->enc_external_port)) != 0)
		goto fail2;

	/*
	 * Get PCIe function number from firmware (used for
	 * per-function privilege and dynamic config info).
	 *  - PCIe PF: pf = PF number, vf = 0xffff.
	 *  - PCIe VF: pf = parent PF, vf = VF number.
	 */
	if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0)
		goto fail3;

	encp->enc_pf = pf;
	encp->enc_vf = vf;

	/* MAC address for this function */
	if (EFX_PCI_FUNCTION_IS_PF(encp)) {
		rc = efx_mcdi_get_mac_address_pf(enp, mac_addr);
		if ((rc == 0) && (mac_addr[0] & 0x02)) {
			/*
			 * If the static config does not include a global MAC
			 * address pool then the board may return a locally
			 * administered MAC address (this should only happen on
			 * incorrectly programmed boards).
			 */
			rc = EINVAL;
		}
	} else {
		rc = efx_mcdi_get_mac_address_vf(enp, mac_addr);
	}
	if (rc != 0)
		goto fail4;

	EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);

	/* Board configuration */
	rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL);
	if (rc != 0) {
		/* Unprivileged functions may not be able to read board cfg */
		if (rc == EACCES)
			board_type = 0;
		else
			goto fail5;
	}

	encp->enc_board_type = board_type;
	encp->enc_clk_mult = 1; /* not used for Huntington */

	/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
	if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
		goto fail6;

	/* Obtain the default PHY advertised capabilities */
	if ((rc = ef10_phy_get_link(enp, &els)) != 0)
		goto fail7;
	epp->ep_default_adv_cap_mask = els.els_adv_cap_mask;
	epp->ep_adv_cap_mask = els.els_adv_cap_mask;

	/*
	 * Enable firmware workarounds for hardware errata.
	 * Expected responses are:
	 *  - 0 (zero):
	 *	Success: workaround enabled or disabled as requested.
	 *  - MC_CMD_ERR_ENOSYS (reported as ENOTSUP):
	 *	Firmware does not support the MC_CMD_WORKAROUND request.
	 *	(assume that the workaround is not supported).
	 *  - MC_CMD_ERR_ENOENT (reported as ENOENT):
	 *	Firmware does not support the requested workaround.
	 *  - MC_CMD_ERR_EPERM  (reported as EACCES):
	 *	Unprivileged function cannot enable/disable workarounds.
	 *
	 * See efx_mcdi_request_errcode() for MCDI error translations.
	 */

	/*
	 * If the bug35388 workaround is enabled, then use an indirect access
	 * method to avoid unsafe EVQ writes.
	 */
	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG35388, B_TRUE,
	    NULL);
	if ((rc == 0) || (rc == EACCES))
		encp->enc_bug35388_workaround = B_TRUE;
	else if ((rc == ENOTSUP) || (rc == ENOENT))
		encp->enc_bug35388_workaround = B_FALSE;
	else
		goto fail8;

	/*
	 * If the bug41750 workaround is enabled, then do not test interrupts,
	 * as the test will fail (seen with Greenport controllers).
	 */
	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG41750, B_TRUE,
	    NULL);
	if (rc == 0) {
		encp->enc_bug41750_workaround = B_TRUE;
	} else if (rc == EACCES) {
		/* Assume a controller with 40G ports needs the workaround. */
		if (epp->ep_default_adv_cap_mask & EFX_PHY_CAP_40000FDX)
			encp->enc_bug41750_workaround = B_TRUE;
		else
			encp->enc_bug41750_workaround = B_FALSE;
	} else if ((rc == ENOTSUP) || (rc == ENOENT)) {
		encp->enc_bug41750_workaround = B_FALSE;
	} else {
		goto fail9;
	}
	if (EFX_PCI_FUNCTION_IS_VF(encp)) {
		/* Interrupt testing does not work for VFs. See bug50084. */
		encp->enc_bug41750_workaround = B_TRUE;
	}

	/*
	 * If the bug26807 workaround is enabled, then firmware has enabled
	 * support for chained multicast filters. Firmware will reset (FLR)
	 * functions which have filters in the hardware filter table when the
	 * workaround is enabled/disabled.
	 *
	 * We must recheck if the workaround is enabled after inserting the
	 * first hardware filter, in case it has been changed since this check.
	 */
	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG26807,
	    B_TRUE, &flags);
	if (rc == 0) {
		encp->enc_bug26807_workaround = B_TRUE;
		if (flags & (1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN)) {
			/*
			 * Other functions had installed filters before the
			 * workaround was enabled, and they have been reset
			 * by firmware.
			 */
			EFSYS_PROBE(bug26807_workaround_flr_done);
			/* FIXME: bump MC warm boot count ? */
		}
	} else if (rc == EACCES) {
		/*
		 * Unprivileged functions cannot enable the workaround in older
		 * firmware.
		 */
		encp->enc_bug26807_workaround = B_FALSE;
	} else if ((rc == ENOTSUP) || (rc == ENOENT)) {
		encp->enc_bug26807_workaround = B_FALSE;
	} else {
		goto fail10;
	}

	/* Get clock frequencies (in MHz). */
	if ((rc = efx_mcdi_get_clock(enp, &sysclk, &dpcpu_clk)) != 0)
		goto fail11;

	/*
	 * The Huntington timer quantum is 1536 sysclk cycles, documented for
	 * the EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units.
	 */
	encp->enc_evq_timer_quantum_ns = 1536000UL / sysclk; /* 1536 cycles */
	if (encp->enc_bug35388_workaround) {
		encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
		ERF_DD_EVQ_IND_TIMER_VAL_WIDTH) / 1000;
	} else {
		encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
		FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;
	}

	encp->enc_bug61265_workaround = B_FALSE; /* Medford only */

	/* Check capabilities of running datapath firmware */
	if ((rc = ef10_get_datapath_caps(enp)) != 0)
		goto fail12;

	/* Alignment for receive packet DMA buffers */
	encp->enc_rx_buf_align_start = 1;
	encp->enc_rx_buf_align_end = 64; /* RX DMA end padding */

	/* Alignment for WPTR updates */
	encp->enc_rx_push_align = EF10_RX_WPTR_ALIGN;

	encp->enc_tx_dma_desc_size_max = EFX_MASK32(ESF_DZ_RX_KER_BYTE_CNT);
	/* No boundary crossing limits */
	encp->enc_tx_dma_desc_boundary = 0;

	/*
	 * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use
	 * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available
	 * resources (allocated to this PCIe function), which is zero until
	 * after we have allocated VIs.
	 */
	encp->enc_evq_limit = 1024;
	encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET;
	encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET;

	encp->enc_buftbl_limit = 0xFFFFFFFF;

	encp->enc_piobuf_limit = HUNT_PIOBUF_NBUFS;
	encp->enc_piobuf_size = HUNT_PIOBUF_SIZE;
	encp->enc_piobuf_min_alloc_size = HUNT_MIN_PIO_ALLOC_SIZE;

	/*
	 * Get the current privilege mask. Note that this may be modified
	 * dynamically, so this value is informational only. DO NOT use
	 * the privilege mask to check for sufficient privileges, as that
	 * can result in time-of-check/time-of-use bugs.
	 */
	if ((rc = ef10_get_privilege_mask(enp, &mask)) != 0)
		goto fail13;
	encp->enc_privilege_mask = mask;

	/* Get interrupt vector limits */
	if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) {
		if (EFX_PCI_FUNCTION_IS_PF(encp))
			goto fail14;

		/* Ignore error (cannot query vector limits from a VF). */
		base = 0;
		nvec = 1024;
	}
	encp->enc_intr_vec_base = base;
	encp->enc_intr_limit = nvec;

	/*
	 * Maximum number of bytes into the frame the TCP header can start for
	 * firmware assisted TSO to work.
	 */
	encp->enc_tx_tso_tcp_header_offset_limit = EF10_TCP_HEADER_OFFSET_LIMIT;

	if ((rc = hunt_nic_get_required_pcie_bandwidth(enp, &bandwidth)) != 0)
		goto fail15;
	encp->enc_required_pcie_bandwidth_mbps = bandwidth;

	/* All Huntington devices have a PCIe Gen3, 8 lane connector */
	encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN3;

	return (0);

fail15:
	EFSYS_PROBE(fail15);
fail14:
	EFSYS_PROBE(fail14);
fail13:
	EFSYS_PROBE(fail13);
fail12:
	EFSYS_PROBE(fail12);
fail11:
	EFSYS_PROBE(fail11);
fail10:
	EFSYS_PROBE(fail10);
fail9:
	EFSYS_PROBE(fail9);
fail8:
	EFSYS_PROBE(fail8);
fail7:
	EFSYS_PROBE(fail7);
fail6:
	EFSYS_PROBE(fail6);
fail5:
	EFSYS_PROBE(fail5);
fail4:
	EFSYS_PROBE(fail4);
fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
Exemple #13
0
static	__checkReturn	efx_rc_t
siena_board_cfg(
	__in		efx_nic_t *enp)
{
	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
	uint8_t mac_addr[6];
	efx_dword_t capabilities;
	uint32_t board_type;
	uint32_t nevq, nrxq, ntxq;
	efx_rc_t rc;

	/* External port identifier using one-based port numbering */
	encp->enc_external_port = (uint8_t)enp->en_mcdi.em_emip.emi_port;

	/* Board configuration */
	if ((rc = efx_mcdi_get_board_cfg(enp, &board_type,
		    &capabilities, mac_addr)) != 0)
		goto fail1;

	EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);

	encp->enc_board_type = board_type;

	/*
	 * There is no possibility to determine the number of PFs on Siena
	 * by issuing MCDI request, and it is not an easy task to find the
	 * value based on the board type, so 'enc_hw_pf_count' is set to 1
	 */
	encp->enc_hw_pf_count = 1;

	/* Additional capabilities */
	encp->enc_clk_mult = 1;
	if (EFX_DWORD_FIELD(capabilities, MC_CMD_CAPABILITIES_TURBO)) {
		enp->en_features |= EFX_FEATURE_TURBO;

		if (EFX_DWORD_FIELD(capabilities,
			MC_CMD_CAPABILITIES_TURBO_ACTIVE)) {
			encp->enc_clk_mult = 2;
		}
	}

	encp->enc_evq_timer_quantum_ns =
		EFX_EVQ_SIENA_TIMER_QUANTUM_NS / encp->enc_clk_mult;
	encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
		FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;

	/* When hash header insertion is enabled, Siena inserts 16 bytes */
	encp->enc_rx_prefix_size = 16;

	/* Alignment for receive packet DMA buffers */
	encp->enc_rx_buf_align_start = 1;
	encp->enc_rx_buf_align_end = 1;

	/* Alignment for WPTR updates */
	encp->enc_rx_push_align = 1;

	/* Resource limits */
	rc = efx_mcdi_get_resource_limits(enp, &nevq, &nrxq, &ntxq);
	if (rc != 0) {
		if (rc != ENOTSUP)
			goto fail2;

		nevq = 1024;
		nrxq = EFX_RXQ_LIMIT_TARGET;
		ntxq = EFX_TXQ_LIMIT_TARGET;
	}
	encp->enc_evq_limit = nevq;
	encp->enc_rxq_limit = MIN(EFX_RXQ_LIMIT_TARGET, nrxq);
	encp->enc_txq_limit = MIN(EFX_TXQ_LIMIT_TARGET, ntxq);

	encp->enc_buftbl_limit = SIENA_SRAM_ROWS -
	    (encp->enc_txq_limit * EFX_TXQ_DC_NDESCS(EFX_TXQ_DC_SIZE)) -
	    (encp->enc_rxq_limit * EFX_RXQ_DC_NDESCS(EFX_RXQ_DC_SIZE));

	encp->enc_hw_tx_insert_vlan_enabled = B_FALSE;
	encp->enc_fw_assisted_tso_enabled = B_FALSE;
	encp->enc_fw_assisted_tso_v2_enabled = B_FALSE;
	encp->enc_fw_assisted_tso_v2_n_contexts = 0;
	encp->enc_allow_set_mac_with_installed_filters = B_TRUE;

	/* Siena supports two 10G ports, and 8 lanes of PCIe Gen2 */
	encp->enc_required_pcie_bandwidth_mbps = 2 * 10000;
	encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN2;

	encp->enc_fw_verified_nvram_update_required = B_FALSE;

	return (0);

fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
	__checkReturn	efx_rc_t
medford_board_cfg(
	__in		efx_nic_t *enp)
{
	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
	uint8_t mac_addr[6] = { 0 };
	uint32_t board_type = 0;
	ef10_link_state_t els;
	efx_port_t *epp = &(enp->en_port);
	uint32_t port;
	uint32_t pf;
	uint32_t vf;
	uint32_t mask;
	uint32_t sysclk, dpcpu_clk;
	uint32_t base, nvec;
	uint32_t end_padding;
	uint32_t bandwidth;
	efx_rc_t rc;

	/*
	 * FIXME: Likely to be incomplete and incorrect.
	 * Parts of this should be shared with Huntington.
	 */

	if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0)
		goto fail1;

	/*
	 * NOTE: The MCDI protocol numbers ports from zero.
	 * The common code MCDI interface numbers ports from one.
	 */
	emip->emi_port = port + 1;

	if ((rc = ef10_external_port_mapping(enp, port,
		    &encp->enc_external_port)) != 0)
		goto fail2;

	/*
	 * Get PCIe function number from firmware (used for
	 * per-function privilege and dynamic config info).
	 *  - PCIe PF: pf = PF number, vf = 0xffff.
	 *  - PCIe VF: pf = parent PF, vf = VF number.
	 */
	if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0)
		goto fail3;

	encp->enc_pf = pf;
	encp->enc_vf = vf;

	/* MAC address for this function */
	if (EFX_PCI_FUNCTION_IS_PF(encp)) {
		rc = efx_mcdi_get_mac_address_pf(enp, mac_addr);
#if EFSYS_OPT_ALLOW_UNCONFIGURED_NIC
		/* Disable static config checking for Medford NICs, ONLY
		 * for manufacturing test and setup at the factory, to
		 * allow the static config to be installed.
		 */
#else /* EFSYS_OPT_ALLOW_UNCONFIGURED_NIC */
		if ((rc == 0) && (mac_addr[0] & 0x02)) {
			/*
			 * If the static config does not include a global MAC
			 * address pool then the board may return a locally
			 * administered MAC address (this should only happen on
			 * incorrectly programmed boards).
			 */
			rc = EINVAL;
		}
#endif /* EFSYS_OPT_ALLOW_UNCONFIGURED_NIC */
	} else {
		rc = efx_mcdi_get_mac_address_vf(enp, mac_addr);
	}
	if (rc != 0)
		goto fail4;

	EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);

	/* Board configuration */
	rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL);
	if (rc != 0) {
		/* Unprivileged functions may not be able to read board cfg */
		if (rc == EACCES)
			board_type = 0;
		else
			goto fail5;
	}

	encp->enc_board_type = board_type;
	encp->enc_clk_mult = 1; /* not used for Medford */

	/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
	if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
		goto fail6;

	/* Obtain the default PHY advertised capabilities */
	if ((rc = ef10_phy_get_link(enp, &els)) != 0)
		goto fail7;
	epp->ep_default_adv_cap_mask = els.els_adv_cap_mask;
	epp->ep_adv_cap_mask = els.els_adv_cap_mask;

	/*
	 * Enable firmware workarounds for hardware errata.
	 * Expected responses are:
	 *  - 0 (zero):
	 *	Success: workaround enabled or disabled as requested.
	 *  - MC_CMD_ERR_ENOSYS (reported as ENOTSUP):
	 *	Firmware does not support the MC_CMD_WORKAROUND request.
	 *	(assume that the workaround is not supported).
	 *  - MC_CMD_ERR_ENOENT (reported as ENOENT):
	 *	Firmware does not support the requested workaround.
	 *  - MC_CMD_ERR_EPERM  (reported as EACCES):
	 *	Unprivileged function cannot enable/disable workarounds.
	 *
	 * See efx_mcdi_request_errcode() for MCDI error translations.
	 */


	if (EFX_PCI_FUNCTION_IS_VF(encp)) {
		/*
		 * Interrupt testing does not work for VFs. See bug50084.
		 * FIXME: Does this still  apply to Medford?
		 */
		encp->enc_bug41750_workaround = B_TRUE;
	}

	/* Chained multicast is always enabled on Medford */
	encp->enc_bug26807_workaround = B_TRUE;

	/*
	 * If the bug61265 workaround is enabled, then interrupt holdoff timers
	 * cannot be controlled by timer table writes, so MCDI must be used
	 * (timer table writes can still be used for wakeup timers).
	 */
	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG61265, B_TRUE,
	    NULL);
	if ((rc == 0) || (rc == EACCES))
		encp->enc_bug61265_workaround = B_TRUE;
	else if ((rc == ENOTSUP) || (rc == ENOENT))
		encp->enc_bug61265_workaround = B_FALSE;
	else
		goto fail8;

	/* Get clock frequencies (in MHz). */
	if ((rc = efx_mcdi_get_clock(enp, &sysclk, &dpcpu_clk)) != 0)
		goto fail9;

	/*
	 * The Medford timer quantum is 1536 dpcpu_clk cycles, documented for
	 * the EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units.
	 */
	encp->enc_evq_timer_quantum_ns = 1536000UL / dpcpu_clk; /* 1536 cycles */
	encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
		    FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;

	/* Check capabilities of running datapath firmware */
	if ((rc = ef10_get_datapath_caps(enp)) != 0)
		goto fail10;

	/* Alignment for receive packet DMA buffers */
	encp->enc_rx_buf_align_start = 1;

	/* Get the RX DMA end padding alignment configuration */
	if ((rc = efx_mcdi_get_rxdp_config(enp, &end_padding)) != 0) {
		if (rc != EACCES)
			goto fail11;

		/* Assume largest tail padding size supported by hardware */
		end_padding = 256;
	}
	encp->enc_rx_buf_align_end = end_padding;

	/* Alignment for WPTR updates */
	encp->enc_rx_push_align = EF10_RX_WPTR_ALIGN;

	/*
	 * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use
	 * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available
	 * resources (allocated to this PCIe function), which is zero until
	 * after we have allocated VIs.
	 */
	encp->enc_evq_limit = 1024;
	encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET;
	encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET;

	/*
	 * The maximum supported transmit queue size is 2048. TXQs with 4096
	 * descriptors are not supported as the top bit is used for vfifo
	 * stuffing.
	 */
	encp->enc_txq_max_ndescs = 2048;

	encp->enc_buftbl_limit = 0xFFFFFFFF;

	encp->enc_piobuf_limit = MEDFORD_PIOBUF_NBUFS;
	encp->enc_piobuf_size = MEDFORD_PIOBUF_SIZE;
	encp->enc_piobuf_min_alloc_size = MEDFORD_MIN_PIO_ALLOC_SIZE;

	/*
	 * Get the current privilege mask. Note that this may be modified
	 * dynamically, so this value is informational only. DO NOT use
	 * the privilege mask to check for sufficient privileges, as that
	 * can result in time-of-check/time-of-use bugs.
	 */
	if ((rc = ef10_get_privilege_mask(enp, &mask)) != 0)
		goto fail12;
	encp->enc_privilege_mask = mask;

	/* Get interrupt vector limits */
	if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) {
		if (EFX_PCI_FUNCTION_IS_PF(encp))
			goto fail13;

		/* Ignore error (cannot query vector limits from a VF). */
		base = 0;
		nvec = 1024;
	}
	encp->enc_intr_vec_base = base;
	encp->enc_intr_limit = nvec;

	/*
	 * Maximum number of bytes into the frame the TCP header can start for
	 * firmware assisted TSO to work.
	 */
	encp->enc_tx_tso_tcp_header_offset_limit = EF10_TCP_HEADER_OFFSET_LIMIT;

	/*
	 * Medford stores a single global copy of VPD, not per-PF as on
	 * Huntington.
	 */
	encp->enc_vpd_is_global = B_TRUE;

	rc = medford_nic_get_required_pcie_bandwidth(enp, &bandwidth);
	if (rc != 0)
		goto fail14;
	encp->enc_required_pcie_bandwidth_mbps = bandwidth;
	encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN3;

	return (0);

fail14:
	EFSYS_PROBE(fail14);
fail13:
	EFSYS_PROBE(fail13);
fail12:
	EFSYS_PROBE(fail12);
fail11:
	EFSYS_PROBE(fail11);
fail10:
	EFSYS_PROBE(fail10);
fail9:
	EFSYS_PROBE(fail9);
fail8:
	EFSYS_PROBE(fail8);
fail7:
	EFSYS_PROBE(fail7);
fail6:
	EFSYS_PROBE(fail6);
fail5:
	EFSYS_PROBE(fail5);
fail4:
	EFSYS_PROBE(fail4);
fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
static	__checkReturn	efx_rc_t
efx_mcdi_filter_op_add(
	__in		efx_nic_t *enp,
	__in		efx_filter_spec_t *spec,
	__in		unsigned int filter_op,
	__inout		ef10_filter_handle_t *handle)
{
	efx_mcdi_req_t req;
	uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN,
			    MC_CMD_FILTER_OP_OUT_LEN)];
	uint32_t match_fields = 0;
	efx_rc_t rc;

	memset(payload, 0, sizeof (payload));
	req.emr_cmd = MC_CMD_FILTER_OP;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN;
	req.emr_out_buf = payload;
	req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN;

	switch (filter_op) {
	case MC_CMD_FILTER_OP_IN_OP_REPLACE:
		MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO,
		    handle->efh_lo);
		MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI,
		    handle->efh_hi);
		/* Fall through */
	case MC_CMD_FILTER_OP_IN_OP_INSERT:
	case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE:
		MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, filter_op);
		break;
	default:
		EFSYS_ASSERT(0);
		rc = EINVAL;
		goto fail1;
	}

	if (spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) {
		/*
		 * The LOC_MAC_IG match flag can represent unknown unicast
		 *  or multicast filters - use the MAC address to distinguish
		 *  them.
		 */
		if (EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac))
			match_fields |= 1U <<
				MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN;
		else
			match_fields |= 1U <<
				MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN;
	}

	match_fields |= spec->efs_match_flags & (~EFX_FILTER_MATCH_LOC_MAC_IG);

	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID,
	    EVB_PORT_ID_ASSIGNED);
	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS,
	    match_fields);
	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST,
	    MC_CMD_FILTER_OP_IN_RX_DEST_HOST);
	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE,
	    spec->efs_dmaq_id);
	if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) {
		MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_CONTEXT,
		    spec->efs_rss_context);
	}
	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_MODE,
	    spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ?
	    MC_CMD_FILTER_OP_IN_RX_MODE_RSS :
	    MC_CMD_FILTER_OP_IN_RX_MODE_SIMPLE);
	MCDI_IN_SET_DWORD(req, FILTER_OP_IN_TX_DEST,
	    MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT);

	if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) {
		/*
		 * NOTE: Unlike most MCDI requests, the filter fields
		 * are presented in network (big endian) byte order.
		 */
		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_MAC),
		    spec->efs_rem_mac, EFX_MAC_ADDR_LEN);
		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_MAC),
		    spec->efs_loc_mac, EFX_MAC_ADDR_LEN);

		MCDI_IN_SET_WORD(req, FILTER_OP_IN_SRC_PORT,
		    __CPU_TO_BE_16(spec->efs_rem_port));
		MCDI_IN_SET_WORD(req, FILTER_OP_IN_DST_PORT,
		    __CPU_TO_BE_16(spec->efs_loc_port));

		MCDI_IN_SET_WORD(req, FILTER_OP_IN_ETHER_TYPE,
		    __CPU_TO_BE_16(spec->efs_ether_type));

		MCDI_IN_SET_WORD(req, FILTER_OP_IN_INNER_VLAN,
		    __CPU_TO_BE_16(spec->efs_inner_vid));
		MCDI_IN_SET_WORD(req, FILTER_OP_IN_OUTER_VLAN,
		    __CPU_TO_BE_16(spec->efs_outer_vid));

		/* IP protocol (in low byte, high byte is zero) */
		MCDI_IN_SET_BYTE(req, FILTER_OP_IN_IP_PROTO,
		    spec->efs_ip_proto);

		EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) ==
		    MC_CMD_FILTER_OP_IN_SRC_IP_LEN);
		EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) ==
		    MC_CMD_FILTER_OP_IN_DST_IP_LEN);

		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_IP),
		    &spec->efs_rem_host.eo_byte[0],
		    MC_CMD_FILTER_OP_IN_SRC_IP_LEN);
		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_IP),
		    &spec->efs_loc_host.eo_byte[0],
		    MC_CMD_FILTER_OP_IN_DST_IP_LEN);
	}

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail2;
	}

	if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) {
		rc = EMSGSIZE;
		goto fail3;
	}

	handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_LO);
	handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_HI);

	return (0);

fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);

}
	__checkReturn	efx_rc_t
efx_intr_init(
	__in		efx_nic_t *enp,
	__in		efx_intr_type_t type,
	__in		efsys_mem_t *esmp)
{
	efx_intr_t *eip = &(enp->en_intr);
	const efx_intr_ops_t *eiop;
	efx_rc_t rc;

	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);

	if (enp->en_mod_flags & EFX_MOD_INTR) {
		rc = EINVAL;
		goto fail1;
	}

	eip->ei_esmp = esmp;
	eip->ei_type = type;
	eip->ei_level = 0;

	enp->en_mod_flags |= EFX_MOD_INTR;

	switch (enp->en_family) {
#if EFSYS_OPT_SIENA
	case EFX_FAMILY_SIENA:
		eiop = &__efx_intr_siena_ops;
		break;
#endif	/* EFSYS_OPT_SIENA */

#if EFSYS_OPT_HUNTINGTON
	case EFX_FAMILY_HUNTINGTON:
		eiop = &__efx_intr_ef10_ops;
		break;
#endif	/* EFSYS_OPT_HUNTINGTON */

#if EFSYS_OPT_MEDFORD
	case EFX_FAMILY_MEDFORD:
		eiop = &__efx_intr_ef10_ops;
		break;
#endif	/* EFSYS_OPT_MEDFORD */

	default:
		EFSYS_ASSERT(B_FALSE);
		rc = ENOTSUP;
		goto fail2;
	}

	if ((rc = eiop->eio_init(enp, type, esmp)) != 0)
		goto fail3;

	eip->ei_eiop = eiop;

	return (0);

fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
static	__checkReturn	efx_rc_t
ef10_filter_add_internal(
	__in		efx_nic_t *enp,
	__inout		efx_filter_spec_t *spec,
	__in		boolean_t may_replace,
	__out_opt	uint32_t *filter_id)
{
	efx_rc_t rc;
	ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
	efx_filter_spec_t *saved_spec;
	uint32_t hash;
	unsigned int depth;
	int ins_index;
	boolean_t replacing = B_FALSE;
	unsigned int i;
	efsys_lock_state_t state;
	boolean_t locked = B_FALSE;

	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
		    enp->en_family == EFX_FAMILY_MEDFORD);

#if EFSYS_OPT_RX_SCALE
	spec->efs_rss_context = enp->en_rss_context;
#endif

	hash = ef10_filter_hash(spec);

	/*
	 * FIXME: Add support for inserting filters of different priorities
	 * and removing lower priority multicast filters (bug 42378)
	 */

	/*
	 * Find any existing filters with the same match tuple or
	 * else a free slot to insert at.  If any of them are busy,
	 * we have to wait and retry.
	 */
	for (;;) {
		ins_index = -1;
		depth = 1;
		EFSYS_LOCK(enp->en_eslp, state);
		locked = B_TRUE;

		for (;;) {
			i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1);
			saved_spec = ef10_filter_entry_spec(eftp, i);

			if (!saved_spec) {
				if (ins_index < 0) {
					ins_index = i;
				}
			} else if (ef10_filter_equal(spec, saved_spec)) {
				if (ef10_filter_entry_is_busy(eftp, i))
					break;
				if (saved_spec->efs_priority
					    == EFX_FILTER_PRI_AUTO) {
					ins_index = i;
					goto found;
				} else if (ef10_filter_is_exclusive(spec)) {
					if (may_replace) {
						ins_index = i;
						goto found;
					} else {
						rc = EEXIST;
						goto fail1;
					}
				}

				/* Leave existing */
			}

			/*
			 * Once we reach the maximum search depth, use
			 * the first suitable slot or return EBUSY if
			 * there was none.
			 */
			if (depth == EF10_FILTER_SEARCH_LIMIT) {
				if (ins_index < 0) {
					rc = EBUSY;
					goto fail2;
				}
				goto found;
			}
			depth++;
		}
		EFSYS_UNLOCK(enp->en_eslp, state);
		locked = B_FALSE;
	}

found:
	/*
	 * Create a software table entry if necessary, and mark it
	 * busy.  We might yet fail to insert, but any attempt to
	 * insert a conflicting filter while we're waiting for the
	 * firmware must find the busy entry.
	 */
	saved_spec = ef10_filter_entry_spec(eftp, ins_index);
	if (saved_spec) {
		if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) {
			/* This is a filter we are refreshing */
			ef10_filter_set_entry_not_auto_old(eftp, ins_index);
			goto out_unlock;

		}
		replacing = B_TRUE;
	} else {
		EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec);
		if (!saved_spec) {
			rc = ENOMEM;
			goto fail3;
		}
		*saved_spec = *spec;
		ef10_filter_set_entry(eftp, ins_index, saved_spec);
	}
	ef10_filter_set_entry_busy(eftp, ins_index);

	EFSYS_UNLOCK(enp->en_eslp, state);
	locked = B_FALSE;

	/*
	 * On replacing the filter handle may change after after a successful
	 * replace operation.
	 */
	if (replacing) {
		rc = efx_mcdi_filter_op_add(enp, spec,
		    MC_CMD_FILTER_OP_IN_OP_REPLACE,
		    &eftp->eft_entry[ins_index].efe_handle);
	} else if (ef10_filter_is_exclusive(spec)) {
		rc = efx_mcdi_filter_op_add(enp, spec,
		    MC_CMD_FILTER_OP_IN_OP_INSERT,
		    &eftp->eft_entry[ins_index].efe_handle);
	} else {
		rc = efx_mcdi_filter_op_add(enp, spec,
		    MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
		    &eftp->eft_entry[ins_index].efe_handle);
	}

	if (rc != 0)
		goto fail4;

	EFSYS_LOCK(enp->en_eslp, state);
	locked = B_TRUE;

	if (replacing) {
		/* Update the fields that may differ */
		saved_spec->efs_priority = spec->efs_priority;
		saved_spec->efs_flags = spec->efs_flags;
		saved_spec->efs_rss_context = spec->efs_rss_context;
		saved_spec->efs_dmaq_id = spec->efs_dmaq_id;
	}

	ef10_filter_set_entry_not_busy(eftp, ins_index);

out_unlock:

	EFSYS_UNLOCK(enp->en_eslp, state);
	locked = B_FALSE;

	if (filter_id)
		*filter_id = ins_index;

	return (0);

fail4:
	EFSYS_PROBE(fail4);

	if (!replacing) {
		EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec);
		saved_spec = NULL;
	}
	ef10_filter_set_entry_not_busy(eftp, ins_index);
	ef10_filter_set_entry(eftp, ins_index, NULL);

fail3:
	EFSYS_PROBE(fail3);

fail2:
	EFSYS_PROBE(fail2);

fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	if (locked)
		EFSYS_UNLOCK(enp->en_eslp, state);

	return (rc);
}
Exemple #18
0
static	__checkReturn	efx_rc_t
efx_mcdi_rss_context_alloc(
	__in		efx_nic_t *enp,
	__in		efx_rx_scale_support_t scale_support,
	__in		uint32_t num_queues,
	__out		uint32_t *rss_contextp)
{
	efx_mcdi_req_t req;
	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN,
			    MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN)];
	uint32_t rss_context;
	uint32_t context_type;
	efx_rc_t rc;

	if (num_queues > EFX_MAXRSS) {
		rc = EINVAL;
		goto fail1;
	}

	switch (scale_support) {
	case EFX_RX_SCALE_EXCLUSIVE:
		context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE;
		break;
	case EFX_RX_SCALE_SHARED:
		context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED;
		break;
	default:
		rc = EINVAL;
		goto fail2;
	}

	(void) memset(payload, 0, sizeof (payload));
	req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
	req.emr_out_buf = payload;
	req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN;

	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID,
	    EVB_PORT_ID_ASSIGNED);
	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE, context_type);
	/* NUM_QUEUES is only used to validate indirection table offsets */
	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, num_queues);

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail3;
	}

	if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) {
		rc = EMSGSIZE;
		goto fail4;
	}

	rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
	if (rss_context == EF10_RSS_CONTEXT_INVALID) {
		rc = ENOENT;
		goto fail5;
	}

	*rss_contextp = rss_context;

	return (0);

fail5:
	EFSYS_PROBE(fail5);
fail4:
	EFSYS_PROBE(fail4);
fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
static	__checkReturn	efx_rc_t
ef10_filter_delete_internal(
	__in		efx_nic_t *enp,
	__in		uint32_t filter_id)
{
	efx_rc_t rc;
	ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
	efx_filter_spec_t *spec;
	efsys_lock_state_t state;
	uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS;

	/*
	 * Find the software table entry and mark it busy.  Don't
	 * remove it yet; any attempt to update while we're waiting
	 * for the firmware must find the busy entry.
	 *
	 * FIXME: What if the busy flag is never cleared?
	 */
	EFSYS_LOCK(enp->en_eslp, state);
	while (ef10_filter_entry_is_busy(table, filter_idx)) {
		EFSYS_UNLOCK(enp->en_eslp, state);
		EFSYS_SPIN(1);
		EFSYS_LOCK(enp->en_eslp, state);
	}
	if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) {
		ef10_filter_set_entry_busy(table, filter_idx);
	}
	EFSYS_UNLOCK(enp->en_eslp, state);

	if (spec == NULL) {
		rc = ENOENT;
		goto fail1;
	}

	/*
	 * Try to remove the hardware filter. This may fail if the MC has
	 * rebooted (which frees all hardware filter resources).
	 */
	if (ef10_filter_is_exclusive(spec)) {
		rc = efx_mcdi_filter_op_delete(enp,
		    MC_CMD_FILTER_OP_IN_OP_REMOVE,
		    &table->eft_entry[filter_idx].efe_handle);
	} else {
		rc = efx_mcdi_filter_op_delete(enp,
		    MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE,
		    &table->eft_entry[filter_idx].efe_handle);
	}

	/* Free the software table entry */
	EFSYS_LOCK(enp->en_eslp, state);
	ef10_filter_set_entry_not_busy(table, filter_idx);
	ef10_filter_set_entry(table, filter_idx, NULL);
	EFSYS_UNLOCK(enp->en_eslp, state);

	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);

	/* Check result of hardware filter removal */
	if (rc != 0)
		goto fail2;

	return (0);

fail2:
	EFSYS_PROBE(fail2);

fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
Exemple #20
0
	__checkReturn	efx_rc_t
efx_nic_create(
	__in		efx_family_t family,
	__in		efsys_identifier_t *esip,
	__in		efsys_bar_t *esbp,
	__in		efsys_lock_t *eslp,
	__deref_out	efx_nic_t **enpp)
{
	efx_nic_t *enp;
	efx_rc_t rc;

	EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID);
	EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES);

	/* Allocate a NIC object */
	EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp);

	if (enp == NULL) {
		rc = ENOMEM;
		goto fail1;
	}

	enp->en_magic = EFX_NIC_MAGIC;

	switch (family) {
#if EFSYS_OPT_FALCON
	case EFX_FAMILY_FALCON:
		enp->en_enop = (efx_nic_ops_t *)&__efx_nic_falcon_ops;
		enp->en_features = 0;
		break;
#endif	/* EFSYS_OPT_FALCON */

#if EFSYS_OPT_SIENA
	case EFX_FAMILY_SIENA:
		enp->en_enop = (efx_nic_ops_t *)&__efx_nic_siena_ops;
		enp->en_features =
		    EFX_FEATURE_IPV6 |
		    EFX_FEATURE_LFSR_HASH_INSERT |
		    EFX_FEATURE_LINK_EVENTS |
		    EFX_FEATURE_PERIODIC_MAC_STATS |
		    EFX_FEATURE_WOL |
		    EFX_FEATURE_MCDI |
		    EFX_FEATURE_LOOKAHEAD_SPLIT |
		    EFX_FEATURE_MAC_HEADER_FILTERS |
		    EFX_FEATURE_TX_SRC_FILTERS;
		break;
#endif	/* EFSYS_OPT_SIENA */

#if EFSYS_OPT_HUNTINGTON
	case EFX_FAMILY_HUNTINGTON:
		enp->en_enop = (efx_nic_ops_t *)&__efx_nic_hunt_ops;
		/* FIXME: Add WOL support */
		enp->en_features =
		    EFX_FEATURE_IPV6 |
		    EFX_FEATURE_LINK_EVENTS |
		    EFX_FEATURE_PERIODIC_MAC_STATS |
		    EFX_FEATURE_MCDI |
		    EFX_FEATURE_MAC_HEADER_FILTERS |
		    EFX_FEATURE_MCDI_DMA |
		    EFX_FEATURE_PIO_BUFFERS |
		    EFX_FEATURE_FW_ASSISTED_TSO;
		break;
#endif	/* EFSYS_OPT_HUNTINGTON */

	default:
		rc = ENOTSUP;
		goto fail2;
	}

	enp->en_family = family;
	enp->en_esip = esip;
	enp->en_esbp = esbp;
	enp->en_eslp = eslp;

	*enpp = enp;

	return (0);

fail2:
	EFSYS_PROBE(fail2);

	enp->en_magic = 0;

	/* Free the NIC object */
	EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp);

fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
static	__checkReturn	efx_rc_t
efx_mcdi_get_parser_disp_info(
	__in		efx_nic_t *enp,
	__out		uint32_t *list,
	__out		size_t *length)
{
	efx_mcdi_req_t req;
	uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN,
			    MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)];
	efx_rc_t rc;
	uint32_t i;
	boolean_t support_unknown_ucast = B_FALSE;
	boolean_t support_unknown_mcast = B_FALSE;

	(void) memset(payload, 0, sizeof (payload));
	req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN;
	req.emr_out_buf = payload;
	req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX;

	MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP,
	    MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES);

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail1;
	}

	*length = MCDI_OUT_DWORD(req,
	    GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES);

	if (req.emr_out_length_used <
	    MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(*length)) {
		rc = EMSGSIZE;
		goto fail2;
	}

	memcpy(list,
	    MCDI_OUT2(req,
	    uint32_t,
	    GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES),
	    (*length) * sizeof (uint32_t));
	EFX_STATIC_ASSERT(sizeof (uint32_t) ==
	    MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN);

	/*
	 * Remove UNKNOWN UCAST and MCAST flags, and if both are present, change
	 * the lower priority one to LOC_MAC_IG.
	 */
	for (i = 0; i < *length; i++) {
		if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN) {
			list[i] &=
			(~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN);
			support_unknown_ucast = B_TRUE;
		}
		if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) {
			list[i] &=
			(~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN);
			support_unknown_mcast = B_TRUE;
		}

		if (support_unknown_ucast && support_unknown_mcast) {
			list[i] &= EFX_FILTER_MATCH_LOC_MAC_IG;
			break;
		}
	}

	return (0);

fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
Exemple #22
0
__checkReturn			efx_rc_t
efx_mac_fcntl_set(
    __in				efx_nic_t *enp,
    __in				unsigned int fcntl,
    __in				boolean_t autoneg)
{
    efx_port_t *epp = &(enp->en_port);
    efx_mac_ops_t *emop = epp->ep_emop;
    efx_phy_ops_t *epop = epp->ep_epop;
    unsigned int old_fcntl;
    boolean_t old_autoneg;
    unsigned int old_adv_cap;
    efx_rc_t rc;

    EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
    EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);

    if ((fcntl & ~(EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE)) != 0) {
        rc = EINVAL;
        goto fail1;
    }

    /*
     * Ignore a request to set flow control auto-negotiation
     * if the PHY doesn't support it.
     */
    if (~epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
        autoneg = B_FALSE;

    old_fcntl = epp->ep_fcntl;
    old_autoneg = epp->ep_fcntl_autoneg;
    old_adv_cap = epp->ep_adv_cap_mask;

    epp->ep_fcntl = fcntl;
    epp->ep_fcntl_autoneg = autoneg;

    /*
     * Always encode the flow control settings in the advertised
     * capabilities even if we are not trying to auto-negotiate
     * them and reconfigure both the PHY and the MAC.
     */
    if (fcntl & EFX_FCNTL_RESPOND)
        epp->ep_adv_cap_mask |=    (1 << EFX_PHY_CAP_PAUSE |
                                    1 << EFX_PHY_CAP_ASYM);
    else
        epp->ep_adv_cap_mask &=   ~(1 << EFX_PHY_CAP_PAUSE |
                                    1 << EFX_PHY_CAP_ASYM);

    if (fcntl & EFX_FCNTL_GENERATE)
        epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM);

    if ((rc = epop->epo_reconfigure(enp)) != 0)
        goto fail2;

    if ((rc = emop->emo_reconfigure(enp)) != 0)
        goto fail3;

    return (0);

fail3:
    EFSYS_PROBE(fail3);

fail2:
    EFSYS_PROBE(fail2);

    epp->ep_fcntl = old_fcntl;
    epp->ep_fcntl_autoneg = old_autoneg;
    epp->ep_adv_cap_mask = old_adv_cap;

fail1:
    EFSYS_PROBE1(fail1, efx_rc_t, rc);

    return (rc);
}
Exemple #23
0
	__checkReturn	efx_rc_t
efx_tx_init(
	__in		efx_nic_t *enp)
{
	efx_tx_ops_t *etxop;
	efx_rc_t rc;

	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);

	if (!(enp->en_mod_flags & EFX_MOD_EV)) {
		rc = EINVAL;
		goto fail1;
	}

	if (enp->en_mod_flags & EFX_MOD_TX) {
		rc = EINVAL;
		goto fail2;
	}

	switch (enp->en_family) {
#if EFSYS_OPT_FALCON
	case EFX_FAMILY_FALCON:
		etxop = (efx_tx_ops_t *)&__efx_tx_falcon_ops;
		break;
#endif /* EFSYS_OPT_FALCON */

#if EFSYS_OPT_SIENA
	case EFX_FAMILY_SIENA:
		etxop = (efx_tx_ops_t *)&__efx_tx_siena_ops;
		break;
#endif /* EFSYS_OPT_SIENA */

#if EFSYS_OPT_HUNTINGTON
	case EFX_FAMILY_HUNTINGTON:
		etxop = (efx_tx_ops_t *)&__efx_tx_hunt_ops;
		break;
#endif /* EFSYS_OPT_HUNTINGTON */

#if EFSYS_OPT_MEDFORD
	case EFX_FAMILY_MEDFORD:
		etxop = (efx_tx_ops_t *)&__efx_tx_medford_ops;
		break;
#endif /* EFSYS_OPT_MEDFORD */

	default:
		EFSYS_ASSERT(0);
		rc = ENOTSUP;
		goto fail3;
	}

	EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);

	if ((rc = etxop->etxo_init(enp)) != 0)
		goto fail4;

	enp->en_etxop = etxop;
	enp->en_mod_flags |= EFX_MOD_TX;
	return (0);

fail4:
	EFSYS_PROBE(fail4);
fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	enp->en_etxop = NULL;
	enp->en_mod_flags &= ~EFX_MOD_TX;
	return (rc);
}
Exemple #24
0
	__checkReturn	int
siena_mac_reconfigure(
	__in		efx_nic_t *enp)
{
	efx_port_t *epp = &(enp->en_port);
	uint8_t payload[MAX(MC_CMD_SET_MAC_IN_LEN,
			    MC_CMD_SET_MCAST_HASH_IN_LEN)];
	efx_mcdi_req_t req;
	unsigned int fcntl;
	int rc;

	req.emr_cmd = MC_CMD_SET_MAC;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_SET_MAC_IN_LEN;
	EFX_STATIC_ASSERT(MC_CMD_SET_MAC_OUT_LEN == 0);
	req.emr_out_buf = NULL;
	req.emr_out_length = 0;

	MCDI_IN_SET_DWORD(req, SET_MAC_IN_MTU, epp->ep_mac_pdu);
	MCDI_IN_SET_DWORD(req, SET_MAC_IN_DRAIN, epp->ep_mac_drain ? 1 : 0);
	EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, SET_MAC_IN_ADDR),
			    epp->ep_mac_addr);
	MCDI_IN_POPULATE_DWORD_2(req, SET_MAC_IN_REJECT,
				    SET_MAC_IN_REJECT_UNCST, !epp->ep_unicst,
				    SET_MAC_IN_REJECT_BRDCST, !epp->ep_brdcst);

	if (epp->ep_fcntl_autoneg)
		/* efx_fcntl_set() has already set the phy capabilities */
		fcntl = MC_CMD_FCNTL_AUTO;
	else if (epp->ep_fcntl & EFX_FCNTL_RESPOND)
		fcntl = (epp->ep_fcntl & EFX_FCNTL_GENERATE)
			? MC_CMD_FCNTL_BIDIR
			: MC_CMD_FCNTL_RESPOND;
	else
		fcntl = MC_CMD_FCNTL_OFF;

	MCDI_IN_SET_DWORD(req, SET_MAC_IN_FCNTL, fcntl);

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail1;
	}

	/* Push multicast hash. Set the broadcast bit (0xff) appropriately */
	req.emr_cmd = MC_CMD_SET_MCAST_HASH;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_SET_MCAST_HASH_IN_LEN;
	EFX_STATIC_ASSERT(MC_CMD_SET_MCAST_HASH_OUT_LEN == 0);
	req.emr_out_buf = NULL;
	req.emr_out_length = 0;

	memcpy(MCDI_IN2(req, uint8_t, SET_MCAST_HASH_IN_HASH0),
	    epp->ep_multicst_hash, sizeof (epp->ep_multicst_hash));
	if (epp->ep_brdcst)
		EFX_SET_OWORD_BIT(*MCDI_IN2(req, efx_oword_t,
		    SET_MCAST_HASH_IN_HASH1), 0x7f);

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail2;
	}

	return (0);

fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, int, rc);

	return (rc);
}
Exemple #25
0
	__checkReturn	efx_rc_t
siena_phy_get_link(
	__in		efx_nic_t *enp,
	__out		siena_link_state_t *slsp)
{
	efx_mcdi_req_t req;
	uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN,
			    MC_CMD_GET_LINK_OUT_LEN)];
	efx_rc_t rc;

	(void) memset(payload, 0, sizeof (payload));
	req.emr_cmd = MC_CMD_GET_LINK;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
	req.emr_out_buf = payload;
	req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN;

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail1;
	}

	if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
		rc = EMSGSIZE;
		goto fail2;
	}

	siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
			    &slsp->sls_adv_cap_mask);
	siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
			    &slsp->sls_lp_cap_mask);

	siena_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
			    MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
			    MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
			    &slsp->sls_link_mode, &slsp->sls_fcntl);

#if EFSYS_OPT_LOOPBACK
	/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);

	slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
#endif	/* EFSYS_OPT_LOOPBACK */

	slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;

	return (0);

fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}
Exemple #26
0
	__checkReturn	int
hunt_phy_reconfigure(
	__in		efx_nic_t *enp)
{
	/*
	 * TBD: this is a little different for now (no LED support for Hunt
	 * yet), but ultimately should consider common Siena/Hunt function:
	 * Hunt should be a superset of Siena here (adds 40G)
	 */

	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
	efx_port_t *epp = &(enp->en_port);
	efx_mcdi_req_t req;
	uint8_t payload[MAX(MC_CMD_SET_LINK_IN_LEN,
			    MC_CMD_SET_LINK_OUT_LEN)];
	uint32_t cap_mask;
	unsigned int led_mode;
	unsigned int speed;
	int rc;

	if (~encp->enc_func_flags & EFX_NIC_FUNC_LINKCTRL)
		goto out;

	(void) memset(payload, 0, sizeof (payload));
	req.emr_cmd = MC_CMD_SET_LINK;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
	req.emr_out_buf = payload;
	req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;

	cap_mask = epp->ep_adv_cap_mask;
	MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
		PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
		PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
		PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
		PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
		PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
		PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
		PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
		PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
		PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
		PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
	/* Too many fields for for POPULATE macros, so insert this afterwards */
	MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
	    PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1);

#if EFSYS_OPT_LOOPBACK
	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
		    epp->ep_loopback_type);
	switch (epp->ep_loopback_link_mode) {
	case EFX_LINK_100FDX:
		speed = 100;
		break;
	case EFX_LINK_1000FDX:
		speed = 1000;
		break;
	case EFX_LINK_10000FDX:
		speed = 10000;
		break;
	case EFX_LINK_40000FDX:
		speed = 40000;
		break;
	default:
		speed = 0;
	}
#else
	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
	speed = 0;
#endif	/* EFSYS_OPT_LOOPBACK */
	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);

#if EFSYS_OPT_PHY_FLAGS
	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
#else
	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
#endif	/* EFSYS_OPT_PHY_FLAGS */

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail1;
	}

	/* And set the blink mode */
	(void) memset(payload, 0, sizeof (payload));
	req.emr_cmd = MC_CMD_SET_ID_LED;
	req.emr_in_buf = payload;
	req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
	req.emr_out_buf = payload;
	req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;

#if EFSYS_OPT_PHY_LED_CONTROL
	switch (epp->ep_phy_led_mode) {
	case EFX_PHY_LED_DEFAULT:
		led_mode = MC_CMD_LED_DEFAULT;
		break;
	case EFX_PHY_LED_OFF:
		led_mode = MC_CMD_LED_OFF;
		break;
	case EFX_PHY_LED_ON:
		led_mode = MC_CMD_LED_ON;
		break;
	default:
		EFSYS_ASSERT(0);
		led_mode = MC_CMD_LED_DEFAULT;
	}

	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
#else
	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
#endif	/* EFSYS_OPT_PHY_LED_CONTROL */

	efx_mcdi_execute(enp, &req);

	if (req.emr_rc != 0) {
		rc = req.emr_rc;
		goto fail2;
	}
out:
	return (0);

fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, int, rc);

	return (rc);
}
Exemple #27
0
	__checkReturn	efx_rc_t
siena_nic_probe(
	__in		efx_nic_t *enp)
{
	efx_port_t *epp = &(enp->en_port);
	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
	siena_link_state_t sls;
	unsigned int mask;
	efx_oword_t oword;
	efx_rc_t rc;

	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);

	/* Test BIU */
	if ((rc = efx_nic_biu_test(enp)) != 0)
		goto fail1;

	/* Clear the region register */
	EFX_POPULATE_OWORD_4(oword,
	    FRF_AZ_ADR_REGION0, 0,
	    FRF_AZ_ADR_REGION1, (1 << 16),
	    FRF_AZ_ADR_REGION2, (2 << 16),
	    FRF_AZ_ADR_REGION3, (3 << 16));
	EFX_BAR_WRITEO(enp, FR_AZ_ADR_REGION_REG, &oword);

	/* Read clear any assertion state */
	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
		goto fail2;

	/* Exit the assertion handler */
	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
		goto fail3;

	/* Wrestle control from the BMC */
	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
		goto fail4;

	if ((rc = siena_board_cfg(enp)) != 0)
		goto fail5;

	if ((rc = siena_phy_cfg(enp)) != 0)
		goto fail6;

	/* Obtain the default PHY advertised capabilities */
	if ((rc = siena_nic_reset(enp)) != 0)
		goto fail7;
	if ((rc = siena_phy_get_link(enp, &sls)) != 0)
		goto fail8;
	epp->ep_default_adv_cap_mask = sls.sls_adv_cap_mask;
	epp->ep_adv_cap_mask = sls.sls_adv_cap_mask;

#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
	if ((rc = siena_nic_get_partn_mask(enp, &mask)) != 0)
		goto fail9;
	enp->en_u.siena.enu_partn_mask = mask;
#endif

#if EFSYS_OPT_MAC_STATS
	/* Wipe the MAC statistics */
	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
		goto fail10;
#endif

#if EFSYS_OPT_LOOPBACK
	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
		goto fail11;
#endif

#if EFSYS_OPT_MON_STATS
	if ((rc = mcdi_mon_cfg_build(enp)) != 0)
		goto fail12;
#endif

	encp->enc_features = enp->en_features;

	return (0);

#if EFSYS_OPT_MON_STATS
fail12:
	EFSYS_PROBE(fail12);
#endif
#if EFSYS_OPT_LOOPBACK
fail11:
	EFSYS_PROBE(fail11);
#endif
#if EFSYS_OPT_MAC_STATS
fail10:
	EFSYS_PROBE(fail10);
#endif
#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
fail9:
	EFSYS_PROBE(fail9);
#endif
fail8:
	EFSYS_PROBE(fail8);
fail7:
	EFSYS_PROBE(fail7);
fail6:
	EFSYS_PROBE(fail6);
fail5:
	EFSYS_PROBE(fail5);
fail4:
	EFSYS_PROBE(fail4);
fail3:
	EFSYS_PROBE(fail3);
fail2:
	EFSYS_PROBE(fail2);
fail1:
	EFSYS_PROBE1(fail1, efx_rc_t, rc);

	return (rc);
}