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:
parent
099c33bef3
commit
f7dc06bf35
@ -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
|
||||
|
@ -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
@ -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;
|
||||
};
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
215
drivers/net/sfc/base/siena_flash.h
Normal file
215
drivers/net/sfc/base/siena_flash.h
Normal 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 */
|
179
drivers/net/sfc/base/siena_impl.h
Normal file
179
drivers/net/sfc/base/siena_impl.h
Normal 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 */
|
205
drivers/net/sfc/base/siena_mac.c
Normal file
205
drivers/net/sfc/base/siena_mac.c
Normal 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 */
|
263
drivers/net/sfc/base/siena_mcdi.c
Normal file
263
drivers/net/sfc/base/siena_mcdi.c
Normal 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 */
|
357
drivers/net/sfc/base/siena_nic.c
Normal file
357
drivers/net/sfc/base/siena_nic.c
Normal 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 */
|
375
drivers/net/sfc/base/siena_phy.c
Normal file
375
drivers/net/sfc/base/siena_phy.c
Normal 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 */
|
74
drivers/net/sfc/base/siena_sram.c
Normal file
74
drivers/net/sfc/base/siena_sram.c
Normal 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 */
|
Loading…
Reference in New Issue
Block a user