net/sfc/base: import 5xxx/6xxx family support

EFSYS_OPT_SIENA should be enabled to use it.

From Solarflare Communications Inc.

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
This commit is contained in:
Andrew Rybchenko 2016-11-29 16:18:41 +00:00 committed by Ferruh Yigit
parent 099c33bef3
commit f7dc06bf35
18 changed files with 5005 additions and 0 deletions

View File

@ -47,12 +47,16 @@
#if EFSYS_OPT_CHECK_REG
/* Verify chip implements accessed registers */
# if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD)
# error "CHECK_REG requires SIENA or HUNTINGTON or MEDFORD"
# endif
#endif /* EFSYS_OPT_CHECK_REG */
#if EFSYS_OPT_DECODE_INTR_FATAL
/* Decode fatal errors */
# if !EFSYS_OPT_SIENA
# error "INTR_FATAL requires SIENA"
# endif
#endif /* EFSYS_OPT_DECODE_INTR_FATAL */
#ifdef EFSYS_OPT_FALCON_NIC_CFG_OVERRIDE
@ -61,7 +65,9 @@
#if EFSYS_OPT_FILTER
/* Support hardware packet filters */
# if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD)
# error "FILTER requires SIENA or HUNTINGTON or MEDFORD"
# endif
#endif /* EFSYS_OPT_FILTER */
#ifdef EFSYS_OPT_MAC_FALCON_GMAC
@ -74,9 +80,17 @@
#if EFSYS_OPT_MCDI
/* Support management controller messages */
# if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD)
# error "MCDI requires SIENA or HUNTINGTON or MEDFORD"
# endif
#endif /* EFSYS_OPT_MCDI */
#if (EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD)
# if !EFSYS_OPT_MCDI
# error "SIENA or HUNTINGTON or MEDFORD requires MCDI"
# endif
#endif
#if EFSYS_OPT_MCDI_LOGGING
/* Support MCDI logging */
# if !EFSYS_OPT_MCDI

View File

@ -39,6 +39,61 @@
#if EFSYS_OPT_SIENA
static __checkReturn efx_rc_t
siena_ev_init(
__in efx_nic_t *enp);
static void
siena_ev_fini(
__in efx_nic_t *enp);
static __checkReturn efx_rc_t
siena_ev_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__in uint32_t us,
__in uint32_t flags,
__in efx_evq_t *eep);
static void
siena_ev_qdestroy(
__in efx_evq_t *eep);
static __checkReturn efx_rc_t
siena_ev_qprime(
__in efx_evq_t *eep,
__in unsigned int count);
static void
siena_ev_qpost(
__in efx_evq_t *eep,
__in uint16_t data);
static __checkReturn efx_rc_t
siena_ev_qmoderate(
__in efx_evq_t *eep,
__in unsigned int us);
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_SIENA
static const efx_ev_ops_t __efx_ev_siena_ops = {
siena_ev_init, /* eevo_init */
siena_ev_fini, /* eevo_fini */
siena_ev_qcreate, /* eevo_qcreate */
siena_ev_qdestroy, /* eevo_qdestroy */
siena_ev_qprime, /* eevo_qprime */
siena_ev_qpost, /* eevo_qpost */
siena_ev_qmoderate, /* eevo_qmoderate */
};
#endif /* EFSYS_OPT_SIENA */
__checkReturn efx_rc_t
efx_ev_init(
__in efx_nic_t *enp)
@ -55,6 +110,11 @@ efx_ev_init(
}
switch (enp->en_family) {
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
eevop = &__efx_ev_siena_ops;
break;
#endif /* EFSYS_OPT_SIENA */
default:
EFSYS_ASSERT(0);
@ -440,3 +500,726 @@ efx_ev_qmoderate(
return (rc);
}
#if EFSYS_OPT_SIENA
static __checkReturn efx_rc_t
siena_ev_init(
__in efx_nic_t *enp)
{
efx_oword_t oword;
/*
* Program the event queue for receive and transmit queue
* flush events.
*/
EFX_BAR_READO(enp, FR_AZ_DP_CTRL_REG, &oword);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_FLS_EVQ_ID, 0);
EFX_BAR_WRITEO(enp, FR_AZ_DP_CTRL_REG, &oword);
return (0);
}
static __checkReturn boolean_t
siena_ev_rx_not_ok(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in uint32_t label,
__in uint32_t id,
__inout uint16_t *flagsp)
{
boolean_t ignore = B_FALSE;
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_TOBE_DISC) != 0) {
EFX_EV_QSTAT_INCR(eep, EV_RX_TOBE_DISC);
EFSYS_PROBE(tobe_disc);
/*
* Assume this is a unicast address mismatch, unless below
* we find either FSF_AZ_RX_EV_ETH_CRC_ERR or
* EV_RX_PAUSE_FRM_ERR is set.
*/
(*flagsp) |= EFX_ADDR_MISMATCH;
}
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_FRM_TRUNC) != 0) {
EFSYS_PROBE2(frm_trunc, uint32_t, label, uint32_t, id);
EFX_EV_QSTAT_INCR(eep, EV_RX_FRM_TRUNC);
(*flagsp) |= EFX_DISCARD;
}
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_ETH_CRC_ERR) != 0) {
EFX_EV_QSTAT_INCR(eep, EV_RX_ETH_CRC_ERR);
EFSYS_PROBE(crc_err);
(*flagsp) &= ~EFX_ADDR_MISMATCH;
(*flagsp) |= EFX_DISCARD;
}
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_PAUSE_FRM_ERR) != 0) {
EFX_EV_QSTAT_INCR(eep, EV_RX_PAUSE_FRM_ERR);
EFSYS_PROBE(pause_frm_err);
(*flagsp) &= ~EFX_ADDR_MISMATCH;
(*flagsp) |= EFX_DISCARD;
}
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_BUF_OWNER_ID_ERR) != 0) {
EFX_EV_QSTAT_INCR(eep, EV_RX_BUF_OWNER_ID_ERR);
EFSYS_PROBE(owner_id_err);
(*flagsp) |= EFX_DISCARD;
}
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR) != 0) {
EFX_EV_QSTAT_INCR(eep, EV_RX_IPV4_HDR_CHKSUM_ERR);
EFSYS_PROBE(ipv4_err);
(*flagsp) &= ~EFX_CKSUM_IPV4;
}
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR) != 0) {
EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_UDP_CHKSUM_ERR);
EFSYS_PROBE(udp_chk_err);
(*flagsp) &= ~EFX_CKSUM_TCPUDP;
}
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_IP_FRAG_ERR) != 0) {
EFX_EV_QSTAT_INCR(eep, EV_RX_IP_FRAG_ERR);
/*
* If IP is fragmented FSF_AZ_RX_EV_IP_FRAG_ERR is set. This
* causes FSF_AZ_RX_EV_PKT_OK to be clear. This is not an error
* condition.
*/
(*flagsp) &= ~(EFX_PKT_TCP | EFX_PKT_UDP | EFX_CKSUM_TCPUDP);
}
return (ignore);
}
static __checkReturn boolean_t
siena_ev_rx(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg)
{
uint32_t id;
uint32_t size;
uint32_t label;
boolean_t ok;
uint32_t hdr_type;
boolean_t is_v6;
uint16_t flags;
boolean_t ignore;
boolean_t should_abort;
EFX_EV_QSTAT_INCR(eep, EV_RX);
/* Basic packet information */
id = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_DESC_PTR);
size = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_BYTE_CNT);
label = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_Q_LABEL);
ok = (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_PKT_OK) != 0);
hdr_type = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_HDR_TYPE);
is_v6 = (EFX_QWORD_FIELD(*eqp, FSF_CZ_RX_EV_IPV6_PKT) != 0);
/*
* If packet is marked as OK and packet type is TCP/IP or
* UDP/IP or other IP, then we can rely on the hardware checksums.
*/
switch (hdr_type) {
case FSE_AZ_RX_EV_HDR_TYPE_IPV4V6_TCP:
flags = EFX_PKT_TCP | EFX_CKSUM_TCPUDP;
if (is_v6) {
EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV6);
flags |= EFX_PKT_IPV6;
} else {
EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV4);
flags |= EFX_PKT_IPV4 | EFX_CKSUM_IPV4;
}
break;
case FSE_AZ_RX_EV_HDR_TYPE_IPV4V6_UDP:
flags = EFX_PKT_UDP | EFX_CKSUM_TCPUDP;
if (is_v6) {
EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV6);
flags |= EFX_PKT_IPV6;
} else {
EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV4);
flags |= EFX_PKT_IPV4 | EFX_CKSUM_IPV4;
}
break;
case FSE_AZ_RX_EV_HDR_TYPE_IPV4V6_OTHER:
if (is_v6) {
EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV6);
flags = EFX_PKT_IPV6;
} else {
EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV4);
flags = EFX_PKT_IPV4 | EFX_CKSUM_IPV4;
}
break;
case FSE_AZ_RX_EV_HDR_TYPE_OTHER:
EFX_EV_QSTAT_INCR(eep, EV_RX_NON_IP);
flags = 0;
break;
default:
EFSYS_ASSERT(B_FALSE);
flags = 0;
break;
}
/* Detect errors included in the FSF_AZ_RX_EV_PKT_OK indication */
if (!ok) {
ignore = siena_ev_rx_not_ok(eep, eqp, label, id, &flags);
if (ignore) {
EFSYS_PROBE4(rx_complete, uint32_t, label, uint32_t, id,
uint32_t, size, uint16_t, flags);
return (B_FALSE);
}
}
/* If we're not discarding the packet then it is ok */
if (~flags & EFX_DISCARD)
EFX_EV_QSTAT_INCR(eep, EV_RX_OK);
/* Detect multicast packets that didn't match the filter */
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_MCAST_PKT) != 0) {
EFX_EV_QSTAT_INCR(eep, EV_RX_MCAST_PKT);
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_MCAST_HASH_MATCH) != 0) {
EFX_EV_QSTAT_INCR(eep, EV_RX_MCAST_HASH_MATCH);
} else {
EFSYS_PROBE(mcast_mismatch);
flags |= EFX_ADDR_MISMATCH;
}
} else {
flags |= EFX_PKT_UNICAST;
}
/*
* The packet parser in Siena can abort parsing packets under
* certain error conditions, setting the PKT_NOT_PARSED bit
* (which clears PKT_OK). If this is set, then don't trust
* the PKT_TYPE field.
*/
if (!ok) {
uint32_t parse_err;
parse_err = EFX_QWORD_FIELD(*eqp, FSF_CZ_RX_EV_PKT_NOT_PARSED);
if (parse_err != 0)
flags |= EFX_CHECK_VLAN;
}
if (~flags & EFX_CHECK_VLAN) {
uint32_t pkt_type;
pkt_type = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_PKT_TYPE);
if (pkt_type >= FSE_AZ_RX_EV_PKT_TYPE_VLAN)
flags |= EFX_PKT_VLAN_TAGGED;
}
EFSYS_PROBE4(rx_complete, uint32_t, label, uint32_t, id,
uint32_t, size, uint16_t, flags);
EFSYS_ASSERT(eecp->eec_rx != NULL);
should_abort = eecp->eec_rx(arg, label, id, size, flags);
return (should_abort);
}
static __checkReturn boolean_t
siena_ev_tx(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg)
{
uint32_t id;
uint32_t label;
boolean_t should_abort;
EFX_EV_QSTAT_INCR(eep, EV_TX);
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_COMP) != 0 &&
EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_ERR) == 0 &&
EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_TOO_BIG) == 0 &&
EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_WQ_FF_FULL) == 0) {
id = EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_DESC_PTR);
label = EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_Q_LABEL);
EFSYS_PROBE2(tx_complete, uint32_t, label, uint32_t, id);
EFSYS_ASSERT(eecp->eec_tx != NULL);
should_abort = eecp->eec_tx(arg, label, id);
return (should_abort);
}
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_COMP) != 0)
EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index,
uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1),
uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0));
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_ERR) != 0)
EFX_EV_QSTAT_INCR(eep, EV_TX_PKT_ERR);
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_TOO_BIG) != 0)
EFX_EV_QSTAT_INCR(eep, EV_TX_PKT_TOO_BIG);
if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_WQ_FF_FULL) != 0)
EFX_EV_QSTAT_INCR(eep, EV_TX_WQ_FF_FULL);
EFX_EV_QSTAT_INCR(eep, EV_TX_UNEXPECTED);
return (B_FALSE);
}
static __checkReturn boolean_t
siena_ev_global(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg)
{
_NOTE(ARGUNUSED(eqp, eecp, arg))
EFX_EV_QSTAT_INCR(eep, EV_GLOBAL);
return (B_FALSE);
}
static __checkReturn boolean_t
siena_ev_driver(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg)
{
boolean_t should_abort;
EFX_EV_QSTAT_INCR(eep, EV_DRIVER);
should_abort = B_FALSE;
switch (EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBCODE)) {
case FSE_AZ_TX_DESCQ_FLS_DONE_EV: {
uint32_t txq_index;
EFX_EV_QSTAT_INCR(eep, EV_DRIVER_TX_DESCQ_FLS_DONE);
txq_index = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA);
EFSYS_PROBE1(tx_descq_fls_done, uint32_t, txq_index);
EFSYS_ASSERT(eecp->eec_txq_flush_done != NULL);
should_abort = eecp->eec_txq_flush_done(arg, txq_index);
break;
}
case FSE_AZ_RX_DESCQ_FLS_DONE_EV: {
uint32_t rxq_index;
uint32_t failed;
rxq_index = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_RX_DESCQ_ID);
failed = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
EFSYS_ASSERT(eecp->eec_rxq_flush_done != NULL);
EFSYS_ASSERT(eecp->eec_rxq_flush_failed != NULL);
if (failed) {
EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DESCQ_FLS_FAILED);
EFSYS_PROBE1(rx_descq_fls_failed, uint32_t, rxq_index);
should_abort = eecp->eec_rxq_flush_failed(arg,
rxq_index);
} else {
EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DESCQ_FLS_DONE);
EFSYS_PROBE1(rx_descq_fls_done, uint32_t, rxq_index);
should_abort = eecp->eec_rxq_flush_done(arg, rxq_index);
}
break;
}
case FSE_AZ_EVQ_INIT_DONE_EV:
EFSYS_ASSERT(eecp->eec_initialized != NULL);
should_abort = eecp->eec_initialized(arg);
break;
case FSE_AZ_EVQ_NOT_EN_EV:
EFSYS_PROBE(evq_not_en);
break;
case FSE_AZ_SRM_UPD_DONE_EV: {
uint32_t code;
EFX_EV_QSTAT_INCR(eep, EV_DRIVER_SRM_UPD_DONE);
code = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA);
EFSYS_ASSERT(eecp->eec_sram != NULL);
should_abort = eecp->eec_sram(arg, code);
break;
}
case FSE_AZ_WAKE_UP_EV: {
uint32_t id;
id = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA);
EFSYS_ASSERT(eecp->eec_wake_up != NULL);
should_abort = eecp->eec_wake_up(arg, id);
break;
}
case FSE_AZ_TX_PKT_NON_TCP_UDP:
EFSYS_PROBE(tx_pkt_non_tcp_udp);
break;
case FSE_AZ_TIMER_EV: {
uint32_t id;
id = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA);
EFSYS_ASSERT(eecp->eec_timer != NULL);
should_abort = eecp->eec_timer(arg, id);
break;
}
case FSE_AZ_RX_DSC_ERROR_EV:
EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DSC_ERROR);
EFSYS_PROBE(rx_dsc_error);
EFSYS_ASSERT(eecp->eec_exception != NULL);
should_abort = eecp->eec_exception(arg,
EFX_EXCEPTION_RX_DSC_ERROR, 0);
break;
case FSE_AZ_TX_DSC_ERROR_EV:
EFX_EV_QSTAT_INCR(eep, EV_DRIVER_TX_DSC_ERROR);
EFSYS_PROBE(tx_dsc_error);
EFSYS_ASSERT(eecp->eec_exception != NULL);
should_abort = eecp->eec_exception(arg,
EFX_EXCEPTION_TX_DSC_ERROR, 0);
break;
default:
break;
}
return (should_abort);
}
static __checkReturn boolean_t
siena_ev_drv_gen(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg)
{
uint32_t data;
boolean_t should_abort;
EFX_EV_QSTAT_INCR(eep, EV_DRV_GEN);
data = EFX_QWORD_FIELD(*eqp, FSF_AZ_EV_DATA_DW0);
if (data >= ((uint32_t)1 << 16)) {
EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index,
uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1),
uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0));
return (B_TRUE);
}
EFSYS_ASSERT(eecp->eec_software != NULL);
should_abort = eecp->eec_software(arg, (uint16_t)data);
return (should_abort);
}
#if EFSYS_OPT_MCDI
static __checkReturn boolean_t
siena_ev_mcdi(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg)
{
efx_nic_t *enp = eep->ee_enp;
unsigned int code;
boolean_t should_abort = B_FALSE;
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
if (enp->en_family != EFX_FAMILY_SIENA)
goto out;
EFSYS_ASSERT(eecp->eec_link_change != NULL);
EFSYS_ASSERT(eecp->eec_exception != NULL);
EFX_EV_QSTAT_INCR(eep, EV_MCDI_RESPONSE);
code = EFX_QWORD_FIELD(*eqp, MCDI_EVENT_CODE);
switch (code) {
case MCDI_EVENT_CODE_BADSSERT:
efx_mcdi_ev_death(enp, EINTR);
break;
case MCDI_EVENT_CODE_CMDDONE:
efx_mcdi_ev_cpl(enp,
MCDI_EV_FIELD(eqp, CMDDONE_SEQ),
MCDI_EV_FIELD(eqp, CMDDONE_DATALEN),
MCDI_EV_FIELD(eqp, CMDDONE_ERRNO));
break;
case MCDI_EVENT_CODE_LINKCHANGE: {
efx_link_mode_t link_mode;
siena_phy_link_ev(enp, eqp, &link_mode);
should_abort = eecp->eec_link_change(arg, link_mode);
break;
}
case MCDI_EVENT_CODE_SENSOREVT: {
should_abort = B_FALSE;
break;
}
case MCDI_EVENT_CODE_SCHEDERR:
/* Informational only */
break;
case MCDI_EVENT_CODE_REBOOT:
efx_mcdi_ev_death(enp, EIO);
break;
case MCDI_EVENT_CODE_MAC_STATS_DMA:
break;
case MCDI_EVENT_CODE_FWALERT: {
uint32_t reason = MCDI_EV_FIELD(eqp, FWALERT_REASON);
if (reason == MCDI_EVENT_FWALERT_REASON_SRAM_ACCESS)
should_abort = eecp->eec_exception(arg,
EFX_EXCEPTION_FWALERT_SRAM,
MCDI_EV_FIELD(eqp, FWALERT_DATA));
else
should_abort = eecp->eec_exception(arg,
EFX_EXCEPTION_UNKNOWN_FWALERT,
MCDI_EV_FIELD(eqp, DATA));
break;
}
default:
EFSYS_PROBE1(mc_pcol_error, int, code);
break;
}
out:
return (should_abort);
}
#endif /* EFSYS_OPT_MCDI */
static __checkReturn efx_rc_t
siena_ev_qprime(
__in efx_evq_t *eep,
__in unsigned int count)
{
efx_nic_t *enp = eep->ee_enp;
uint32_t rptr;
efx_dword_t dword;
rptr = count & eep->ee_mask;
EFX_POPULATE_DWORD_1(dword, FRF_AZ_EVQ_RPTR, rptr);
EFX_BAR_TBL_WRITED(enp, FR_AZ_EVQ_RPTR_REG, eep->ee_index,
&dword, B_FALSE);
return (0);
}
static void
siena_ev_qpost(
__in efx_evq_t *eep,
__in uint16_t data)
{
efx_nic_t *enp = eep->ee_enp;
efx_qword_t ev;
efx_oword_t oword;
EFX_POPULATE_QWORD_2(ev, FSF_AZ_EV_CODE, FSE_AZ_EV_CODE_DRV_GEN_EV,
FSF_AZ_EV_DATA_DW0, (uint32_t)data);
EFX_POPULATE_OWORD_3(oword, FRF_AZ_DRV_EV_QID, eep->ee_index,
EFX_DWORD_0, EFX_QWORD_FIELD(ev, EFX_DWORD_0),
EFX_DWORD_1, EFX_QWORD_FIELD(ev, EFX_DWORD_1));
EFX_BAR_WRITEO(enp, FR_AZ_DRV_EV_REG, &oword);
}
static __checkReturn efx_rc_t
siena_ev_qmoderate(
__in efx_evq_t *eep,
__in unsigned int us)
{
efx_nic_t *enp = eep->ee_enp;
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
unsigned int locked;
efx_dword_t dword;
efx_rc_t rc;
if (us > encp->enc_evq_timer_max_us) {
rc = EINVAL;
goto fail1;
}
/* If the value is zero then disable the timer */
if (us == 0) {
EFX_POPULATE_DWORD_2(dword,
FRF_CZ_TC_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS,
FRF_CZ_TC_TIMER_VAL, 0);
} else {
unsigned int ticks;
if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0)
goto fail2;
EFSYS_ASSERT(ticks > 0);
EFX_POPULATE_DWORD_2(dword,
FRF_CZ_TC_TIMER_MODE, FFE_CZ_TIMER_MODE_INT_HLDOFF,
FRF_CZ_TC_TIMER_VAL, ticks - 1);
}
locked = (eep->ee_index == 0) ? 1 : 0;
EFX_BAR_TBL_WRITED(enp, FR_BZ_TIMER_COMMAND_REGP0,
eep->ee_index, &dword, locked);
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
static __checkReturn efx_rc_t
siena_ev_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__in uint32_t us,
__in uint32_t flags,
__in efx_evq_t *eep)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
uint32_t size;
efx_oword_t oword;
efx_rc_t rc;
boolean_t notify_mode;
_NOTE(ARGUNUSED(esmp))
EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MAXNEVS));
EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MINNEVS));
if (!ISP2(n) || (n < EFX_EVQ_MINNEVS) || (n > EFX_EVQ_MAXNEVS)) {
rc = EINVAL;
goto fail1;
}
if (index >= encp->enc_evq_limit) {
rc = EINVAL;
goto fail2;
}
for (size = 0; (1 << size) <= (EFX_EVQ_MAXNEVS / EFX_EVQ_MINNEVS);
size++)
if ((1 << size) == (int)(n / EFX_EVQ_MINNEVS))
break;
if (id + (1 << size) >= encp->enc_buftbl_limit) {
rc = EINVAL;
goto fail4;
}
/* Set up the handler table */
eep->ee_rx = siena_ev_rx;
eep->ee_tx = siena_ev_tx;
eep->ee_driver = siena_ev_driver;
eep->ee_global = siena_ev_global;
eep->ee_drv_gen = siena_ev_drv_gen;
#if EFSYS_OPT_MCDI
eep->ee_mcdi = siena_ev_mcdi;
#endif /* EFSYS_OPT_MCDI */
notify_mode = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) !=
EFX_EVQ_FLAGS_NOTIFY_INTERRUPT);
/* Set up the new event queue */
EFX_POPULATE_OWORD_3(oword, FRF_CZ_TIMER_Q_EN, 1,
FRF_CZ_HOST_NOTIFY_MODE, notify_mode,
FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_TIMER_TBL, index, &oword, B_TRUE);
EFX_POPULATE_OWORD_3(oword, FRF_AZ_EVQ_EN, 1, FRF_AZ_EVQ_SIZE, size,
FRF_AZ_EVQ_BUF_BASE_ID, id);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_EVQ_PTR_TBL, index, &oword, B_TRUE);
/* Set initial interrupt moderation */
siena_ev_qmoderate(eep, us);
return (0);
fail4:
EFSYS_PROBE(fail4);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_SIENA
static void
siena_ev_qdestroy(
__in efx_evq_t *eep)
{
efx_nic_t *enp = eep->ee_enp;
efx_oword_t oword;
/* Purge event queue */
EFX_ZERO_OWORD(oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_EVQ_PTR_TBL,
eep->ee_index, &oword, B_TRUE);
EFX_ZERO_OWORD(oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_TIMER_TBL, eep->ee_index, &oword, B_TRUE);
}
static void
siena_ev_fini(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
}
#endif /* EFSYS_OPT_SIENA */

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,10 @@
#endif
#if EFSYS_OPT_SIENA
#include "siena_impl.h"
#endif /* EFSYS_OPT_SIENA */
#ifdef __cplusplus
extern "C" {
#endif
@ -274,9 +278,70 @@ typedef struct efx_nic_ops_s {
#if EFSYS_OPT_FILTER
#if EFSYS_OPT_SIENA
typedef struct siena_filter_spec_s {
uint8_t sfs_type;
uint32_t sfs_flags;
uint32_t sfs_dmaq_id;
uint32_t sfs_dword[3];
} siena_filter_spec_t;
typedef enum siena_filter_type_e {
EFX_SIENA_FILTER_RX_TCP_FULL, /* TCP/IPv4 {dIP,dTCP,sIP,sTCP} */
EFX_SIENA_FILTER_RX_TCP_WILD, /* TCP/IPv4 {dIP,dTCP, -, -} */
EFX_SIENA_FILTER_RX_UDP_FULL, /* UDP/IPv4 {dIP,dUDP,sIP,sUDP} */
EFX_SIENA_FILTER_RX_UDP_WILD, /* UDP/IPv4 {dIP,dUDP, -, -} */
EFX_SIENA_FILTER_RX_MAC_FULL, /* Ethernet {dMAC,VLAN} */
EFX_SIENA_FILTER_RX_MAC_WILD, /* Ethernet {dMAC, -} */
EFX_SIENA_FILTER_TX_TCP_FULL, /* TCP/IPv4 {dIP,dTCP,sIP,sTCP} */
EFX_SIENA_FILTER_TX_TCP_WILD, /* TCP/IPv4 { -, -,sIP,sTCP} */
EFX_SIENA_FILTER_TX_UDP_FULL, /* UDP/IPv4 {dIP,dTCP,sIP,sTCP} */
EFX_SIENA_FILTER_TX_UDP_WILD, /* UDP/IPv4 { -, -,sIP,sUDP} */
EFX_SIENA_FILTER_TX_MAC_FULL, /* Ethernet {sMAC,VLAN} */
EFX_SIENA_FILTER_TX_MAC_WILD, /* Ethernet {sMAC, -} */
EFX_SIENA_FILTER_NTYPES
} siena_filter_type_t;
typedef enum siena_filter_tbl_id_e {
EFX_SIENA_FILTER_TBL_RX_IP = 0,
EFX_SIENA_FILTER_TBL_RX_MAC,
EFX_SIENA_FILTER_TBL_TX_IP,
EFX_SIENA_FILTER_TBL_TX_MAC,
EFX_SIENA_FILTER_NTBLS
} siena_filter_tbl_id_t;
typedef struct siena_filter_tbl_s {
int sft_size; /* number of entries */
int sft_used; /* active count */
uint32_t *sft_bitmap; /* active bitmap */
siena_filter_spec_t *sft_spec; /* array of saved specs */
} siena_filter_tbl_t;
typedef struct siena_filter_s {
siena_filter_tbl_t sf_tbl[EFX_SIENA_FILTER_NTBLS];
unsigned int sf_depth[EFX_SIENA_FILTER_NTYPES];
} siena_filter_t;
#endif /* EFSYS_OPT_SIENA */
typedef struct efx_filter_s {
#if EFSYS_OPT_SIENA
siena_filter_t *ef_siena_filter;
#endif /* EFSYS_OPT_SIENA */
} efx_filter_t;
#if EFSYS_OPT_SIENA
extern void
siena_filter_tbl_clear(
__in efx_nic_t *enp,
__in siena_filter_tbl_id_t tbl);
#endif /* EFSYS_OPT_SIENA */
#endif /* EFSYS_OPT_FILTER */
#if EFSYS_OPT_MCDI
@ -341,6 +406,11 @@ struct efx_nic_s {
#endif /* EFSYS_OPT_MCDI */
uint32_t en_vport_id;
union {
#if EFSYS_OPT_SIENA
struct {
int enu_unused;
} siena;
#endif /* EFSYS_OPT_SIENA */
int enu_unused;
} en_u;
};

View File

@ -32,6 +32,73 @@
#include "efx_impl.h"
#if EFSYS_OPT_SIENA
static __checkReturn efx_rc_t
siena_intr_init(
__in efx_nic_t *enp,
__in efx_intr_type_t type,
__in efsys_mem_t *esmp);
static void
siena_intr_enable(
__in efx_nic_t *enp);
static void
siena_intr_disable(
__in efx_nic_t *enp);
static void
siena_intr_disable_unlocked(
__in efx_nic_t *enp);
static __checkReturn efx_rc_t
siena_intr_trigger(
__in efx_nic_t *enp,
__in unsigned int level);
static void
siena_intr_fini(
__in efx_nic_t *enp);
static void
siena_intr_status_line(
__in efx_nic_t *enp,
__out boolean_t *fatalp,
__out uint32_t *qmaskp);
static void
siena_intr_status_message(
__in efx_nic_t *enp,
__in unsigned int message,
__out boolean_t *fatalp);
static void
siena_intr_fatal(
__in efx_nic_t *enp);
static __checkReturn boolean_t
siena_intr_check_fatal(
__in efx_nic_t *enp);
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_SIENA
static const efx_intr_ops_t __efx_intr_siena_ops = {
siena_intr_init, /* eio_init */
siena_intr_enable, /* eio_enable */
siena_intr_disable, /* eio_disable */
siena_intr_disable_unlocked, /* eio_disable_unlocked */
siena_intr_trigger, /* eio_trigger */
siena_intr_status_line, /* eio_status_line */
siena_intr_status_message, /* eio_status_message */
siena_intr_fatal, /* eio_fatal */
siena_intr_fini, /* eio_fini */
};
#endif /* EFSYS_OPT_SIENA */
__checkReturn efx_rc_t
efx_intr_init(
__in efx_nic_t *enp,
@ -57,6 +124,11 @@ efx_intr_init(
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 */
default:
EFSYS_ASSERT(B_FALSE);
@ -199,3 +271,276 @@ efx_intr_fatal(
/* ************************************************************************* */
/* ************************************************************************* */
#if EFSYS_OPT_SIENA
static __checkReturn efx_rc_t
siena_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);
efx_oword_t oword;
/*
* bug17213 workaround.
*
* Under legacy interrupts, don't share a level between fatal
* interrupts and event queue interrupts. Under MSI-X, they
* must share, or we won't get an interrupt.
*/
if (enp->en_family == EFX_FAMILY_SIENA &&
eip->ei_type == EFX_INTR_LINE)
eip->ei_level = 0x1f;
else
eip->ei_level = 0;
/* Enable all the genuinely fatal interrupts */
EFX_SET_OWORD(oword);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0);
if (enp->en_family >= EFX_FAMILY_SIENA)
EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0);
EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword);
/* Set up the interrupt address register */
EFX_POPULATE_OWORD_3(oword,
FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0,
FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff,
FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32);
EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
return (0);
}
static void
siena_intr_enable(
__in efx_nic_t *enp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_oword_t oword;
EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1);
EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
}
static void
siena_intr_disable(
__in efx_nic_t *enp)
{
efx_oword_t oword;
EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
EFSYS_SPIN(10);
}
static void
siena_intr_disable_unlocked(
__in efx_nic_t *enp)
{
efx_oword_t oword;
EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
&oword, B_FALSE);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
&oword, B_FALSE);
}
static __checkReturn efx_rc_t
siena_intr_trigger(
__in efx_nic_t *enp,
__in unsigned int level)
{
efx_intr_t *eip = &(enp->en_intr);
efx_oword_t oword;
unsigned int count;
uint32_t sel;
efx_rc_t rc;
/* bug16757: No event queues can be initialized */
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
if (level >= EFX_NINTR_SIENA) {
rc = EINVAL;
goto fail1;
}
if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL))
return (ENOTSUP); /* avoid EFSYS_PROBE() */
sel = level;
/* Trigger a test interrupt */
EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1);
EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
/*
* Wait up to 100ms for the interrupt to be raised before restoring
* KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will
* observe this soon enough anyway), but always reset KER_INT_LEVE_SEL
*/
count = 0;
do {
EFSYS_SPIN(100); /* 100us */
EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
} while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
static __checkReturn boolean_t
siena_intr_check_fatal(
__in efx_nic_t *enp)
{
efx_intr_t *eip = &(enp->en_intr);
efsys_mem_t *esmp = eip->ei_esmp;
efx_oword_t oword;
/* Read the syndrome */
EFSYS_MEM_READO(esmp, 0, &oword);
if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) {
EFSYS_PROBE(fatal);
/* Clear the fatal interrupt condition */
EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0);
EFSYS_MEM_WRITEO(esmp, 0, &oword);
return (B_TRUE);
}
return (B_FALSE);
}
static void
siena_intr_status_line(
__in efx_nic_t *enp,
__out boolean_t *fatalp,
__out uint32_t *qmaskp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_dword_t dword;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
/*
* Read the queue mask and implicitly acknowledge the
* interrupt.
*/
EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
*qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
if (*qmaskp & (1U << eip->ei_level))
*fatalp = siena_intr_check_fatal(enp);
else
*fatalp = B_FALSE;
}
static void
siena_intr_status_message(
__in efx_nic_t *enp,
__in unsigned int message,
__out boolean_t *fatalp)
{
efx_intr_t *eip = &(enp->en_intr);
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
if (message == eip->ei_level)
*fatalp = siena_intr_check_fatal(enp);
else
*fatalp = B_FALSE;
}
static void
siena_intr_fatal(
__in efx_nic_t *enp)
{
#if EFSYS_OPT_DECODE_INTR_FATAL
efx_oword_t fatal;
efx_oword_t mem_per;
EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal);
EFX_ZERO_OWORD(mem_per);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 ||
EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR,
EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0);
if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0)
EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR,
EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
#else
EFSYS_ASSERT(0);
#endif
}
static void
siena_intr_fini(
__in efx_nic_t *enp)
{
efx_oword_t oword;
/* Clear the interrupt address register */
EFX_ZERO_OWORD(oword);
EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
}
#endif /* EFSYS_OPT_SIENA */

View File

@ -31,6 +31,28 @@
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_SIENA
static __checkReturn efx_rc_t
siena_mac_multicast_list_set(
__in efx_nic_t *enp);
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_SIENA
static const efx_mac_ops_t __efx_siena_mac_ops = {
siena_mac_poll, /* emo_poll */
siena_mac_up, /* emo_up */
siena_mac_reconfigure, /* emo_addr_set */
siena_mac_reconfigure, /* emo_pdu_set */
siena_mac_pdu_get, /* emo_pdu_get */
siena_mac_reconfigure, /* emo_reconfigure */
siena_mac_multicast_list_set, /* emo_multicast_list_set */
NULL, /* emo_filter_set_default_rxq */
NULL, /* emo_filter_default_rxq_clear */
};
#endif /* EFSYS_OPT_SIENA */
__checkReturn efx_rc_t
efx_mac_pdu_set(
__in efx_nic_t *enp,
@ -465,6 +487,12 @@ efx_mac_select(
int rc = EINVAL;
switch (enp->en_family) {
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
emop = &__efx_siena_mac_ops;
type = EFX_MAC_SIENA;
break;
#endif /* EFSYS_OPT_SIENA */
default:
rc = EINVAL;
@ -487,3 +515,72 @@ efx_mac_select(
}
#if EFSYS_OPT_SIENA
#define EFX_MAC_HASH_BITS (1 << 8)
/* Compute the multicast hash as used on Falcon and Siena. */
static void
siena_mac_multicast_hash_compute(
__in_ecount(6*count) uint8_t const *addrs,
__in int count,
__out efx_oword_t *hash_low,
__out efx_oword_t *hash_high)
{
uint32_t crc, index;
int i;
EFSYS_ASSERT(hash_low != NULL);
EFSYS_ASSERT(hash_high != NULL);
EFX_ZERO_OWORD(*hash_low);
EFX_ZERO_OWORD(*hash_high);
for (i = 0; i < count; i++) {
/* Calculate hash bucket (IEEE 802.3 CRC32 of the MAC addr) */
crc = efx_crc32_calculate(0xffffffff, addrs, EFX_MAC_ADDR_LEN);
index = crc % EFX_MAC_HASH_BITS;
if (index < 128) {
EFX_SET_OWORD_BIT(*hash_low, index);
} else {
EFX_SET_OWORD_BIT(*hash_high, index - 128);
}
addrs += EFX_MAC_ADDR_LEN;
}
}
static __checkReturn efx_rc_t
siena_mac_multicast_list_set(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
const efx_mac_ops_t *emop = epp->ep_emop;
efx_oword_t old_hash[2];
efx_rc_t rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
memcpy(old_hash, epp->ep_multicst_hash, sizeof (old_hash));
siena_mac_multicast_hash_compute(
epp->ep_mulcst_addr_list,
epp->ep_mulcst_addr_count,
&epp->ep_multicst_hash[0],
&epp->ep_multicst_hash[1]);
if ((rc = emop->emo_reconfigure(enp)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
memcpy(epp->ep_multicst_hash, old_hash, sizeof (old_hash));
return (rc);
}
#endif /* EFSYS_OPT_SIENA */

View File

@ -54,6 +54,23 @@
#if EFSYS_OPT_SIENA
static const efx_mcdi_ops_t __efx_mcdi_siena_ops = {
siena_mcdi_init, /* emco_init */
siena_mcdi_send_request, /* emco_send_request */
siena_mcdi_poll_reboot, /* emco_poll_reboot */
siena_mcdi_poll_response, /* emco_poll_response */
siena_mcdi_read_response, /* emco_read_response */
siena_mcdi_fini, /* emco_fini */
siena_mcdi_feature_supported, /* emco_feature_supported */
siena_mcdi_get_timeout, /* emco_get_timeout */
};
#endif /* EFSYS_OPT_SIENA */
__checkReturn efx_rc_t
efx_mcdi_init(
__in efx_nic_t *enp,
@ -66,6 +83,11 @@ efx_mcdi_init(
EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
switch (enp->en_family) {
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
emcop = &__efx_mcdi_siena_ops;
break;
#endif /* EFSYS_OPT_SIENA */
default:
EFSYS_ASSERT(0);

View File

@ -39,6 +39,20 @@ efx_family(
{
if (venid == EFX_PCI_VENID_SFC) {
switch (devid) {
#if EFSYS_OPT_SIENA
case EFX_PCI_DEVID_SIENA_F1_UNINIT:
/*
* Hardware default for PF0 of uninitialised Siena.
* manftest must be able to cope with this device id.
*/
*efp = EFX_FAMILY_SIENA;
return (0);
case EFX_PCI_DEVID_BETHPAGE:
case EFX_PCI_DEVID_SIENA:
*efp = EFX_FAMILY_SIENA;
return (0);
#endif /* EFSYS_OPT_SIENA */
case EFX_PCI_DEVID_FALCON: /* Obsolete, not supported */
default:
@ -122,6 +136,22 @@ efx_nic_biu_test(
return (rc);
}
#if EFSYS_OPT_SIENA
static const efx_nic_ops_t __efx_nic_siena_ops = {
siena_nic_probe, /* eno_probe */
NULL, /* eno_board_cfg */
NULL, /* eno_set_drv_limits */
siena_nic_reset, /* eno_reset */
siena_nic_init, /* eno_init */
NULL, /* eno_get_vi_pool */
NULL, /* eno_get_bar_region */
siena_nic_fini, /* eno_fini */
siena_nic_unprobe, /* eno_unprobe */
};
#endif /* EFSYS_OPT_SIENA */
__checkReturn efx_rc_t
efx_nic_create(
@ -148,6 +178,20 @@ efx_nic_create(
enp->en_magic = EFX_NIC_MAGIC;
switch (family) {
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
enp->en_enop = &__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_MCDI |
EFX_FEATURE_LOOKAHEAD_SPLIT |
EFX_FEATURE_MAC_HEADER_FILTERS |
EFX_FEATURE_TX_SRC_FILTERS;
break;
#endif /* EFSYS_OPT_SIENA */
default:
rc = ENOTSUP;

View File

@ -32,6 +32,16 @@
#include "efx_impl.h"
#if EFSYS_OPT_SIENA
static const efx_phy_ops_t __efx_phy_siena_ops = {
siena_phy_power, /* epo_power */
NULL, /* epo_reset */
siena_phy_reconfigure, /* epo_reconfigure */
siena_phy_verify, /* epo_verify */
siena_phy_oui_get, /* epo_oui_get */
};
#endif /* EFSYS_OPT_SIENA */
__checkReturn efx_rc_t
efx_phy_probe(
__in efx_nic_t *enp)
@ -48,6 +58,11 @@ efx_phy_probe(
/* Hook in operations structure */
switch (enp->en_family) {
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
epop = &__efx_phy_siena_ops;
break;
#endif /* EFSYS_OPT_SIENA */
default:
rc = ENOTSUP;
goto fail1;

View File

@ -32,6 +32,79 @@
#include "efx_impl.h"
#if EFSYS_OPT_SIENA
static __checkReturn efx_rc_t
siena_rx_init(
__in efx_nic_t *enp);
static void
siena_rx_fini(
__in efx_nic_t *enp);
static __checkReturn efx_rc_t
siena_rx_prefix_pktlen(
__in efx_nic_t *enp,
__in uint8_t *buffer,
__out uint16_t *lengthp);
static void
siena_rx_qpost(
__in efx_rxq_t *erp,
__in_ecount(n) efsys_dma_addr_t *addrp,
__in size_t size,
__in unsigned int n,
__in unsigned int completed,
__in unsigned int added);
static void
siena_rx_qpush(
__in efx_rxq_t *erp,
__in unsigned int added,
__inout unsigned int *pushedp);
static __checkReturn efx_rc_t
siena_rx_qflush(
__in efx_rxq_t *erp);
static void
siena_rx_qenable(
__in efx_rxq_t *erp);
static __checkReturn efx_rc_t
siena_rx_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in unsigned int label,
__in efx_rxq_type_t type,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__in efx_evq_t *eep,
__in efx_rxq_t *erp);
static void
siena_rx_qdestroy(
__in efx_rxq_t *erp);
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_SIENA
static const efx_rx_ops_t __efx_rx_siena_ops = {
siena_rx_init, /* erxo_init */
siena_rx_fini, /* erxo_fini */
siena_rx_prefix_pktlen, /* erxo_prefix_pktlen */
siena_rx_qpost, /* erxo_qpost */
siena_rx_qpush, /* erxo_qpush */
siena_rx_qflush, /* erxo_qflush */
siena_rx_qenable, /* erxo_qenable */
siena_rx_qcreate, /* erxo_qcreate */
siena_rx_qdestroy, /* erxo_qdestroy */
};
#endif /* EFSYS_OPT_SIENA */
__checkReturn efx_rc_t
efx_rx_init(
__inout efx_nic_t *enp)
@ -53,6 +126,11 @@ efx_rx_init(
}
switch (enp->en_family) {
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
erxop = &__efx_rx_siena_ops;
break;
#endif /* EFSYS_OPT_SIENA */
default:
EFSYS_ASSERT(0);
@ -240,3 +318,342 @@ efx_pseudo_hdr_pkt_length_get(
return (erxop->erxo_prefix_pktlen(enp, buffer, lengthp));
}
#if EFSYS_OPT_SIENA
static __checkReturn efx_rc_t
siena_rx_init(
__in efx_nic_t *enp)
{
efx_oword_t oword;
unsigned int index;
EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword);
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_DESC_PUSH_EN, 0);
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_ALG, 0);
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_IP_HASH, 0);
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_TCP_SUP, 0);
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_INSRT_HDR, 0);
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_USR_BUF_SIZE, 0x3000 / 32);
EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword);
/* Zero the RSS table */
for (index = 0; index < FR_BZ_RX_INDIRECTION_TBL_ROWS;
index++) {
EFX_ZERO_OWORD(oword);
EFX_BAR_TBL_WRITEO(enp, FR_BZ_RX_INDIRECTION_TBL,
index, &oword, B_TRUE);
}
return (0);
}
#define EFX_RX_LFSR_HASH(_enp, _insert) \
do { \
efx_oword_t oword; \
\
EFX_BAR_READO((_enp), FR_AZ_RX_CFG_REG, &oword); \
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_ALG, 0); \
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_IP_HASH, 0); \
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_TCP_SUP, 0); \
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_INSRT_HDR, \
(_insert) ? 1 : 0); \
EFX_BAR_WRITEO((_enp), FR_AZ_RX_CFG_REG, &oword); \
\
if ((_enp)->en_family == EFX_FAMILY_SIENA) { \
EFX_BAR_READO((_enp), FR_CZ_RX_RSS_IPV6_REG3, \
&oword); \
EFX_SET_OWORD_FIELD(oword, \
FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 0); \
EFX_BAR_WRITEO((_enp), FR_CZ_RX_RSS_IPV6_REG3, \
&oword); \
} \
\
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_RX_TOEPLITZ_IPV4_HASH(_enp, _insert, _ip, _tcp) \
do { \
efx_oword_t oword; \
\
EFX_BAR_READO((_enp), FR_AZ_RX_CFG_REG, &oword); \
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_ALG, 1); \
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_IP_HASH, \
(_ip) ? 1 : 0); \
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_TCP_SUP, \
(_tcp) ? 0 : 1); \
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_INSRT_HDR, \
(_insert) ? 1 : 0); \
EFX_BAR_WRITEO((_enp), FR_AZ_RX_CFG_REG, &oword); \
\
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_RX_TOEPLITZ_IPV6_HASH(_enp, _ip, _tcp, _rc) \
do { \
efx_oword_t oword; \
\
EFX_BAR_READO((_enp), FR_CZ_RX_RSS_IPV6_REG3, &oword); \
EFX_SET_OWORD_FIELD(oword, \
FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 1); \
EFX_SET_OWORD_FIELD(oword, \
FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE, (_ip) ? 1 : 0); \
EFX_SET_OWORD_FIELD(oword, \
FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS, (_tcp) ? 0 : 1); \
EFX_BAR_WRITEO((_enp), FR_CZ_RX_RSS_IPV6_REG3, &oword); \
\
(_rc) = 0; \
\
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
/*
* Falcon/Siena pseudo-header
* --------------------------
*
* Receive packets are prefixed by an optional 16 byte pseudo-header.
* The pseudo-header is a byte array of one of the forms:
*
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
* xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.TT.TT.TT.TT
* xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.LL.LL
*
* where:
* TT.TT.TT.TT Toeplitz hash (32-bit big-endian)
* LL.LL LFSR hash (16-bit big-endian)
*/
static __checkReturn efx_rc_t
siena_rx_prefix_pktlen(
__in efx_nic_t *enp,
__in uint8_t *buffer,
__out uint16_t *lengthp)
{
_NOTE(ARGUNUSED(enp, buffer, lengthp))
/* Not supported by Falcon/Siena hardware */
EFSYS_ASSERT(0);
return (ENOTSUP);
}
static void
siena_rx_qpost(
__in efx_rxq_t *erp,
__in_ecount(n) efsys_dma_addr_t *addrp,
__in size_t size,
__in unsigned int n,
__in unsigned int completed,
__in unsigned int added)
{
efx_qword_t qword;
unsigned int i;
unsigned int offset;
unsigned int id;
/* The client driver must not overfill the queue */
EFSYS_ASSERT3U(added - completed + n, <=,
EFX_RXQ_LIMIT(erp->er_mask + 1));
id = added & (erp->er_mask);
for (i = 0; i < n; i++) {
EFSYS_PROBE4(rx_post, unsigned int, erp->er_index,
unsigned int, id, efsys_dma_addr_t, addrp[i],
size_t, size);
EFX_POPULATE_QWORD_3(qword,
FSF_AZ_RX_KER_BUF_SIZE, (uint32_t)(size),
FSF_AZ_RX_KER_BUF_ADDR_DW0,
(uint32_t)(addrp[i] & 0xffffffff),
FSF_AZ_RX_KER_BUF_ADDR_DW1,
(uint32_t)(addrp[i] >> 32));
offset = id * sizeof (efx_qword_t);
EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword);
id = (id + 1) & (erp->er_mask);
}
}
static void
siena_rx_qpush(
__in efx_rxq_t *erp,
__in unsigned int added,
__inout unsigned int *pushedp)
{
efx_nic_t *enp = erp->er_enp;
unsigned int pushed = *pushedp;
uint32_t wptr;
efx_oword_t oword;
efx_dword_t dword;
/* All descriptors are pushed */
*pushedp = added;
/* Push the populated descriptors out */
wptr = added & erp->er_mask;
EFX_POPULATE_OWORD_1(oword, FRF_AZ_RX_DESC_WPTR, wptr);
/* Only write the third DWORD */
EFX_POPULATE_DWORD_1(dword,
EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3));
/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1,
wptr, pushed & erp->er_mask);
EFSYS_PIO_WRITE_BARRIER();
EFX_BAR_TBL_WRITED3(enp, FR_BZ_RX_DESC_UPD_REGP0,
erp->er_index, &dword, B_FALSE);
}
static __checkReturn efx_rc_t
siena_rx_qflush(
__in efx_rxq_t *erp)
{
efx_nic_t *enp = erp->er_enp;
efx_oword_t oword;
uint32_t label;
label = erp->er_index;
/* Flush the queue */
EFX_POPULATE_OWORD_2(oword, FRF_AZ_RX_FLUSH_DESCQ_CMD, 1,
FRF_AZ_RX_FLUSH_DESCQ, label);
EFX_BAR_WRITEO(enp, FR_AZ_RX_FLUSH_DESCQ_REG, &oword);
return (0);
}
static void
siena_rx_qenable(
__in efx_rxq_t *erp)
{
efx_nic_t *enp = erp->er_enp;
efx_oword_t oword;
EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
EFX_BAR_TBL_READO(enp, FR_AZ_RX_DESC_PTR_TBL,
erp->er_index, &oword, B_TRUE);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_RX_DC_HW_RPTR, 0);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_RX_DESCQ_HW_RPTR, 0);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_RX_DESCQ_EN, 1);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_DESC_PTR_TBL,
erp->er_index, &oword, B_TRUE);
}
static __checkReturn efx_rc_t
siena_rx_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in unsigned int label,
__in efx_rxq_type_t type,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__in efx_evq_t *eep,
__in efx_rxq_t *erp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_oword_t oword;
uint32_t size;
boolean_t jumbo;
efx_rc_t rc;
_NOTE(ARGUNUSED(esmp))
EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS ==
(1 << FRF_AZ_RX_DESCQ_LABEL_WIDTH));
EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS);
EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit);
EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS));
EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS));
if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) {
rc = EINVAL;
goto fail1;
}
if (index >= encp->enc_rxq_limit) {
rc = EINVAL;
goto fail2;
}
for (size = 0; (1 << size) <= (EFX_RXQ_MAXNDESCS / EFX_RXQ_MINNDESCS);
size++)
if ((1 << size) == (int)(n / EFX_RXQ_MINNDESCS))
break;
if (id + (1 << size) >= encp->enc_buftbl_limit) {
rc = EINVAL;
goto fail3;
}
switch (type) {
case EFX_RXQ_TYPE_DEFAULT:
jumbo = B_FALSE;
break;
default:
rc = EINVAL;
goto fail4;
}
/* Set up the new descriptor queue */
EFX_POPULATE_OWORD_7(oword,
FRF_AZ_RX_DESCQ_BUF_BASE_ID, id,
FRF_AZ_RX_DESCQ_EVQ_ID, eep->ee_index,
FRF_AZ_RX_DESCQ_OWNER_ID, 0,
FRF_AZ_RX_DESCQ_LABEL, label,
FRF_AZ_RX_DESCQ_SIZE, size,
FRF_AZ_RX_DESCQ_TYPE, 0,
FRF_AZ_RX_DESCQ_JUMBO, jumbo);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_DESC_PTR_TBL,
erp->er_index, &oword, B_TRUE);
return (0);
fail4:
EFSYS_PROBE(fail4);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
static void
siena_rx_qdestroy(
__in efx_rxq_t *erp)
{
efx_nic_t *enp = erp->er_enp;
efx_oword_t oword;
EFSYS_ASSERT(enp->en_rx_qcount != 0);
--enp->en_rx_qcount;
/* Purge descriptor queue */
EFX_ZERO_OWORD(oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_DESC_PTR_TBL,
erp->er_index, &oword, B_TRUE);
/* Free the RXQ object */
EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
}
static void
siena_rx_fini(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
}
#endif /* EFSYS_OPT_SIENA */

View File

@ -33,6 +33,101 @@
#define EFX_TX_QSTAT_INCR(_etp, _stat)
#if EFSYS_OPT_SIENA
static __checkReturn efx_rc_t
siena_tx_init(
__in efx_nic_t *enp);
static void
siena_tx_fini(
__in efx_nic_t *enp);
static __checkReturn efx_rc_t
siena_tx_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in unsigned int label,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__in uint16_t flags,
__in efx_evq_t *eep,
__in efx_txq_t *etp,
__out unsigned int *addedp);
static void
siena_tx_qdestroy(
__in efx_txq_t *etp);
static __checkReturn efx_rc_t
siena_tx_qpost(
__in efx_txq_t *etp,
__in_ecount(n) efx_buffer_t *eb,
__in unsigned int n,
__in unsigned int completed,
__inout unsigned int *addedp);
static void
siena_tx_qpush(
__in efx_txq_t *etp,
__in unsigned int added,
__in unsigned int pushed);
static __checkReturn efx_rc_t
siena_tx_qpace(
__in efx_txq_t *etp,
__in unsigned int ns);
static __checkReturn efx_rc_t
siena_tx_qflush(
__in efx_txq_t *etp);
static void
siena_tx_qenable(
__in efx_txq_t *etp);
__checkReturn efx_rc_t
siena_tx_qdesc_post(
__in efx_txq_t *etp,
__in_ecount(n) efx_desc_t *ed,
__in unsigned int n,
__in unsigned int completed,
__inout unsigned int *addedp);
void
siena_tx_qdesc_dma_create(
__in efx_txq_t *etp,
__in efsys_dma_addr_t addr,
__in size_t size,
__in boolean_t eop,
__out efx_desc_t *edp);
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_SIENA
static const efx_tx_ops_t __efx_tx_siena_ops = {
siena_tx_init, /* etxo_init */
siena_tx_fini, /* etxo_fini */
siena_tx_qcreate, /* etxo_qcreate */
siena_tx_qdestroy, /* etxo_qdestroy */
siena_tx_qpost, /* etxo_qpost */
siena_tx_qpush, /* etxo_qpush */
siena_tx_qpace, /* etxo_qpace */
siena_tx_qflush, /* etxo_qflush */
siena_tx_qenable, /* etxo_qenable */
NULL, /* etxo_qpio_enable */
NULL, /* etxo_qpio_disable */
NULL, /* etxo_qpio_write */
NULL, /* etxo_qpio_post */
siena_tx_qdesc_post, /* etxo_qdesc_post */
siena_tx_qdesc_dma_create, /* etxo_qdesc_dma_create */
NULL, /* etxo_qdesc_tso_create */
NULL, /* etxo_qdesc_tso2_create */
NULL, /* etxo_qdesc_vlantci_create */
};
#endif /* EFSYS_OPT_SIENA */
__checkReturn efx_rc_t
efx_tx_init(
@ -55,6 +150,11 @@ efx_tx_init(
}
switch (enp->en_family) {
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
etxop = &__efx_tx_siena_ops;
break;
#endif /* EFSYS_OPT_SIENA */
default:
EFSYS_ASSERT(0);
@ -461,3 +561,391 @@ efx_tx_qdesc_vlantci_create(
}
#if EFSYS_OPT_SIENA
static __checkReturn efx_rc_t
siena_tx_init(
__in efx_nic_t *enp)
{
efx_oword_t oword;
/*
* 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);
return (0);
}
#define EFX_TX_DESC(_etp, _addr, _size, _eop, _added) \
do { \
unsigned int id; \
size_t offset; \
efx_qword_t qword; \
\
id = (_added)++ & (_etp)->et_mask; \
offset = id * sizeof (efx_qword_t); \
\
EFSYS_PROBE5(tx_post, unsigned int, (_etp)->et_index, \
unsigned int, id, efsys_dma_addr_t, (_addr), \
size_t, (_size), boolean_t, (_eop)); \
\
EFX_POPULATE_QWORD_4(qword, \
FSF_AZ_TX_KER_CONT, (_eop) ? 0 : 1, \
FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)(_size), \
FSF_AZ_TX_KER_BUF_ADDR_DW0, \
(uint32_t)((_addr) & 0xffffffff), \
FSF_AZ_TX_KER_BUF_ADDR_DW1, \
(uint32_t)((_addr) >> 32)); \
EFSYS_MEM_WRITEQ((_etp)->et_esmp, offset, &qword); \
\
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
static __checkReturn efx_rc_t
siena_tx_qpost(
__in efx_txq_t *etp,
__in_ecount(n) efx_buffer_t *eb,
__in unsigned int n,
__in unsigned int completed,
__inout unsigned int *addedp)
{
unsigned int added = *addedp;
unsigned int i;
int rc = ENOSPC;
if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1))
goto fail1;
for (i = 0; i < n; i++) {
efx_buffer_t *ebp = &eb[i];
efsys_dma_addr_t start = ebp->eb_addr;
size_t size = ebp->eb_size;
efsys_dma_addr_t end = start + size;
/* Fragments must not span 4k boundaries. */
EFSYS_ASSERT(P2ROUNDUP(start + 1, 4096) >= end);
EFX_TX_DESC(etp, start, size, ebp->eb_eop, added);
}
EFX_TX_QSTAT_INCR(etp, TX_POST);
*addedp = added;
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
static void
siena_tx_qpush(
__in efx_txq_t *etp,
__in unsigned int added,
__in unsigned int pushed)
{
efx_nic_t *enp = etp->et_enp;
uint32_t wptr;
efx_dword_t dword;
efx_oword_t oword;
/* Push the populated descriptors out */
wptr = added & etp->et_mask;
EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_DESC_WPTR, wptr);
/* Only write the third DWORD */
EFX_POPULATE_DWORD_1(dword,
EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3));
/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1,
wptr, pushed & etp->et_mask);
EFSYS_PIO_WRITE_BARRIER();
EFX_BAR_TBL_WRITED3(enp, FR_BZ_TX_DESC_UPD_REGP0,
etp->et_index, &dword, B_FALSE);
}
#define EFX_MAX_PACE_VALUE 20
static __checkReturn efx_rc_t
siena_tx_qpace(
__in efx_txq_t *etp,
__in unsigned int ns)
{
efx_nic_t *enp = etp->et_enp;
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_oword_t oword;
unsigned int pace_val;
unsigned int timer_period;
efx_rc_t rc;
if (ns == 0) {
pace_val = 0;
} else {
/*
* The pace_val to write into the table is s.t
* ns <= timer_period * (2 ^ pace_val)
*/
timer_period = 104 / encp->enc_clk_mult;
for (pace_val = 1; pace_val <= EFX_MAX_PACE_VALUE; pace_val++) {
if ((timer_period << pace_val) >= ns)
break;
}
}
if (pace_val > EFX_MAX_PACE_VALUE) {
rc = EINVAL;
goto fail1;
}
/* Update the pacing table */
EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_PACE, pace_val);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_PACE_TBL, etp->et_index,
&oword, B_TRUE);
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
static __checkReturn efx_rc_t
siena_tx_qflush(
__in efx_txq_t *etp)
{
efx_nic_t *enp = etp->et_enp;
efx_oword_t oword;
uint32_t label;
efx_tx_qpace(etp, 0);
label = etp->et_index;
/* Flush the queue */
EFX_POPULATE_OWORD_2(oword, FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
FRF_AZ_TX_FLUSH_DESCQ, label);
EFX_BAR_WRITEO(enp, FR_AZ_TX_FLUSH_DESCQ_REG, &oword);
return (0);
}
static void
siena_tx_qenable(
__in efx_txq_t *etp)
{
efx_nic_t *enp = etp->et_enp;
efx_oword_t oword;
EFX_BAR_TBL_READO(enp, FR_AZ_TX_DESC_PTR_TBL,
etp->et_index, &oword, B_TRUE);
EFSYS_PROBE5(tx_descq_ptr, unsigned int, etp->et_index,
uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_3),
uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_2),
uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_1),
uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_0));
EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DC_HW_RPTR, 0);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_HW_RPTR, 0);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_EN, 1);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
etp->et_index, &oword, B_TRUE);
}
static __checkReturn efx_rc_t
siena_tx_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in unsigned int label,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__in uint16_t flags,
__in efx_evq_t *eep,
__in efx_txq_t *etp,
__out unsigned int *addedp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_oword_t oword;
uint32_t size;
efx_rc_t rc;
_NOTE(ARGUNUSED(esmp))
EFX_STATIC_ASSERT(EFX_EV_TX_NLABELS ==
(1 << FRF_AZ_TX_DESCQ_LABEL_WIDTH));
EFSYS_ASSERT3U(label, <, EFX_EV_TX_NLABELS);
EFSYS_ASSERT(ISP2(encp->enc_txq_max_ndescs));
EFX_STATIC_ASSERT(ISP2(EFX_TXQ_MINNDESCS));
if (!ISP2(n) || (n < EFX_TXQ_MINNDESCS) || (n > EFX_EVQ_MAXNEVS)) {
rc = EINVAL;
goto fail1;
}
if (index >= encp->enc_txq_limit) {
rc = EINVAL;
goto fail2;
}
for (size = 0;
(1 << size) <= (int)(encp->enc_txq_max_ndescs / EFX_TXQ_MINNDESCS);
size++)
if ((1 << size) == (int)(n / EFX_TXQ_MINNDESCS))
break;
if (id + (1 << size) >= encp->enc_buftbl_limit) {
rc = EINVAL;
goto fail3;
}
/* Set up the new descriptor queue */
*addedp = 0;
EFX_POPULATE_OWORD_6(oword,
FRF_AZ_TX_DESCQ_BUF_BASE_ID, id,
FRF_AZ_TX_DESCQ_EVQ_ID, eep->ee_index,
FRF_AZ_TX_DESCQ_OWNER_ID, 0,
FRF_AZ_TX_DESCQ_LABEL, label,
FRF_AZ_TX_DESCQ_SIZE, size,
FRF_AZ_TX_DESCQ_TYPE, 0);
EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_NON_IP_DROP_DIS, 1);
EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_IP_CHKSM_DIS,
(flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1);
EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_TCP_CHKSM_DIS,
(flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
etp->et_index, &oword, B_TRUE);
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
__checkReturn efx_rc_t
siena_tx_qdesc_post(
__in efx_txq_t *etp,
__in_ecount(n) efx_desc_t *ed,
__in unsigned int n,
__in unsigned int completed,
__inout unsigned int *addedp)
{
unsigned int added = *addedp;
unsigned int i;
efx_rc_t rc;
if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
rc = ENOSPC;
goto fail1;
}
for (i = 0; i < n; i++) {
efx_desc_t *edp = &ed[i];
unsigned int id;
size_t offset;
id = added++ & etp->et_mask;
offset = id * sizeof (efx_desc_t);
EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq);
}
EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index,
unsigned int, added, unsigned int, n);
EFX_TX_QSTAT_INCR(etp, TX_POST);
*addedp = added;
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
void
siena_tx_qdesc_dma_create(
__in efx_txq_t *etp,
__in efsys_dma_addr_t addr,
__in size_t size,
__in boolean_t eop,
__out efx_desc_t *edp)
{
/* Fragments must not span 4k boundaries. */
EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= addr + size);
EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index,
efsys_dma_addr_t, addr,
size_t, size, boolean_t, eop);
EFX_POPULATE_QWORD_4(edp->ed_eq,
FSF_AZ_TX_KER_CONT, eop ? 0 : 1,
FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)size,
FSF_AZ_TX_KER_BUF_ADDR_DW0,
(uint32_t)(addr & 0xffffffff),
FSF_AZ_TX_KER_BUF_ADDR_DW1,
(uint32_t)(addr >> 32));
}
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_SIENA
static void
siena_tx_qdestroy(
__in efx_txq_t *etp)
{
efx_nic_t *enp = etp->et_enp;
efx_oword_t oword;
/* Purge descriptor queue */
EFX_ZERO_OWORD(oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
etp->et_index, &oword, B_TRUE);
}
static void
siena_tx_fini(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
}
#endif /* EFSYS_OPT_SIENA */

View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2007-2016 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#ifndef _SYS_SIENA_FLASH_H
#define _SYS_SIENA_FLASH_H
#pragma pack(1)
/* Fixed locations near the start of flash (which may be in the internal PHY
* firmware header) point to the boot header.
*
* - parsed by MC boot ROM and firmware
* - reserved (but not parsed) by PHY firmware
* - opaque to driver
*/
#define SIENA_MC_BOOT_PHY_FW_HDR_LEN (0x20)
#define SIENA_MC_BOOT_PTR_LOCATION (0x18) /* First thing we try to boot */
#define SIENA_MC_BOOT_ALT_PTR_LOCATION (0x1c) /* Alternative if that fails */
#define SIENA_MC_BOOT_HDR_LEN (0x200)
#define SIENA_MC_BOOT_MAGIC (0x51E4A001)
#define SIENA_MC_BOOT_VERSION (1)
/*Structures supporting an arbitrary number of binary blobs in the flash image
intended to house code and tables for the satellite cpus*/
/*thanks to random.org for:*/
#define BLOBS_HEADER_MAGIC (0xBDA3BBD4)
#define BLOB_HEADER_MAGIC (0xA1478A91)
typedef struct blobs_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t magic;
efx_dword_t no_of_blobs;
} blobs_hdr_t;
typedef struct blob_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t magic;
efx_dword_t cpu_type;
efx_dword_t build_variant;
efx_dword_t offset;
efx_dword_t length;
efx_dword_t checksum;
} blob_hdr_t;
#define BLOB_CPU_TYPE_TXDI_TEXT (0)
#define BLOB_CPU_TYPE_RXDI_TEXT (1)
#define BLOB_CPU_TYPE_TXDP_TEXT (2)
#define BLOB_CPU_TYPE_RXDP_TEXT (3)
#define BLOB_CPU_TYPE_RXHRSL_HR_LUT (4)
#define BLOB_CPU_TYPE_RXHRSL_HR_LUT_CFG (5)
#define BLOB_CPU_TYPE_TXHRSL_HR_LUT (6)
#define BLOB_CPU_TYPE_TXHRSL_HR_LUT_CFG (7)
#define BLOB_CPU_TYPE_RXHRSL_HR_PGM (8)
#define BLOB_CPU_TYPE_RXHRSL_SL_PGM (9)
#define BLOB_CPU_TYPE_TXHRSL_HR_PGM (10)
#define BLOB_CPU_TYPE_TXHRSL_SL_PGM (11)
#define BLOB_CPU_TYPE_RXDI_VTBL0 (12)
#define BLOB_CPU_TYPE_TXDI_VTBL0 (13)
#define BLOB_CPU_TYPE_RXDI_VTBL1 (14)
#define BLOB_CPU_TYPE_TXDI_VTBL1 (15)
#define BLOB_CPU_TYPE_DUMPSPEC (32)
#define BLOB_CPU_TYPE_MC_XIP (33)
#define BLOB_CPU_TYPE_INVALID (31)
/*
* The upper four bits of the CPU type field specify the compression
* algorithm used for this blob.
*/
#define BLOB_COMPRESSION_MASK (0xf0000000)
#define BLOB_CPU_TYPE_MASK (0x0fffffff)
#define BLOB_COMPRESSION_NONE (0x00000000) /* Stored as is */
#define BLOB_COMPRESSION_LZ (0x10000000) /* see lib/lzdecoder.c */
typedef struct siena_mc_boot_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t magic; /* = SIENA_MC_BOOT_MAGIC */
efx_word_t hdr_version; /* this structure definition is version 1 */
efx_byte_t board_type;
efx_byte_t firmware_version_a;
efx_byte_t firmware_version_b;
efx_byte_t firmware_version_c;
efx_word_t checksum; /* of whole header area + firmware image */
efx_word_t firmware_version_d;
efx_byte_t mcfw_subtype;
efx_byte_t generation; /* Valid for medford, SBZ for earlier chips */
efx_dword_t firmware_text_offset; /* offset to firmware .text */
efx_dword_t firmware_text_size; /* length of firmware .text, in bytes */
efx_dword_t firmware_data_offset; /* offset to firmware .data */
efx_dword_t firmware_data_size; /* length of firmware .data, in bytes */
efx_byte_t spi_rate; /* SPI rate for reading image, 0 is BootROM default */
efx_byte_t spi_phase_adj; /* SPI SDO/SCL phase adjustment, 0 is default (no adj) */
efx_word_t xpm_sector; /* The sector that contains the key, or 0xffff if unsigned (medford) SBZ (earlier) */
efx_dword_t reserved_c[7]; /* (set to 0) */
} siena_mc_boot_hdr_t;
#define SIENA_MC_BOOT_HDR_PADDING \
(SIENA_MC_BOOT_HDR_LEN - sizeof(siena_mc_boot_hdr_t))
#define SIENA_MC_STATIC_CONFIG_MAGIC (0xBDCF5555)
#define SIENA_MC_STATIC_CONFIG_VERSION (0)
typedef struct siena_mc_static_config_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t magic; /* = SIENA_MC_STATIC_CONFIG_MAGIC */
efx_word_t length; /* of header area (i.e. not including VPD) */
efx_byte_t version;
efx_byte_t csum; /* over header area (i.e. not including VPD) */
efx_dword_t static_vpd_offset;
efx_dword_t static_vpd_length;
efx_dword_t capabilities;
efx_byte_t mac_addr_base[6];
efx_byte_t green_mode_cal; /* Green mode calibration result */
efx_byte_t green_mode_valid; /* Whether cal holds a valid value */
efx_word_t mac_addr_count;
efx_word_t mac_addr_stride;
efx_word_t calibrated_vref; /* Vref as measured during production */
efx_word_t adc_vref; /* Vref as read by ADC */
efx_dword_t reserved2[1]; /* (write as zero) */
efx_dword_t num_dbi_items;
struct {
efx_word_t addr;
efx_word_t byte_enables;
efx_dword_t value;
} dbi[];
} siena_mc_static_config_hdr_t;
/* This prefixes a valid XIP partition */
#define XIP_PARTITION_MAGIC (0x51DEC0DE)
#define SIENA_MC_DYNAMIC_CONFIG_MAGIC (0xBDCFDDDD)
#define SIENA_MC_DYNAMIC_CONFIG_VERSION (0)
typedef struct siena_mc_fw_version_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t fw_subtype;
efx_word_t version_w;
efx_word_t version_x;
efx_word_t version_y;
efx_word_t version_z;
} siena_mc_fw_version_t;
typedef struct siena_mc_dynamic_config_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t magic; /* = SIENA_MC_DYNAMIC_CONFIG_MAGIC */
efx_word_t length; /* of header area (i.e. not including VPD) */
efx_byte_t version;
efx_byte_t csum; /* over header area (i.e. not including VPD) */
efx_dword_t dynamic_vpd_offset;
efx_dword_t dynamic_vpd_length;
efx_dword_t num_fw_version_items;
siena_mc_fw_version_t fw_version[];
} siena_mc_dynamic_config_hdr_t;
#define SIENA_MC_EXPROM_SINGLE_MAGIC (0xAA55) /* little-endian uint16_t */
#define SIENA_MC_EXPROM_COMBO_MAGIC (0xB0070102) /* little-endian uint32_t */
#define SIENA_MC_EXPROM_COMBO_V2_MAGIC (0xB0070103) /* little-endian uint32_t */
typedef struct siena_mc_combo_rom_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t magic; /* = SIENA_MC_EXPROM_COMBO_MAGIC or SIENA_MC_EXPROM_COMBO_V2_MAGIC */
union {
struct {
efx_dword_t len1; /* length of first image */
efx_dword_t len2; /* length of second image */
efx_dword_t off1; /* offset of first byte to edit to combine images */
efx_dword_t off2; /* offset of second byte to edit to combine images */
efx_word_t infoblk0_off;/* infoblk offset */
efx_word_t infoblk1_off;/* infoblk offset */
efx_byte_t infoblk_len;/* length of space reserved for one infoblk structure */
efx_byte_t reserved[7];/* (set to 0) */
} v1;
struct {
efx_dword_t len1; /* length of first image */
efx_dword_t len2; /* length of second image */
efx_dword_t off1; /* offset of first byte to edit to combine images */
efx_dword_t off2; /* offset of second byte to edit to combine images */
efx_word_t infoblk_off;/* infoblk start offset */
efx_word_t infoblk_count;/* infoblk count */
efx_byte_t infoblk_len;/* length of space reserved for one infoblk structure */
efx_byte_t reserved[7];/* (set to 0) */
} v2;
} data;
} siena_mc_combo_rom_hdr_t;
#pragma pack()
#endif /* _SYS_SIENA_FLASH_H */

View File

@ -0,0 +1,179 @@
/*
* Copyright (c) 2009-2016 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#ifndef _SYS_SIENA_IMPL_H
#define _SYS_SIENA_IMPL_H
#include "efx.h"
#include "efx_regs.h"
#include "efx_mcdi.h"
#include "siena_flash.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SIENA_NVRAM_CHUNK 0x80
extern __checkReturn efx_rc_t
siena_nic_probe(
__in efx_nic_t *enp);
extern __checkReturn efx_rc_t
siena_nic_reset(
__in efx_nic_t *enp);
extern __checkReturn efx_rc_t
siena_nic_init(
__in efx_nic_t *enp);
extern void
siena_nic_fini(
__in efx_nic_t *enp);
extern void
siena_nic_unprobe(
__in efx_nic_t *enp);
#define SIENA_SRAM_ROWS 0x12000
extern void
siena_sram_init(
__in efx_nic_t *enp);
#if EFSYS_OPT_MCDI
extern __checkReturn efx_rc_t
siena_mcdi_init(
__in efx_nic_t *enp,
__in const efx_mcdi_transport_t *mtp);
extern void
siena_mcdi_send_request(
__in efx_nic_t *enp,
__in_bcount(hdr_len) void *hdrp,
__in size_t hdr_len,
__in_bcount(sdu_len) void *sdup,
__in size_t sdu_len);
extern __checkReturn boolean_t
siena_mcdi_poll_response(
__in efx_nic_t *enp);
extern void
siena_mcdi_read_response(
__in efx_nic_t *enp,
__out_bcount(length) void *bufferp,
__in size_t offset,
__in size_t length);
extern efx_rc_t
siena_mcdi_poll_reboot(
__in efx_nic_t *enp);
extern void
siena_mcdi_fini(
__in efx_nic_t *enp);
extern __checkReturn efx_rc_t
siena_mcdi_feature_supported(
__in efx_nic_t *enp,
__in efx_mcdi_feature_id_t id,
__out boolean_t *supportedp);
extern void
siena_mcdi_get_timeout(
__in efx_nic_t *enp,
__in efx_mcdi_req_t *emrp,
__out uint32_t *timeoutp);
#endif /* EFSYS_OPT_MCDI */
typedef struct siena_link_state_s {
uint32_t sls_adv_cap_mask;
uint32_t sls_lp_cap_mask;
unsigned int sls_fcntl;
efx_link_mode_t sls_link_mode;
boolean_t sls_mac_up;
} siena_link_state_t;
extern void
siena_phy_link_ev(
__in efx_nic_t *enp,
__in efx_qword_t *eqp,
__out efx_link_mode_t *link_modep);
extern __checkReturn efx_rc_t
siena_phy_get_link(
__in efx_nic_t *enp,
__out siena_link_state_t *slsp);
extern __checkReturn efx_rc_t
siena_phy_power(
__in efx_nic_t *enp,
__in boolean_t on);
extern __checkReturn efx_rc_t
siena_phy_reconfigure(
__in efx_nic_t *enp);
extern __checkReturn efx_rc_t
siena_phy_verify(
__in efx_nic_t *enp);
extern __checkReturn efx_rc_t
siena_phy_oui_get(
__in efx_nic_t *enp,
__out uint32_t *ouip);
extern __checkReturn efx_rc_t
siena_mac_poll(
__in efx_nic_t *enp,
__out efx_link_mode_t *link_modep);
extern __checkReturn efx_rc_t
siena_mac_up(
__in efx_nic_t *enp,
__out boolean_t *mac_upp);
extern __checkReturn efx_rc_t
siena_mac_reconfigure(
__in efx_nic_t *enp);
extern __checkReturn efx_rc_t
siena_mac_pdu_get(
__in efx_nic_t *enp,
__out size_t *pdu);
#ifdef __cplusplus
}
#endif
#endif /* _SYS_SIENA_IMPL_H */

View File

@ -0,0 +1,205 @@
/*
* Copyright (c) 2009-2016 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_SIENA
__checkReturn efx_rc_t
siena_mac_poll(
__in efx_nic_t *enp,
__out efx_link_mode_t *link_modep)
{
efx_port_t *epp = &(enp->en_port);
siena_link_state_t sls;
efx_rc_t rc;
if ((rc = siena_phy_get_link(enp, &sls)) != 0)
goto fail1;
epp->ep_adv_cap_mask = sls.sls_adv_cap_mask;
epp->ep_fcntl = sls.sls_fcntl;
*link_modep = sls.sls_link_mode;
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
*link_modep = EFX_LINK_UNKNOWN;
return (rc);
}
__checkReturn efx_rc_t
siena_mac_up(
__in efx_nic_t *enp,
__out boolean_t *mac_upp)
{
siena_link_state_t sls;
efx_rc_t rc;
/*
* Because Siena doesn't *require* polling, we can't rely on
* siena_mac_poll() being executed to populate epp->ep_mac_up.
*/
if ((rc = siena_phy_get_link(enp, &sls)) != 0)
goto fail1;
*mac_upp = sls.sls_mac_up;
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
__checkReturn efx_rc_t
siena_mac_reconfigure(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
efx_oword_t multicast_hash[2];
efx_mcdi_req_t req;
uint8_t payload[MAX(MAX(MC_CMD_SET_MAC_IN_LEN,
MC_CMD_SET_MAC_OUT_LEN),
MAX(MC_CMD_SET_MCAST_HASH_IN_LEN,
MC_CMD_SET_MCAST_HASH_OUT_LEN))];
unsigned int fcntl;
efx_rc_t rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SET_MAC;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SET_MAC_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SET_MAC_OUT_LEN;
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_all_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 */
if (epp->ep_all_mulcst) {
/* A hash matching all multicast is all 1s */
EFX_SET_OWORD(multicast_hash[0]);
EFX_SET_OWORD(multicast_hash[1]);
} else if (epp->ep_mulcst) {
/* Use the hash set by the multicast list */
multicast_hash[0] = epp->ep_multicst_hash[0];
multicast_hash[1] = epp->ep_multicst_hash[1];
} else {
/* A hash matching no traffic is simply 0 */
EFX_ZERO_OWORD(multicast_hash[0]);
EFX_ZERO_OWORD(multicast_hash[1]);
}
/*
* Broadcast packets go through the multicast hash filter.
* The IEEE 802.3 CRC32 of the broadcast address is 0xbe2612ff
* so we always add bit 0xff to the mask (bit 0x7f in the
* second octword).
*/
if (epp->ep_brdcst) {
/*
* NOTE: due to constant folding, some of this evaluates
* to null expressions, giving E_EXPR_NULL_EFFECT during
* lint on Illumos. No good way to fix this without
* explicit coding the individual word/bit setting.
* So just suppress lint for this one line.
*/
/* LINTED */
EFX_SET_OWORD_BIT(multicast_hash[1], 0x7f);
}
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SET_MCAST_HASH;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SET_MCAST_HASH_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SET_MCAST_HASH_OUT_LEN;
memcpy(MCDI_IN2(req, uint8_t, SET_MCAST_HASH_IN_HASH0),
multicast_hash, sizeof (multicast_hash));
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
siena_mac_pdu_get(
__in efx_nic_t *enp,
__out size_t *pdu)
{
return (ENOTSUP);
}
#endif /* EFSYS_OPT_SIENA */

View File

@ -0,0 +1,263 @@
/*
* Copyright (c) 2012-2016 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_SIENA && EFSYS_OPT_MCDI
#define SIENA_MCDI_PDU(_emip) \
(((emip)->emi_port == 1) \
? MC_SMEM_P0_PDU_OFST >> 2 \
: MC_SMEM_P1_PDU_OFST >> 2)
#define SIENA_MCDI_DOORBELL(_emip) \
(((emip)->emi_port == 1) \
? MC_SMEM_P0_DOORBELL_OFST >> 2 \
: MC_SMEM_P1_DOORBELL_OFST >> 2)
#define SIENA_MCDI_STATUS(_emip) \
(((emip)->emi_port == 1) \
? MC_SMEM_P0_STATUS_OFST >> 2 \
: MC_SMEM_P1_STATUS_OFST >> 2)
void
siena_mcdi_send_request(
__in efx_nic_t *enp,
__in_bcount(hdr_len) void *hdrp,
__in size_t hdr_len,
__in_bcount(sdu_len) void *sdup,
__in size_t sdu_len)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
efx_dword_t dword;
unsigned int pdur;
unsigned int dbr;
unsigned int pos;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
pdur = SIENA_MCDI_PDU(emip);
dbr = SIENA_MCDI_DOORBELL(emip);
/* Write the header */
EFSYS_ASSERT3U(hdr_len, ==, sizeof (efx_dword_t));
dword = *(efx_dword_t *)hdrp;
EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_TRUE);
/* Write the payload */
for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) {
dword = *(efx_dword_t *)((uint8_t *)sdup + pos);
EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM,
pdur + 1 + (pos >> 2), &dword, B_FALSE);
}
/* Ring the doorbell */
EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11);
EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE);
}
efx_rc_t
siena_mcdi_poll_reboot(
__in efx_nic_t *enp)
{
#if 1
/*
* XXX Bug 25922, bug 26099: This function is not being used
* properly. Until its callers are fixed, it should always
* return 0.
*/
_NOTE(ARGUNUSED(enp))
return (0);
#else
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
unsigned int rebootr;
efx_dword_t dword;
uint32_t value;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
rebootr = SIENA_MCDI_STATUS(emip);
EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
value = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
if (value == 0)
return (0);
EFX_ZERO_DWORD(dword);
EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
if (value == MC_STATUS_DWORD_ASSERT)
return (EINTR);
else
return (EIO);
#endif
}
extern __checkReturn boolean_t
siena_mcdi_poll_response(
__in efx_nic_t *enp)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
efx_dword_t hdr;
unsigned int pdur;
EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
pdur = SIENA_MCDI_PDU(emip);
EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &hdr, B_FALSE);
return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
}
void
siena_mcdi_read_response(
__in efx_nic_t *enp,
__out_bcount(length) void *bufferp,
__in size_t offset,
__in size_t length)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
unsigned int pdur;
unsigned int pos;
efx_dword_t data;
EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
pdur = SIENA_MCDI_PDU(emip);
for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) {
EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
pdur + ((offset + pos) >> 2), &data, B_FALSE);
memcpy((uint8_t *)bufferp + pos, &data,
MIN(sizeof (data), length - pos));
}
}
__checkReturn efx_rc_t
siena_mcdi_init(
__in efx_nic_t *enp,
__in const efx_mcdi_transport_t *mtp)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
efx_oword_t oword;
unsigned int portnum;
efx_rc_t rc;
_NOTE(ARGUNUSED(mtp))
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
/* Determine the port number to use for MCDI */
EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword);
portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
if (portnum == 0) {
/* Presumably booted from ROM; only MCDI port 1 will work */
emip->emi_port = 1;
} else if (portnum <= 2) {
emip->emi_port = portnum;
} else {
rc = EINVAL;
goto fail1;
}
/* Siena BootROM and firmware only support MCDIv1 */
emip->emi_max_version = 1;
/*
* Wipe the atomic reboot status so subsequent MCDI requests succeed.
* BOOT_STATUS is preserved so eno_nic_probe() can boot out of the
* assertion handler.
*/
(void) siena_mcdi_poll_reboot(enp);
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
void
siena_mcdi_fini(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
}
__checkReturn efx_rc_t
siena_mcdi_feature_supported(
__in efx_nic_t *enp,
__in efx_mcdi_feature_id_t id,
__out boolean_t *supportedp)
{
efx_rc_t rc;
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
switch (id) {
case EFX_MCDI_FEATURE_FW_UPDATE:
case EFX_MCDI_FEATURE_LINK_CONTROL:
case EFX_MCDI_FEATURE_MACADDR_CHANGE:
case EFX_MCDI_FEATURE_MAC_SPOOFING:
*supportedp = B_TRUE;
break;
default:
rc = ENOTSUP;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
/* Default timeout for MCDI command processing. */
#define SIENA_MCDI_CMD_TIMEOUT_US (10 * 1000 * 1000)
void
siena_mcdi_get_timeout(
__in efx_nic_t *enp,
__in efx_mcdi_req_t *emrp,
__out uint32_t *timeoutp)
{
_NOTE(ARGUNUSED(enp, emrp))
*timeoutp = SIENA_MCDI_CMD_TIMEOUT_US;
}
#endif /* EFSYS_OPT_SIENA && EFSYS_OPT_MCDI */

View File

@ -0,0 +1,357 @@
/*
* Copyright (c) 2009-2016 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include "efx.h"
#include "efx_impl.h"
#include "mcdi_mon.h"
#if EFSYS_OPT_SIENA
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_txq_max_ndescs = 4096;
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;
encp->enc_rx_packed_stream_supported = B_FALSE;
encp->enc_rx_var_packed_stream_supported = B_FALSE;
/* 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);
}
static __checkReturn efx_rc_t
siena_phy_cfg(
__in efx_nic_t *enp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_rc_t rc;
/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
__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;
encp->enc_features = enp->en_features;
return (0);
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);
}
__checkReturn efx_rc_t
siena_nic_reset(
__in efx_nic_t *enp)
{
efx_mcdi_req_t req;
efx_rc_t rc;
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
/* siena_nic_reset() is called to recover from BADASSERT failures. */
if ((rc = efx_mcdi_read_assertion(enp)) != 0)
goto fail1;
if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
goto fail2;
/*
* Bug24908: ENTITY_RESET_IN_LEN is non zero but zero may be supplied
* for backwards compatibility with PORT_RESET_IN_LEN.
*/
EFX_STATIC_ASSERT(MC_CMD_ENTITY_RESET_OUT_LEN == 0);
req.emr_cmd = MC_CMD_ENTITY_RESET;
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_out_buf = NULL;
req.emr_out_length = 0;
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail3;
}
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (0);
}
static void
siena_nic_rx_cfg(
__in efx_nic_t *enp)
{
efx_oword_t oword;
/*
* RX_INGR_EN is always enabled on Siena, because we rely on
* the RX parser to be resiliant to missing SOP/EOP.
*/
EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword);
EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_INGR_EN, 1);
EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword);
/* Disable parsing of additional 802.1Q in Q packets */
EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
EFX_SET_OWORD_FIELD(oword, FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES, 0);
EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
}
static void
siena_nic_usrev_dis(
__in efx_nic_t *enp)
{
efx_oword_t oword;
EFX_POPULATE_OWORD_1(oword, FRF_CZ_USREV_DIS, 1);
EFX_BAR_WRITEO(enp, FR_CZ_USR_EV_CFG, &oword);
}
__checkReturn efx_rc_t
siena_nic_init(
__in efx_nic_t *enp)
{
efx_rc_t rc;
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
/* Enable reporting of some events (e.g. link change) */
if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
goto fail1;
siena_sram_init(enp);
/* Configure Siena's RX block */
siena_nic_rx_cfg(enp);
/* Disable USR_EVents for now */
siena_nic_usrev_dis(enp);
/* bug17057: Ensure set_link is called */
if ((rc = siena_phy_reconfigure(enp)) != 0)
goto fail2;
enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V1;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
void
siena_nic_fini(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
}
void
siena_nic_unprobe(
__in efx_nic_t *enp)
{
(void) efx_mcdi_drv_attach(enp, B_FALSE);
}
#endif /* EFSYS_OPT_SIENA */

View File

@ -0,0 +1,375 @@
/*
* Copyright (c) 2009-2016 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_SIENA
static void
siena_phy_decode_cap(
__in uint32_t mcdi_cap,
__out uint32_t *maskp)
{
uint32_t mask;
mask = 0;
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
mask |= (1 << EFX_PHY_CAP_10HDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
mask |= (1 << EFX_PHY_CAP_10FDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
mask |= (1 << EFX_PHY_CAP_100HDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
mask |= (1 << EFX_PHY_CAP_100FDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
mask |= (1 << EFX_PHY_CAP_1000HDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
mask |= (1 << EFX_PHY_CAP_1000FDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
mask |= (1 << EFX_PHY_CAP_10000FDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
mask |= (1 << EFX_PHY_CAP_PAUSE);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
mask |= (1 << EFX_PHY_CAP_ASYM);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
mask |= (1 << EFX_PHY_CAP_AN);
*maskp = mask;
}
static void
siena_phy_decode_link_mode(
__in efx_nic_t *enp,
__in uint32_t link_flags,
__in unsigned int speed,
__in unsigned int fcntl,
__out efx_link_mode_t *link_modep,
__out unsigned int *fcntlp)
{
boolean_t fd = !!(link_flags &
(1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
boolean_t up = !!(link_flags &
(1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
_NOTE(ARGUNUSED(enp))
if (!up)
*link_modep = EFX_LINK_DOWN;
else if (speed == 10000 && fd)
*link_modep = EFX_LINK_10000FDX;
else if (speed == 1000)
*link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
else if (speed == 100)
*link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
else if (speed == 10)
*link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
else
*link_modep = EFX_LINK_UNKNOWN;
if (fcntl == MC_CMD_FCNTL_OFF)
*fcntlp = 0;
else if (fcntl == MC_CMD_FCNTL_RESPOND)
*fcntlp = EFX_FCNTL_RESPOND;
else if (fcntl == MC_CMD_FCNTL_BIDIR)
*fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
else {
EFSYS_PROBE1(mc_pcol_error, int, fcntl);
*fcntlp = 0;
}
}
void
siena_phy_link_ev(
__in efx_nic_t *enp,
__in efx_qword_t *eqp,
__out efx_link_mode_t *link_modep)
{
efx_port_t *epp = &(enp->en_port);
unsigned int link_flags;
unsigned int speed;
unsigned int fcntl;
efx_link_mode_t link_mode;
uint32_t lp_cap_mask;
/*
* Convert the LINKCHANGE speed enumeration into mbit/s, in the
* same way as GET_LINK encodes the speed
*/
switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
case MCDI_EVENT_LINKCHANGE_SPEED_100M:
speed = 100;
break;
case MCDI_EVENT_LINKCHANGE_SPEED_1G:
speed = 1000;
break;
case MCDI_EVENT_LINKCHANGE_SPEED_10G:
speed = 10000;
break;
default:
speed = 0;
break;
}
link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
siena_phy_decode_link_mode(enp, link_flags, speed,
MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
&link_mode, &fcntl);
siena_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
&lp_cap_mask);
/*
* It's safe to update ep_lp_cap_mask without the driver's port lock
* because presumably any concurrently running efx_port_poll() is
* only going to arrive at the same value.
*
* ep_fcntl has two meanings. It's either the link common fcntl
* (if the PHY supports AN), or it's the forced link state. If
* the former, it's safe to update the value for the same reason as
* for ep_lp_cap_mask. If the latter, then just ignore the value,
* because we can race with efx_mac_fcntl_set().
*/
epp->ep_lp_cap_mask = lp_cap_mask;
if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
epp->ep_fcntl = fcntl;
*link_modep = link_mode;
}
__checkReturn efx_rc_t
siena_phy_power(
__in efx_nic_t *enp,
__in boolean_t power)
{
efx_rc_t rc;
if (!power)
return (0);
/* Check if the PHY is a zombie */
if ((rc = siena_phy_verify(enp)) != 0)
goto fail1;
enp->en_reset_flags |= EFX_RESET_PHY;
return (0);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
__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);
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);
}
__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);
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
speed = 0;
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
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;
MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
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
siena_phy_verify(
__in efx_nic_t *enp)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN,
MC_CMD_GET_PHY_STATE_OUT_LEN)];
uint32_t state;
efx_rc_t rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_GET_PHY_STATE;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_GET_PHY_STATE_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_PHY_STATE_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
if (state != MC_CMD_PHY_STATE_OK) {
if (state != MC_CMD_PHY_STATE_ZOMBIE)
EFSYS_PROBE1(mc_pcol_error, int, state);
rc = ENOTACTIVE;
goto fail3;
}
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
}
__checkReturn efx_rc_t
siena_phy_oui_get(
__in efx_nic_t *enp,
__out uint32_t *ouip)
{
_NOTE(ARGUNUSED(enp, ouip))
return (ENOTSUP);
}
#endif /* EFSYS_OPT_SIENA */

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2009-2016 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_SIENA
void
siena_sram_init(
__in efx_nic_t *enp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_oword_t oword;
uint32_t rx_base, tx_base;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
rx_base = encp->enc_buftbl_limit;
tx_base = rx_base + (encp->enc_rxq_limit *
EFX_RXQ_DC_NDESCS(EFX_RXQ_DC_SIZE));
/* Initialize the transmit descriptor cache */
EFX_POPULATE_OWORD_1(oword, FRF_AZ_SRM_TX_DC_BASE_ADR, tx_base);
EFX_BAR_WRITEO(enp, FR_AZ_SRM_TX_DC_CFG_REG, &oword);
EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_DC_SIZE, EFX_TXQ_DC_SIZE);
EFX_BAR_WRITEO(enp, FR_AZ_TX_DC_CFG_REG, &oword);
/* Initialize the receive descriptor cache */
EFX_POPULATE_OWORD_1(oword, FRF_AZ_SRM_RX_DC_BASE_ADR, rx_base);
EFX_BAR_WRITEO(enp, FR_AZ_SRM_RX_DC_CFG_REG, &oword);
EFX_POPULATE_OWORD_1(oword, FRF_AZ_RX_DC_SIZE, EFX_RXQ_DC_SIZE);
EFX_BAR_WRITEO(enp, FR_AZ_RX_DC_CFG_REG, &oword);
/* Set receive descriptor pre-fetch low water mark */
EFX_POPULATE_OWORD_1(oword, FRF_AZ_RX_DC_PF_LWM, 56);
EFX_BAR_WRITEO(enp, FR_AZ_RX_DC_PF_WM_REG, &oword);
/* Set the event queue to use for SRAM updates */
EFX_POPULATE_OWORD_1(oword, FRF_AZ_SRM_UPD_EVQ_ID, 0);
EFX_BAR_WRITEO(enp, FR_AZ_SRM_UPD_EVQ_REG, &oword);
}
#endif /* EFSYS_OPT_SIENA */