/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
*/
/*
* This file is part of the Chelsio T4 support code.
*
* Copyright (C) 2010-2013 Chelsio Communications. All rights reserved.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this
* release for licensing terms and conditions.
*/
#include <sys/mac_provider.h>
#include <sys/mac_ether.h>
static int t4_mc_start(void *arg);
static void t4_mc_stop(void *arg);
void *val);
.mc_start = t4_mc_start,
.mc_stop = t4_mc_stop,
};
char *t4_priv_props[] = {
#if MAC_VERSION == 1
/* MAC_VERSION 1 doesn't seem to use MAC_PROP_MTU, hmmmm */
#endif
};
static int
{
switch (stat) {
case MAC_STAT_IFSPEED:
*val *= 1000000;
} else
*val = 0;
break;
case MAC_STAT_MULTIRCV:
break;
case MAC_STAT_BRDCSTRCV:
break;
case MAC_STAT_MULTIXMT:
break;
case MAC_STAT_BRDCSTXMT:
break;
case MAC_STAT_NORCVBUF:
*val = 0; /* TODO should come from rxq->nomem */
break;
case MAC_STAT_IERRORS:
break;
case MAC_STAT_UNKNOWNS:
return (ENOTSUP);
case MAC_STAT_NOXMTBUF:
break;
case MAC_STAT_OERRORS:
break;
case MAC_STAT_COLLISIONS:
return (ENOTSUP);
case MAC_STAT_RBYTES:
break;
case MAC_STAT_IPACKETS:
break;
case MAC_STAT_OBYTES:
break;
case MAC_STAT_OPACKETS:
break;
case ETHER_STAT_ALIGN_ERRORS:
return (ENOTSUP);
case ETHER_STAT_FCS_ERRORS:
break;
case ETHER_STAT_SQE_ERRORS:
case ETHER_STAT_DEFER_XMTS:
case ETHER_STAT_EX_COLLISIONS:
return (ENOTSUP);
case ETHER_STAT_MACXMT_ERRORS:
break;
return (ENOTSUP);
break;
case ETHER_STAT_MACRCV_ERRORS:
break;
case ETHER_STAT_XCVR_ADDR:
case ETHER_STAT_XCVR_ID:
case ETHER_STAT_XCVR_INUSE:
return (ENOTSUP);
case ETHER_STAT_CAP_1000FDX:
break;
case ETHER_STAT_CAP_1000HDX:
return (ENOTSUP);
case ETHER_STAT_CAP_100FDX:
break;
case ETHER_STAT_CAP_100HDX:
return (ENOTSUP);
case ETHER_STAT_CAP_10FDX:
case ETHER_STAT_CAP_10HDX:
return (ENOTSUP);
case ETHER_STAT_CAP_ASMPAUSE:
*val = 0;
break;
case ETHER_STAT_CAP_PAUSE:
*val = 1;
break;
case ETHER_STAT_CAP_AUTONEG:
break;
/*
* We have set flow control configuration based on tx_pause and rx_pause
* values supported through ndd. Now, we need to translate the settings
* we have in link_config structure to adv_cap_asmpause and
* adv_cap_pause.
*
* There are 4 combinations possible and the translation is as below:
* tx_pause = 0 => We don't send pause frames during Rx congestion
* tx_pause = 1 => We send pause frames during Rx congestion
* rx_pause = 0 => We ignore received pause frames
* rx_pause = 1 => We pause transmission when we receive pause frames
*
* +----------------------------+----------------------------------+
* | tx_pause | rx_pause | adv_cap_asmpause | adv_cap_pause |
* +-------------------------+-------------------------------------+
* | 0 | 0 | 0 | 0 |
* | 0 | 1 | 1 | 0 |
* | 1 | 0 | 1 | 1 |
* | 1 | 1 | 0 | 1 |
* +----------------------------+----------------------------------+
*/
/* Advertised asymmetric pause capability */
break;
/* Advertised pause capability */
case ETHER_STAT_ADV_CAP_PAUSE:
break;
case ETHER_STAT_ADV_CAP_10FDX:
case ETHER_STAT_ADV_CAP_10HDX:
return (ENOTSUP); /* TODO */
case ETHER_STAT_LP_CAP_100FDX:
case ETHER_STAT_LP_CAP_100HDX:
case ETHER_STAT_LP_CAP_10FDX:
case ETHER_STAT_LP_CAP_10HDX:
case ETHER_STAT_LP_CAP_PAUSE:
return (ENOTSUP);
case ETHER_STAT_LINK_ASMPAUSE:
*val = 0;
break;
case ETHER_STAT_LINK_PAUSE:
*val = 1;
break;
case ETHER_STAT_LINK_AUTONEG:
break;
case ETHER_STAT_LINK_DUPLEX:
*val = LINK_DUPLEX_FULL;
else
break;
default:
#ifdef DEBUG
#endif
return (ENOTSUP);
}
return (0);
}
static int
{
int rc;
if (rc != 0)
return (rc);
end_synchronized_op(pi, 0);
return (rc);
}
static void
{
continue;
(void) t4_uninit_synchronized(pi);
end_synchronized_op(pi, 0);
}
static int
{
int rc;
if (rc != 0)
return (rc);
false);
return (rc);
}
/*
* TODO: Starts failing as soon as the 336 entry table fills up. Need to use
* hash in that case.
*/
static int
{
struct fw_vi_mac_cmd c;
sizeof (c.u.exact[0]), 16);
if (rc != 0)
return (rc);
if (rc != 0)
return (rc);
#ifdef DEBUG
/*
* TODO: Firmware doesn't seem to return the correct index on removal
* (it gives back 0x3fd FW_VI_MAC_MAC_BASED_FREE unchanged. Remove this
* code once it is fixed.
*/
else {
"%02x:%02x:%02x:%02x:%02x:%02x %s %d", mcaddr[0],
}
#endif
return (0);
}
static int
{
int rc;
if (rc != 0)
return (rc);
true, true);
if (rc < 0)
else {
/* LINTED: E_CONSTANT_CONDITION */
rc = 0;
}
return (rc);
}
static mblk_t *
{
}
static boolean_t
{
switch (cap) {
case MAC_CAPAB_HCKSUM:
*d = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM;
} else
break;
case MAC_CAPAB_LSO:
/* Enabling LSO requires Checksum offloading */
mac_capab_lso_t *d = data;
} else
break;
default:
}
return (status);
}
/* ARGSUSED */
static int
const void *val)
{
/*
* Save a copy of link_config. This can be used to restore link_config
* if t4_link_start() fails.
*/
switch (id) {
case MAC_PROP_AUTONEG:
/* LINTED: E_CONSTANT_CONDITION */
relink = 1;
if (new == AUTONEG_DISABLE) {
/* Only 100M is available */
lc->advertising =
} else {
/*
* Advertise autonegotiation capability
* along with supported speeds
*/
lc->requested_speed = 0;
}
}
} else
break;
case MAC_PROP_MTU:
rx_mode = 1;
}
break;
case MAC_PROP_FLOWCTRL:
if (fc == LINK_FLOWCTRL_BI)
else if (fc == LINK_FLOWCTRL_TX)
else if (fc == LINK_FLOWCTRL_RX)
relink = 1;
}
break;
case MAC_PROP_EN_10GFDX_CAP:
relink = 1;
}
} else
break;
case MAC_PROP_EN_1000FDX_CAP:
/* Forced 1G */
relink = 1;
}
} else
break;
case MAC_PROP_EN_100FDX_CAP:
/* Forced 100M */
relink = 1;
}
} else
break;
case MAC_PROP_PRIVATE:
break;
default:
}
if (relink != 0) {
if (rc != 0)
return (rc);
if (rc != 0) {
"start_link failed:%d", rc);
/* Restore link_config */
sizeof (struct link_config));
}
}
if (rx_mode != 0) {
if (rc != 0)
return (rc);
-1, -1, -1, false);
if (rc != 0) {
"set_rxmode failed: %d", rc);
}
}
}
return (rc);
}
static int
void *val)
{
switch (id) {
case MAC_PROP_DUPLEX:
break;
case MAC_PROP_SPEED:
} else
break;
case MAC_PROP_STATUS:
break;
case MAC_PROP_AUTONEG:
break;
case MAC_PROP_MTU:
break;
case MAC_PROP_FLOWCTRL:
else
break;
case MAC_PROP_ADV_10GFDX_CAP:
case MAC_PROP_EN_10GFDX_CAP:
break;
case MAC_PROP_ADV_1000FDX_CAP:
case MAC_PROP_EN_1000FDX_CAP:
break;
case MAC_PROP_ADV_100FDX_CAP:
case MAC_PROP_EN_100FDX_CAP:
break;
case MAC_PROP_PRIVATE:
default:
return (ENOTSUP);
}
return (0);
}
static void
{
switch (id) {
case MAC_PROP_DUPLEX:
case MAC_PROP_SPEED:
case MAC_PROP_STATUS:
break;
case MAC_PROP_AUTONEG:
else
break;
case MAC_PROP_MTU:
break;
case MAC_PROP_FLOWCTRL:
break;
case MAC_PROP_EN_10GFDX_CAP:
else
break;
case MAC_PROP_EN_1000FDX_CAP:
else
break;
case MAC_PROP_EN_100FDX_CAP:
else
break;
case MAC_PROP_ADV_10GFDX_CAP:
case MAC_PROP_ADV_1000FDX_CAP:
case MAC_PROP_ADV_100FDX_CAP:
break;
case MAC_PROP_PRIVATE:
break;
default:
break;
}
}
static int
{
int rc = 0;
if (!waitok) {
goto failed;
goto failed;
}
}
goto failed;
}
/* LINTED: E_CONSTANT_CONDITION */
if (!hold)
return (0);
return (rc);
}
static void
{
if (!held)
/* LINTED: E_CONSTANT_CONDITION */
}
static int
{
int rc = 0;
return (0); /* already running */
return (rc); /* error message displayed already */
if (rc != 0)
return (rc); /* error message displayed already */
} else
if (rc != 0) {
goto done;
}
if (rc < 0) {
goto done;
} else
/* LINTED: E_ASSIGN_NARROW_CONV */
if (rc != 0) {
goto done;
}
if (rc != 0) {
goto done;
}
/* all ok */
done:
if (rc != 0)
(void) t4_uninit_synchronized(pi);
return (rc);
}
/*
* Idempotent.
*/
static int
{
int rc;
/*
* Disable the VI so that all its data in either direction is discarded
* by the MPS. Leave everything else (the queues, interrupts, and 1Hz
* tick) intact as the TP can deliver negative advice or data that it's
* holding in its RAM (for an offloaded connection) even after the VI is
* disabled.
*/
if (rc != 0) {
return (rc);
}
return (0);
}
static void
{
int v;
#if MAC_VERSION == 1
v = ETHERMTU;
#endif
else
return;
}
static int
{
int v;
#if MAC_VERSION == 1
#endif
else
return (ENOTSUP);
return (0);
}
static int
{
long v;
/*
* Save a copy of link_config. This can be used to restore link_config
* if t4_link_start() fails.
*/
if (v < 0 || v >= SGE_NTIMERS)
return (EINVAL);
return (0);
/* LINTED: E_ASSIGN_NARROW_CONV */
}
if (v >= SGE_NCOUNTERS)
return (EINVAL);
return (0);
/* LINTED: E_ASSIGN_NARROW_CONV */
/* takes effect right away */
V_QINTR_CNT_EN(v >= 0);
/* LINTED: E_ASSIGN_NARROW_CONV */
}
if (v != 0 && v != 1)
return (EINVAL);
if (v == 1)
else
if (v != 0 && v != 1)
return (EINVAL);
if (v == 1)
else
if (v != 0 && v != 1)
return (EINVAL);
if (v != 0)
else
relink = 1;
if (v != 0 && v != 1)
return (EINVAL);
if (v != 0)
else
relink = 1;
}
#if MAC_VERSION == 1
if (v < 46 || v > MAX_MTU)
return (EINVAL);
return (0);
rx_mode = 1;
}
#endif
else
return (ENOTSUP);
return (0);
/* If we are here, either relink or rx_mode is 1 */
if (relink != 0) {
if (rc != 0)
return (rc);
if (rc != 0) {
"start_link failed:%d", rc);
/* Restore link_config */
}
} else if (rx_mode != 0) {
if (rc != 0)
return (rc);
-1, -1, false);
if (rc != 0) {
"set_rxmode failed: %d", rc);
}
}
return (rc);
}
return (0);
}
void
{
}
void
{
}
/* ARGSUSED */
void
{
}