sfxge_gld_v3.c revision 49ef7e0638c8b771d8a136eae78b1c0f99acc8e0
/*
* Copyright (c) 2008-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 <sys/types.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/stream.h>
#include <sys/strsun.h>
#include <sys/strsubr.h>
#include <sys/dlpi.h>
#include <sys/ksynch.h>
#include <sys/cpuvar.h>
#include <sys/cpu.h>
#include <sys/vlan.h>
#include <inet/tcp.h>
#include "sfxge.h"
void
sfxge_gld_link_update(sfxge_t *sp)
{
sfxge_mac_t *smp = &(sp->s_mac);
link_state_t link;
switch (smp->sm_link_mode) {
case EFX_LINK_UNKNOWN:
link = LINK_STATE_UNKNOWN;
break;
case EFX_LINK_DOWN:
link = LINK_STATE_DOWN;
break;
default:
link = LINK_STATE_UP;
}
mac_link_update(sp->s_mh, link);
}
void
sfxge_gld_mtu_update(sfxge_t *sp)
{
#ifdef _USE_MTU_UPDATE
(void) mac_maxsdu_update(sp->s_mh, sp->s_mtu);
#else
_NOTE(ARGUNUSED(sp));
#endif
}
void
sfxge_gld_rx_post(sfxge_t *sp, unsigned int index, mblk_t *mp)
{
_NOTE(ARGUNUSED(index))
mac_rx(sp->s_mh, NULL, mp);
}
void
sfxge_gld_rx_push(sfxge_t *sp)
{
_NOTE(ARGUNUSED(sp))
}
static uint64_t
sfxge_phy_dfl_cap_test64(sfxge_t *sp, uint32_t field)
{
return (sfxge_phy_cap_test(sp, EFX_PHY_CAP_DEFAULT, field, NULL) ?
1ull : 0ull);
}
static uint64_t
sfxge_phy_cur_cap_test64(sfxge_t *sp, uint32_t field)
{
return (sfxge_phy_cap_test(sp, EFX_PHY_CAP_CURRENT, field, NULL) ?
1ull : 0ull);
}
static uint64_t
sfxge_phy_lp_cap_test64(sfxge_t *sp, uint32_t field)
{
return (sfxge_phy_lp_cap_test(sp, field) ? 1ull : 0ull);
}
static int
sfxge_gld_getstat(void *arg, unsigned int id, uint64_t *valp)
{
sfxge_t *sp = arg;
efx_nic_t *enp = sp->s_enp;
int rc;
if (sp->s_mac.sm_state != SFXGE_MAC_STARTED) {
rc = ENODEV;
goto fail1;
}
switch (id) {
case MAC_STAT_IFSPEED: {
unsigned int speed;
sfxge_mac_link_speed_get(sp, &speed);
*valp = (uint64_t)speed * 1000000ull;
break;
}
case ETHER_STAT_LINK_DUPLEX: {
sfxge_link_duplex_t duplex;
sfxge_mac_link_duplex_get(sp, &duplex);
switch (duplex) {
case SFXGE_LINK_DUPLEX_UNKNOWN:
*valp = LINK_DUPLEX_UNKNOWN;
break;
case SFXGE_LINK_DUPLEX_HALF:
*valp = LINK_DUPLEX_HALF;
break;
case SFXGE_LINK_DUPLEX_FULL:
*valp = LINK_DUPLEX_FULL;
break;
default:
ASSERT(B_FALSE);
break;
}
break;
}
case ETHER_STAT_CAP_40GFDX:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_40000FDX);
break;
case ETHER_STAT_CAP_10GFDX:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_10000FDX);
break;
case ETHER_STAT_CAP_1000FDX:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_1000FDX);
break;
case ETHER_STAT_CAP_1000HDX:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_1000HDX);
break;
case ETHER_STAT_CAP_100FDX:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_100FDX);
break;
case ETHER_STAT_CAP_100HDX:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_100HDX);
break;
case ETHER_STAT_CAP_10FDX:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_10FDX);
break;
case ETHER_STAT_CAP_10HDX:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_10HDX);
break;
case ETHER_STAT_CAP_ASMPAUSE:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_ASYM);
break;
case ETHER_STAT_CAP_PAUSE:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_PAUSE);
break;
case ETHER_STAT_CAP_AUTONEG:
*valp = sfxge_phy_dfl_cap_test64(sp, EFX_PHY_CAP_AN);
break;
case ETHER_STAT_ADV_CAP_40GFDX:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_40000FDX);
break;
case ETHER_STAT_ADV_CAP_10GFDX:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_10000FDX);
break;
case ETHER_STAT_ADV_CAP_1000FDX:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_1000FDX);
break;
case ETHER_STAT_ADV_CAP_1000HDX:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_1000HDX);
break;
case ETHER_STAT_ADV_CAP_100FDX:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_100FDX);
break;
case ETHER_STAT_ADV_CAP_100HDX:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_100HDX);
break;
case ETHER_STAT_ADV_CAP_10FDX:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_10FDX);
break;
case ETHER_STAT_ADV_CAP_10HDX:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_10HDX);
break;
case ETHER_STAT_ADV_CAP_ASMPAUSE:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_ASYM);
break;
case ETHER_STAT_ADV_CAP_PAUSE:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_PAUSE);
break;
case ETHER_STAT_ADV_CAP_AUTONEG:
*valp = sfxge_phy_cur_cap_test64(sp, EFX_PHY_CAP_AN);
break;
case ETHER_STAT_LP_CAP_40GFDX:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_40000FDX);
break;
case ETHER_STAT_LP_CAP_10GFDX:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_10000FDX);
break;
case ETHER_STAT_LP_CAP_1000FDX:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_1000FDX);
break;
case ETHER_STAT_LP_CAP_1000HDX:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_1000HDX);
break;
case ETHER_STAT_LP_CAP_100FDX:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_100FDX);
break;
case ETHER_STAT_LP_CAP_100HDX:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_100HDX);
break;
case ETHER_STAT_LP_CAP_10FDX:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_10FDX);
break;
case ETHER_STAT_LP_CAP_10HDX:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_10HDX);
break;
case ETHER_STAT_LP_CAP_ASMPAUSE:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_ASYM);
break;
case ETHER_STAT_LP_CAP_PAUSE:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_PAUSE);
break;
case ETHER_STAT_LP_CAP_AUTONEG:
*valp = sfxge_phy_lp_cap_test64(sp, EFX_PHY_CAP_AN);
break;
case ETHER_STAT_XCVR_ADDR: {
const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
*valp = encp->enc_port;
break;
}
case ETHER_STAT_XCVR_ID: {
uint32_t oui;
if ((rc = efx_phy_oui_get(sp->s_enp, &oui)) != 0)
goto fail2;
*valp = oui;
break;
}
case MAC_STAT_MULTIRCV:
sfxge_mac_stat_get(sp, EFX_MAC_RX_MULTICST_PKTS, valp);
break;
case MAC_STAT_BRDCSTRCV:
sfxge_mac_stat_get(sp, EFX_MAC_RX_BRDCST_PKTS, valp);
break;
case MAC_STAT_MULTIXMT:
sfxge_mac_stat_get(sp, EFX_MAC_TX_MULTICST_PKTS, valp);
break;
case MAC_STAT_BRDCSTXMT:
sfxge_mac_stat_get(sp, EFX_MAC_TX_BRDCST_PKTS, valp);
break;
case MAC_STAT_IERRORS:
sfxge_mac_stat_get(sp, EFX_MAC_RX_ERRORS, valp);
break;
case MAC_STAT_OERRORS:
sfxge_mac_stat_get(sp, EFX_MAC_TX_ERRORS, valp);
break;
case MAC_STAT_RBYTES:
sfxge_mac_stat_get(sp, EFX_MAC_RX_OCTETS, valp);
break;
case MAC_STAT_IPACKETS:
sfxge_mac_stat_get(sp, EFX_MAC_RX_PKTS, valp);
break;
case MAC_STAT_OBYTES:
sfxge_mac_stat_get(sp, EFX_MAC_TX_OCTETS, valp);
break;
case MAC_STAT_OPACKETS:
sfxge_mac_stat_get(sp, EFX_MAC_TX_PKTS, valp);
break;
case MAC_STAT_NORCVBUF:
sfxge_mac_stat_get(sp, EFX_MAC_RX_DROP_EVENTS, valp);
break;
case ETHER_STAT_FCS_ERRORS:
sfxge_mac_stat_get(sp, EFX_MAC_RX_FCS_ERRORS, valp);
break;
default:
rc = ENOTSUP;
goto fail3;
}
return (0);
fail3:
DTRACE_PROBE(fail3);
fail2:
DTRACE_PROBE(fail2);
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (rc);
}
static int
sfxge_gld_start(void *arg)
{
sfxge_t *sp = arg;
int rc;
if ((rc = sfxge_start(sp, B_FALSE)) != 0)
goto fail1;
return (0);
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (rc);
}
static void
sfxge_gld_stop(void *arg)
{
sfxge_t *sp = arg;
sfxge_stop(sp);
}
static int
sfxge_gld_setpromisc(void *arg, boolean_t on)
{
sfxge_t *sp = arg;
return sfxge_mac_promisc_set(sp,
(on) ? SFXGE_PROMISC_ALL_PHYS : SFXGE_PROMISC_OFF);
}
static int
sfxge_gld_multicst(void *arg, boolean_t add, const uint8_t *addr)
{
sfxge_t *sp = arg;
int rc;
if (add) {
if ((rc = sfxge_mac_multicst_add(sp, addr)) != 0)
goto fail1;
} else {
if ((rc = sfxge_mac_multicst_remove(sp, addr)) != 0)
goto fail2;
}
return (0);
fail2:
DTRACE_PROBE(fail2);
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (rc);
}
static int
sfxge_gld_unicst(void *arg, const uint8_t *addr)
{
sfxge_t *sp = arg;
int rc;
if ((rc = sfxge_mac_unicst_set(sp, (uint8_t *)addr)) != 0)
goto fail1;
return (0);
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (rc);
}
static void
sfxge_gld_ioctl(void *arg, queue_t *wq, mblk_t *mp)
{
sfxge_t *sp = arg;
sfxge_ioctl(sp, wq, mp);
}
static mblk_t *
sfxge_gld_tx(void *arg, mblk_t *mp)
{
sfxge_t *sp = arg;
mblk_t *next;
/* Walk the packet chain */
do {
/* Break the packet out of the chain */
next = mp->b_next;
mp->b_next = NULL;
if (next != NULL)
prefetch_read_many(next);
/* Post the packet in the appropriate transmit queue */
if (sfxge_tx_packet_add(sp, mp) == ENOSPC) {
mp->b_next = next;
return (mp);
}
mp = next;
} while (mp != NULL);
return (NULL);
}
/*
* This must not be static, in order to be tunable by /etc/system.
* (Static declarations may be optmized away by the compiler.)
*/
boolean_t sfxge_lso = B_TRUE;
static boolean_t
sfxge_gld_getcapab(void *arg, mac_capab_t cap, void *cap_arg)
{
int rc;
_NOTE(ARGUNUSED(arg))
switch (cap) {
case MAC_CAPAB_LSO: {
mac_capab_lso_t *lsop = cap_arg;
/* Check whether LSO is disabled */
if (!sfxge_lso) {
rc = ENOTSUP;
goto fail1;
}
DTRACE_PROBE(lso);
lsop->lso_flags = LSO_TX_BASIC_TCP_IPV4;
lsop->lso_basic_tcp_ipv4.lso_max = TCP_MAX_LSO_LENGTH;
break;
}
case MAC_CAPAB_HCKSUM: {
uint32_t *hcksump = cap_arg;
DTRACE_PROBE(cksum);
*hcksump = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM;
break;
}
default:
rc = ENOTSUP;
goto fail1;
}
return (B_TRUE);
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (B_FALSE);
}
/*
* GLDv3 driver-private property names must be preceded by an underscore - see
* mc_getprop(9E).
*/
#define SFXGE_PRIV_PROP_NAME(s) ("_" #s)
#define SFXGE_XSTR(s) SFXGE_STR(s)
#define SFXGE_STR(s) #s
static void
sfxge_gld_priv_prop_info(sfxge_t *sp, const char *name,
mac_prop_info_handle_t handle)
{
if (strcmp(name, SFXGE_PRIV_PROP_NAME(rx_coalesce_mode)) == 0) {
mac_prop_info_set_default_uint32(handle,
SFXGE_RX_COALESCE_OFF);
mac_prop_info_set_perm(handle, MAC_PROP_PERM_RW);
return;
}
if (strcmp(name, SFXGE_PRIV_PROP_NAME(rx_scale_count)) == 0) {
mac_prop_info_set_default_uint32(handle, ncpus);
mac_prop_info_set_range_uint32(handle, 1,
(uint32_t)sp->s_intr.si_nalloc);
mac_prop_info_set_perm(handle, MAC_PROP_PERM_RW);
return;
}
if (strcmp(name, SFXGE_PRIV_PROP_NAME(intr_moderation)) == 0) {
mac_prop_info_set_default_uint32(handle,
SFXGE_DEFAULT_MODERATION);
mac_prop_info_set_range_uint32(handle,
0, efx_nic_cfg_get(sp->s_enp)->enc_evq_timer_max_us);
mac_prop_info_set_perm(handle, MAC_PROP_PERM_RW);
return;
}
if (strcmp(name, SFXGE_PRIV_PROP_NAME(mon_polling)) == 0) {
mac_prop_info_set_default_uint8(handle, 0);
mac_prop_info_set_perm(handle, MAC_PROP_PERM_RW);
return;
}
#if EFSYS_OPT_MCDI_LOGGING
if (strcmp(name, SFXGE_PRIV_PROP_NAME(mcdi_logging)) == 0) {
mac_prop_info_set_default_uint8(handle, 0);
mac_prop_info_set_perm(handle, MAC_PROP_PERM_RW);
return;
}
#endif
DTRACE_PROBE(unknown_priv_prop);
}
static int
sfxge_gld_priv_prop_get(sfxge_t *sp, const char *name,
unsigned int size, void *valp)
{
long val;
int rc;
if (strcmp(name, SFXGE_PRIV_PROP_NAME(rx_coalesce_mode)) == 0) {
sfxge_rx_coalesce_mode_t mode;
sfxge_rx_coalesce_mode_get(sp, &mode);
val = (long)mode;
goto done;
}
if (strcmp(name, SFXGE_PRIV_PROP_NAME(rx_scale_count)) == 0) {
unsigned int count;
if (sfxge_rx_scale_count_get(sp, &count) != 0)
count = 0;
val = (long)count;
goto done;
}
if (strcmp(name, SFXGE_PRIV_PROP_NAME(intr_moderation)) == 0) {
unsigned int us;
sfxge_ev_moderation_get(sp, &us);
val = (long)us;
goto done;
}
if (strcmp(name, SFXGE_PRIV_PROP_NAME(mon_polling)) == 0) {
val = (long)sp->s_mon.sm_polling;
goto done;
}
#if EFSYS_OPT_MCDI_LOGGING
if (strcmp(name, SFXGE_PRIV_PROP_NAME(mcdi_logging)) == 0) {
val = (long)sp->s_mcdi_logging;
goto done;
}
#endif
rc = ENOTSUP;
goto fail1;
done:
(void) snprintf(valp, size, "%ld", val);
return (0);
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (rc);
}
static int
sfxge_gld_priv_prop_set(sfxge_t *sp, const char *name, unsigned int size,
const void *valp)
{
long val;
int rc = 0;
_NOTE(ARGUNUSED(size))
(void) ddi_strtol(valp, (char **)NULL, 0, &val);
if (strcmp(name, SFXGE_PRIV_PROP_NAME(rx_coalesce_mode)) == 0) {
if ((rc = sfxge_rx_coalesce_mode_set(sp,
(sfxge_rx_coalesce_mode_t)val)) != 0)
goto fail1;
goto done;
}
if (strcmp(name, SFXGE_PRIV_PROP_NAME(rx_scale_count)) == 0) {
if ((rc = sfxge_rx_scale_count_set(sp, (unsigned int)val)) != 0)
goto fail1;
goto done;
}
if (strcmp(name, SFXGE_PRIV_PROP_NAME(intr_moderation)) == 0) {
if ((rc = sfxge_ev_moderation_set(sp, (unsigned int) val)) != 0)
goto fail1;
goto done;
}
if (strcmp(name, SFXGE_PRIV_PROP_NAME(mon_polling)) == 0) {
sp->s_mon.sm_polling = (int)val;
goto done;
}
#if EFSYS_OPT_MCDI_LOGGING
if (strcmp(name, SFXGE_PRIV_PROP_NAME(mcdi_logging)) == 0) {
sp->s_mcdi_logging = (int)val;
goto done;
}
#endif
rc = ENOTSUP;
goto fail1;
done:
return (0);
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (rc);
}
#if EFSYS_OPT_MCDI_LOGGING
#define SFXGE_N_NAMED_PROPS 4
#else
#define SFXGE_N_NAMED_PROPS 3
#endif
static void
sfxge_gld_priv_prop_init(sfxge_t *sp)
{
sfxge_mac_priv_prop_t *mac_priv_props;
unsigned int nprops = 0;
/*
* We have named_props (3 or 4) named properties and the structure must
* be finished by a NULL pointer.
*/
sp->s_mac_priv_props_alloc = SFXGE_N_NAMED_PROPS + 1;
sp->s_mac_priv_props = kmem_zalloc(sizeof (sfxge_mac_priv_prop_t) *
sp->s_mac_priv_props_alloc,
KM_SLEEP);
/*
* Driver-private property names start with an underscore - see
* mc_getprop(9E).
*/
mac_priv_props = sp->s_mac_priv_props;
*mac_priv_props = kmem_zalloc(MAXLINKPROPNAME, KM_SLEEP);
(void) snprintf(*mac_priv_props, MAXLINKPROPNAME - 1,
SFXGE_PRIV_PROP_NAME(rx_coalesce_mode));
mac_priv_props++;
nprops++;
*mac_priv_props = kmem_zalloc(MAXLINKPROPNAME, KM_SLEEP);
(void) snprintf(*mac_priv_props, MAXLINKPROPNAME - 1,
SFXGE_PRIV_PROP_NAME(rx_scale_count));
mac_priv_props++;
nprops++;
*mac_priv_props = kmem_zalloc(MAXLINKPROPNAME, KM_SLEEP);
(void) snprintf(*mac_priv_props, MAXLINKPROPNAME - 1,
SFXGE_PRIV_PROP_NAME(intr_moderation));
mac_priv_props++;
nprops++;
#if EFSYS_OPT_MCDI_LOGGING
*mac_priv_props = kmem_zalloc(MAXLINKPROPNAME, KM_SLEEP);
(void) snprintf(*mac_priv_props, MAXLINKPROPNAME - 1,
SFXGE_PRIV_PROP_NAME(mcdi_logging));
mac_priv_props++;
nprops++;
#endif
ASSERT3U((nprops + 1), ==, sp->s_mac_priv_props_alloc);
/* Terminated by a NULL pointer */
*mac_priv_props = NULL;
}
static void
sfxge_gld_priv_prop_fini(sfxge_t *sp)
{
char **mac_priv_props;
unsigned int id;
mac_priv_props = sp->s_mac_priv_props;
for (id = 0; id < SFXGE_N_NAMED_PROPS; id++) {
kmem_free(*mac_priv_props, MAXLINKPROPNAME);
mac_priv_props++;
}
kmem_free(sp->s_mac_priv_props, sizeof (sfxge_mac_priv_prop_t) *
sp->s_mac_priv_props_alloc);
sp->s_mac_priv_props = NULL;
}
static int
sfxge_gld_getprop(void *arg, const char *name, mac_prop_id_t id,
unsigned int size, void *valp)
{
sfxge_t *sp = arg;
uint32_t flag = EFX_PHY_CAP_CURRENT;
uint8_t *v8 = ((uint8_t *)valp);
int rc;
/* check size */
switch (id) {
case MAC_PROP_DUPLEX:
if (size < sizeof (link_duplex_t)) {
rc = EINVAL;
goto fail1;
}
break;
case MAC_PROP_FLOWCTRL:
if (size < sizeof (link_flowctrl_t)) {
rc = EINVAL;
goto fail1;
}
break;
case MAC_PROP_SPEED:
case MAC_PROP_STATUS:
if (size < sizeof (uint64_t)) {
rc = EINVAL;
goto fail1;
}
break;
case MAC_PROP_MTU:
if (size < sizeof (uint32_t)) {
rc = EINVAL;
goto fail1;
}
break;
case MAC_PROP_EN_AUTONEG:
case MAC_PROP_AUTONEG:
case MAC_PROP_EN_40GFDX_CAP:
case MAC_PROP_ADV_40GFDX_CAP:
case MAC_PROP_EN_10GFDX_CAP:
case MAC_PROP_ADV_10GFDX_CAP:
case MAC_PROP_EN_1000FDX_CAP:
case MAC_PROP_ADV_1000FDX_CAP:
case MAC_PROP_EN_1000HDX_CAP:
case MAC_PROP_ADV_1000HDX_CAP:
case MAC_PROP_EN_100FDX_CAP:
case MAC_PROP_ADV_100FDX_CAP:
case MAC_PROP_EN_100HDX_CAP:
case MAC_PROP_ADV_100HDX_CAP:
case MAC_PROP_EN_10FDX_CAP:
case MAC_PROP_ADV_10FDX_CAP:
case MAC_PROP_EN_10HDX_CAP:
case MAC_PROP_ADV_10HDX_CAP:
if (size < sizeof (uint8_t)) {
rc = EINVAL;
goto fail1;
}
break;
case MAC_PROP_PRIVATE:
/* sfxge_gld_priv_prop_get should do any size checking */
break;
default:
rc = ENOTSUP;
goto fail1;
}
switch (id) {
case MAC_PROP_DUPLEX: {
sfxge_link_duplex_t duplex;
sfxge_mac_link_duplex_get(sp, &duplex);
switch (duplex) {
case SFXGE_LINK_DUPLEX_UNKNOWN:
*((link_duplex_t *)valp) = LINK_DUPLEX_UNKNOWN;
break;
case SFXGE_LINK_DUPLEX_HALF:
*((link_duplex_t *)valp) = LINK_DUPLEX_HALF;
break;
case SFXGE_LINK_DUPLEX_FULL:
*((link_duplex_t *)valp) = LINK_DUPLEX_FULL;
break;
default:
ASSERT(B_FALSE);
break;
}
break;
}
case MAC_PROP_SPEED: {
unsigned int speed;
sfxge_mac_link_speed_get(sp, &speed);
*((uint64_t *)valp) = (uint64_t)speed * 1000000ull;
break;
}
case MAC_PROP_STATUS: {
boolean_t up;
sfxge_mac_link_check(sp, &up);
*((link_state_t *)valp) = (up) ?
LINK_STATE_UP : LINK_STATE_DOWN;
break;
}
case MAC_PROP_EN_AUTONEG:
case MAC_PROP_AUTONEG:
*v8 = sfxge_phy_cap_test(sp, flag, EFX_PHY_CAP_AN, NULL);
break;
case MAC_PROP_EN_40GFDX_CAP:
case MAC_PROP_ADV_40GFDX_CAP:
*v8 = sfxge_phy_cap_test(sp, flag, EFX_PHY_CAP_40000FDX, NULL);
break;
case MAC_PROP_EN_10GFDX_CAP:
case MAC_PROP_ADV_10GFDX_CAP:
*v8 = sfxge_phy_cap_test(sp, flag, EFX_PHY_CAP_10000FDX, NULL);
break;
case MAC_PROP_EN_1000FDX_CAP:
case MAC_PROP_ADV_1000FDX_CAP:
*v8 = sfxge_phy_cap_test(sp, flag, EFX_PHY_CAP_1000FDX, NULL);
break;
case MAC_PROP_EN_1000HDX_CAP:
case MAC_PROP_ADV_1000HDX_CAP:
*v8 = sfxge_phy_cap_test(sp, flag, EFX_PHY_CAP_1000HDX, NULL);
break;
case MAC_PROP_EN_100FDX_CAP:
case MAC_PROP_ADV_100FDX_CAP:
*v8 = sfxge_phy_cap_test(sp, flag, EFX_PHY_CAP_100FDX, NULL);
break;
case MAC_PROP_EN_100HDX_CAP:
case MAC_PROP_ADV_100HDX_CAP:
*v8 = sfxge_phy_cap_test(sp, flag, EFX_PHY_CAP_100HDX, NULL);
break;
case MAC_PROP_EN_10FDX_CAP:
case MAC_PROP_ADV_10FDX_CAP:
*v8 = sfxge_phy_cap_test(sp, flag, EFX_PHY_CAP_10FDX, NULL);
break;
case MAC_PROP_EN_10HDX_CAP:
case MAC_PROP_ADV_10HDX_CAP:
*v8 = sfxge_phy_cap_test(sp, flag, EFX_PHY_CAP_10HDX, NULL);
break;
case MAC_PROP_MTU:
*((uint32_t *)valp) = (uint32_t)(sp->s_mtu);
break;
case MAC_PROP_FLOWCTRL: {
unsigned int fcntl;
sfxge_mac_fcntl_get(sp, &fcntl);
switch (fcntl) {
case 0:
*((link_flowctrl_t *)valp) = LINK_FLOWCTRL_NONE;
break;
case EFX_FCNTL_GENERATE:
*((link_flowctrl_t *)valp) = LINK_FLOWCTRL_RX;
break;
case EFX_FCNTL_RESPOND:
*((link_flowctrl_t *)valp) = LINK_FLOWCTRL_TX;
break;
case (EFX_FCNTL_GENERATE | EFX_FCNTL_RESPOND):
*((link_flowctrl_t *)valp) = LINK_FLOWCTRL_BI;
break;
default:
ASSERT(B_FALSE);
break;
}
break;
}
case MAC_PROP_PRIVATE:
if ((rc = sfxge_gld_priv_prop_get(sp, name, size, valp)) != 0)
goto fail2;
break;
default:
rc = ENOTSUP;
goto fail3;
}
return (0);
fail3:
DTRACE_PROBE(fail3);
fail2:
DTRACE_PROBE(fail2);
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (rc);
}
static int
sfxge_gld_setprop(void *arg, const char *name, mac_prop_id_t id,
unsigned int size, const void *valp)
{
sfxge_t *sp = arg;
int v8 = *(uint8_t *)valp;
int rc;
/* get size checks out fo the way */
switch (id) {
/*
* On Sol11 (no updates) dladm seems to be using MAC_PROP_AUTONEG to set
* the autoneg parameter. This does not match the scheme suggested in
* mac(9E) but as they both map to the same think in the driver and in
* dladm it doesn't matter.
*/
case MAC_PROP_AUTONEG:
case MAC_PROP_EN_AUTONEG:
case MAC_PROP_EN_40GFDX_CAP:
case MAC_PROP_EN_10GFDX_CAP:
case MAC_PROP_EN_1000FDX_CAP:
case MAC_PROP_EN_1000HDX_CAP:
case MAC_PROP_EN_100FDX_CAP:
case MAC_PROP_EN_100HDX_CAP:
case MAC_PROP_EN_10FDX_CAP:
case MAC_PROP_EN_10HDX_CAP:
if (size < sizeof (uint8_t)) {
rc = EINVAL;
goto fail1;
}
break;
case MAC_PROP_MTU:
if (size < sizeof (uint32_t)) {
rc = EINVAL;
goto fail1;
}
break;
case MAC_PROP_FLOWCTRL:
if (size < sizeof (link_flowctrl_t)) {
rc = EINVAL;
goto fail1;
}
break;
case MAC_PROP_PRIVATE:
/* sfxge_gld_priv_prop_set should do any size checking */
break;
default:
rc = ENOTSUP;
goto fail1;
}
switch (id) {
/*
* It is unclear which of MAC_PROP_AUTONEG and MAC_PROP_EN_AUTONEG is
* used. Try both.
*/
case MAC_PROP_AUTONEG:
case MAC_PROP_EN_AUTONEG:
if ((rc = sfxge_phy_cap_set(sp, EFX_PHY_CAP_AN, v8)) != 0)
goto fail2;
break;
case MAC_PROP_EN_40GFDX_CAP:
if ((rc = sfxge_phy_cap_set(sp, EFX_PHY_CAP_40000FDX, v8)) != 0)
goto fail2;
break;
case MAC_PROP_EN_10GFDX_CAP: {
if ((rc = sfxge_phy_cap_set(sp, EFX_PHY_CAP_10000FDX, v8)) != 0)
goto fail2;
break;
}
case MAC_PROP_EN_1000FDX_CAP: {
if ((rc = sfxge_phy_cap_set(sp, EFX_PHY_CAP_1000FDX, v8)) != 0)
goto fail2;
break;
}
case MAC_PROP_EN_1000HDX_CAP: {
if ((rc = sfxge_phy_cap_set(sp, EFX_PHY_CAP_1000HDX, v8)) != 0)
goto fail2;
break;
}
case MAC_PROP_EN_100FDX_CAP: {
if ((rc = sfxge_phy_cap_set(sp, EFX_PHY_CAP_100FDX, v8)) != 0)
goto fail2;
break;
}
case MAC_PROP_EN_100HDX_CAP: {
if ((rc = sfxge_phy_cap_set(sp, EFX_PHY_CAP_100HDX, v8)) != 0)
goto fail2;
break;
}
case MAC_PROP_EN_10FDX_CAP: {
if ((rc = sfxge_phy_cap_set(sp, EFX_PHY_CAP_10FDX, v8)) != 0)
goto fail2;
break;
}
case MAC_PROP_EN_10HDX_CAP: {
if ((rc = sfxge_phy_cap_set(sp, EFX_PHY_CAP_10HDX, v8)) != 0)
goto fail2;
break;
}
case MAC_PROP_MTU: {
size_t mtu = (size_t)(*((uint32_t *)valp));
if (mtu > EFX_MAC_SDU_MAX) {
rc = EINVAL;
goto fail2;
}
sp->s_mtu = mtu;
DTRACE_PROBE(restart_mtu);
(void) sfxge_restart_dispatch(sp, DDI_SLEEP, SFXGE_HW_OK,
"MTU changing", (uint32_t)mtu);
break;
}
case MAC_PROP_FLOWCTRL: {
unsigned int fcntl = 0;
switch (*((link_flowctrl_t *)valp)) {
case LINK_FLOWCTRL_NONE:
fcntl = 0;
break;
case LINK_FLOWCTRL_RX:
fcntl = EFX_FCNTL_GENERATE;
break;
case LINK_FLOWCTRL_TX:
fcntl = EFX_FCNTL_RESPOND;
break;
case LINK_FLOWCTRL_BI:
fcntl = EFX_FCNTL_GENERATE | EFX_FCNTL_RESPOND;
break;
default:
rc = EINVAL;
goto fail2;
}
if ((rc = sfxge_mac_fcntl_set(sp, fcntl)) != 0)
goto fail3;
break;
}
case MAC_PROP_PRIVATE:
if ((rc = sfxge_gld_priv_prop_set(sp, name, size, valp)) != 0)
goto fail4;
break;
default:
rc = ENOTSUP;
goto fail5;
}
return (0);
fail5:
DTRACE_PROBE(fail5);
fail4:
DTRACE_PROBE(fail4);
fail3:
DTRACE_PROBE(fail3);
fail2:
DTRACE_PROBE(fail2);
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (rc);
}
static void
sfxge_gld_propinfo(void *arg, const char *name, mac_prop_id_t id,
mac_prop_info_handle_t handle)
{
sfxge_t *sp = arg;
efx_phy_cap_type_t phy_cap = EFX_PHY_CAP_INVALID;
switch (id) {
case MAC_PROP_DUPLEX:
mac_prop_info_set_perm(handle, MAC_PROP_PERM_READ);
return;
case MAC_PROP_FLOWCTRL:
mac_prop_info_set_perm(handle, MAC_PROP_PERM_RW);
mac_prop_info_set_default_link_flowctrl(handle,
LINK_FLOWCTRL_BI);
return;
case MAC_PROP_SPEED:
mac_prop_info_set_perm(handle, MAC_PROP_PERM_READ);
return;
case MAC_PROP_STATUS:
mac_prop_info_set_perm(handle, MAC_PROP_PERM_READ);
return;
case MAC_PROP_MTU: {
uint32_t mtu_default;
mac_prop_info_set_perm(handle, MAC_PROP_PERM_RW);
mtu_default = ddi_prop_get_int(DDI_DEV_T_ANY,
sp->s_dip, DDI_PROP_DONTPASS, "mtu", ETHERMTU);
mac_prop_info_set_default_uint32(handle, mtu_default);
return;
}
case MAC_PROP_PRIVATE:
sfxge_gld_priv_prop_info(sp, name, handle);
return;
case MAC_PROP_EN_AUTONEG:
case MAC_PROP_AUTONEG:
phy_cap = EFX_PHY_CAP_AN;
break;
case MAC_PROP_EN_10GFDX_CAP:
case MAC_PROP_ADV_10GFDX_CAP:
phy_cap = EFX_PHY_CAP_10000FDX;
break;
case MAC_PROP_EN_1000FDX_CAP:
case MAC_PROP_ADV_1000FDX_CAP:
phy_cap = EFX_PHY_CAP_1000FDX;
break;
case MAC_PROP_EN_1000HDX_CAP:
case MAC_PROP_ADV_1000HDX_CAP:
phy_cap = EFX_PHY_CAP_1000HDX;
break;
case MAC_PROP_EN_100FDX_CAP:
case MAC_PROP_ADV_100FDX_CAP:
phy_cap = EFX_PHY_CAP_100FDX;
break;
case MAC_PROP_EN_100HDX_CAP:
case MAC_PROP_ADV_100HDX_CAP:
phy_cap = EFX_PHY_CAP_100HDX;
break;
case MAC_PROP_EN_10FDX_CAP:
case MAC_PROP_ADV_10FDX_CAP:
phy_cap = EFX_PHY_CAP_10FDX;
break;
case MAC_PROP_EN_10HDX_CAP:
case MAC_PROP_ADV_10HDX_CAP:
phy_cap = EFX_PHY_CAP_10HDX;
break;
default:
DTRACE_PROBE(unknown_prop);
return;
}
if (phy_cap != EFX_PHY_CAP_INVALID) {
boolean_t rw;
uint8_t cap_default;
cap_default = sfxge_phy_cap_test(sp, EFX_PHY_CAP_DEFAULT,
phy_cap, &rw);
if (rw == B_TRUE)
mac_prop_info_set_perm(handle, MAC_PROP_PERM_RW);
else
mac_prop_info_set_perm(handle, MAC_PROP_PERM_READ);
mac_prop_info_set_default_uint8(handle, cap_default);
}
}
int
sfxge_gld_register(sfxge_t *sp)
{
mac_callbacks_t *mcp;
mac_register_t *mrp;
mac_handle_t mh;
uint8_t addr[ETHERADDRL];
int rc;
if ((mrp = mac_alloc(MAC_VERSION)) == NULL) {
rc = ENOTSUP;
goto fail1;
}
mrp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
mrp->m_driver = sp;
mrp->m_dip = sp->s_dip;
/* Set up the callbacks */
mcp = &(sp->s_mc);
bzero(mcp, sizeof (mac_callbacks_t));
mcp->mc_getstat = sfxge_gld_getstat;
mcp->mc_start = sfxge_gld_start;
mcp->mc_stop = sfxge_gld_stop;
mcp->mc_setpromisc = sfxge_gld_setpromisc;
mcp->mc_multicst = sfxge_gld_multicst;
mcp->mc_unicst = sfxge_gld_unicst;
mcp->mc_tx = sfxge_gld_tx;
mcp->mc_callbacks |= MC_IOCTL;
mcp->mc_ioctl = sfxge_gld_ioctl;
mcp->mc_callbacks |= MC_GETCAPAB;
mcp->mc_getcapab = sfxge_gld_getcapab;
mcp->mc_callbacks |= MC_SETPROP;
mcp->mc_setprop = sfxge_gld_setprop;
mcp->mc_callbacks |= MC_GETPROP;
mcp->mc_getprop = sfxge_gld_getprop;
mcp->mc_callbacks |= MC_PROPINFO;
mcp->mc_propinfo = sfxge_gld_propinfo;
mrp->m_callbacks = mcp;
mrp->m_src_addr = addr;
if ((rc = sfxge_mac_unicst_get(sp, SFXGE_UNICST_BIA,
mrp->m_src_addr)) != 0)
goto fail2;
mrp->m_min_sdu = 0;
mrp->m_max_sdu = sp->s_mtu;
mrp->m_margin = VLAN_TAGSZ;
/* Set up the private properties */
/* NOTE: m_priv_props added in s10u9 */
mrp->m_priv_props = sp->s_mac_priv_props;
sfxge_gld_priv_prop_init(sp);
/* NOTE: m_flags added in s11.0 */
/* NOTE: m_multicast_sdu added in s11.0 */
/* Register the interface */
if ((rc = mac_register(mrp, &mh)) != 0)
goto fail3;
/* Free the stack registration object */
kmem_free(mrp, sizeof (mac_register_t));
sp->s_mh = mh;
return (0);
fail3:
DTRACE_PROBE(fail3);
fail2:
DTRACE_PROBE(fail2);
/* Free the stack registration object */
mac_free(mrp);
/* Tear down the private properties */
sfxge_gld_priv_prop_fini(sp);
/* Clear the callbacks */
bzero(&(sp->s_mc), sizeof (mac_callbacks_t));
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (rc);
}
int
sfxge_gld_unregister(sfxge_t *sp)
{
mac_handle_t mh = sp->s_mh;
int rc;
if ((rc = mac_unregister(mh)) != 0)
goto fail1;
sp->s_mh = NULL;
/* Tear down the private properties */
sfxge_gld_priv_prop_fini(sp);
/* Clear the callbacks */
bzero(&(sp->s_mc), sizeof (mac_callbacks_t));
return (0);
fail1:
DTRACE_PROBE1(fail1, int, rc);
return (rc);
}