net/sfc: retrieve link info

Signed-off-by: Artem Andreev <artem.andreev@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
This commit is contained in:
Artem Andreev 2016-11-29 16:19:14 +00:00 committed by Ferruh Yigit
parent 03ed21195d
commit 886f8d8a05
7 changed files with 118 additions and 4 deletions

View File

@ -4,6 +4,7 @@
; Refer to default.ini for the full list of available PMD features. ; Refer to default.ini for the full list of available PMD features.
; ;
[Features] [Features]
Link status = Y
BSD nic_uio = Y BSD nic_uio = Y
Linux UIO = Y Linux UIO = Y
Linux VFIO = Y Linux VFIO = Y

View File

@ -44,6 +44,8 @@ SFC EFX PMD has support for:
- Multiple transmit and receive queues - Multiple transmit and receive queues
- Link state information
Non-supported Features Non-supported Features
---------------------- ----------------------

View File

@ -37,6 +37,8 @@ CFLAGS += -I$(SRCDIR)/base/
CFLAGS += -I$(SRCDIR) CFLAGS += -I$(SRCDIR)
CFLAGS += -O3 CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS) CFLAGS += $(WERROR_FLAGS)
# Strict-aliasing rules are violated by rte_eth_link to uint64_t casts
CFLAGS += -Wno-strict-aliasing
# Enable extra warnings # Enable extra warnings
CFLAGS += -Wextra CFLAGS += -Wextra

View File

@ -218,6 +218,9 @@ int sfc_port_init(struct sfc_adapter *sa);
void sfc_port_fini(struct sfc_adapter *sa); void sfc_port_fini(struct sfc_adapter *sa);
int sfc_port_start(struct sfc_adapter *sa); int sfc_port_start(struct sfc_adapter *sa);
void sfc_port_stop(struct sfc_adapter *sa); void sfc_port_stop(struct sfc_adapter *sa);
void sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
struct rte_eth_link *link_info);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -37,6 +37,7 @@
#include "sfc_debug.h" #include "sfc_debug.h"
#include "sfc_log.h" #include "sfc_log.h"
#include "sfc_kvargs.h" #include "sfc_kvargs.h"
#include "sfc_ev.h"
static void static void
@ -99,6 +100,46 @@ sfc_dev_start(struct rte_eth_dev *dev)
return -rc; return -rc;
} }
static int
sfc_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete)
{
struct sfc_adapter *sa = dev->data->dev_private;
struct rte_eth_link *dev_link = &dev->data->dev_link;
struct rte_eth_link old_link;
struct rte_eth_link current_link;
sfc_log_init(sa, "entry");
if (sa->state != SFC_ADAPTER_STARTED)
return 0;
retry:
EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t));
*(int64_t *)&old_link = rte_atomic64_read((rte_atomic64_t *)dev_link);
if (wait_to_complete) {
efx_link_mode_t link_mode;
efx_port_poll(sa->nic, &link_mode);
sfc_port_link_mode_to_info(link_mode, &current_link);
if (!rte_atomic64_cmpset((volatile uint64_t *)dev_link,
*(uint64_t *)&old_link,
*(uint64_t *)&current_link))
goto retry;
} else {
sfc_ev_mgmt_qpoll(sa);
*(int64_t *)&current_link =
rte_atomic64_read((rte_atomic64_t *)dev_link);
}
if (old_link.link_status != current_link.link_status)
sfc_info(sa, "Link status is %s",
current_link.link_status ? "UP" : "DOWN");
return old_link.link_status == current_link.link_status ? 0 : -1;
}
static void static void
sfc_dev_stop(struct rte_eth_dev *dev) sfc_dev_stop(struct rte_eth_dev *dev)
{ {
@ -146,6 +187,7 @@ static const struct eth_dev_ops sfc_eth_dev_ops = {
.dev_start = sfc_dev_start, .dev_start = sfc_dev_start,
.dev_stop = sfc_dev_stop, .dev_stop = sfc_dev_stop,
.dev_close = sfc_dev_close, .dev_close = sfc_dev_close,
.link_update = sfc_dev_link_update,
.dev_infos_get = sfc_dev_infos_get, .dev_infos_get = sfc_dev_infos_get,
}; };

View File

@ -181,13 +181,19 @@ sfc_ev_timer(void *arg, uint32_t index)
} }
static boolean_t static boolean_t
sfc_ev_link_change(void *arg, __rte_unused efx_link_mode_t link_mode) sfc_ev_link_change(void *arg, efx_link_mode_t link_mode)
{ {
struct sfc_evq *evq = arg; struct sfc_evq *evq = arg;
struct sfc_adapter *sa = evq->sa;
struct rte_eth_link *dev_link = &sa->eth_dev->data->dev_link;
struct rte_eth_link new_link;
sfc_err(evq->sa, "EVQ %u unexpected link change", EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t));
evq->evq_index);
return B_TRUE; sfc_port_link_mode_to_info(link_mode, &new_link);
rte_atomic64_set((rte_atomic64_t *)dev_link, *(uint64_t *)&new_link);
return B_FALSE;
} }
static const efx_ev_callbacks_t sfc_ev_callbacks = { static const efx_ev_callbacks_t sfc_ev_callbacks = {

View File

@ -129,3 +129,61 @@ sfc_port_fini(struct sfc_adapter *sa)
sfc_log_init(sa, "done"); sfc_log_init(sa, "done");
} }
void
sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
struct rte_eth_link *link_info)
{
SFC_ASSERT(link_mode < EFX_LINK_NMODES);
memset(link_info, 0, sizeof(*link_info));
if ((link_mode == EFX_LINK_DOWN) || (link_mode == EFX_LINK_UNKNOWN))
link_info->link_status = ETH_LINK_DOWN;
else
link_info->link_status = ETH_LINK_UP;
switch (link_mode) {
case EFX_LINK_10HDX:
link_info->link_speed = ETH_SPEED_NUM_10M;
link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
break;
case EFX_LINK_10FDX:
link_info->link_speed = ETH_SPEED_NUM_10M;
link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
break;
case EFX_LINK_100HDX:
link_info->link_speed = ETH_SPEED_NUM_100M;
link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
break;
case EFX_LINK_100FDX:
link_info->link_speed = ETH_SPEED_NUM_100M;
link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
break;
case EFX_LINK_1000HDX:
link_info->link_speed = ETH_SPEED_NUM_1G;
link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
break;
case EFX_LINK_1000FDX:
link_info->link_speed = ETH_SPEED_NUM_1G;
link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
break;
case EFX_LINK_10000FDX:
link_info->link_speed = ETH_SPEED_NUM_10G;
link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
break;
case EFX_LINK_40000FDX:
link_info->link_speed = ETH_SPEED_NUM_40G;
link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
break;
default:
SFC_ASSERT(B_FALSE);
/* FALLTHROUGH */
case EFX_LINK_UNKNOWN:
case EFX_LINK_DOWN:
link_info->link_speed = ETH_SPEED_NUM_NONE;
link_info->link_duplex = 0;
break;
}
link_info->link_autoneg = ETH_LINK_AUTONEG;
}