ce110ea12f
MANA is the new network adapter from Microsoft which will be available in Azure public cloud. It provides SRIOV NIC as virtual function to guest OS running on Hyper-V. The code can be divided into two major parts. Gdma_main.c is the one to bring up the hardware board and drives all underlying hardware queue infrastructure. Mana_en.c contains all main ethernet driver code. It has only tested and supported on amd64 architecture. PR: 256336 Reviewed by: decui@microsoft.com Tested by: whu MFC after: 2 week Relnotes: yes Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D31150
220 lines
7.4 KiB
C
220 lines
7.4 KiB
C
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2021 Microsoft Corp.
|
|
* 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.
|
|
*/
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
#include "mana_sysctl.h"
|
|
|
|
static int mana_sysctl_cleanup_thread_cpu(SYSCTL_HANDLER_ARGS);
|
|
|
|
int mana_log_level = MANA_ALERT | MANA_WARNING | MANA_INFO;
|
|
|
|
SYSCTL_NODE(_hw, OID_AUTO, mana, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
|
|
"MANA driver parameters");
|
|
|
|
/*
|
|
* Logging level for changing verbosity of the output
|
|
*/
|
|
SYSCTL_INT(_hw_mana, OID_AUTO, log_level, CTLFLAG_RWTUN,
|
|
&mana_log_level, 0, "Logging level indicating verbosity of the logs");
|
|
|
|
SYSCTL_CONST_STRING(_hw_mana, OID_AUTO, driver_version, CTLFLAG_RD,
|
|
DRV_MODULE_VERSION, "MANA driver version");
|
|
|
|
void
|
|
mana_sysctl_add_port(struct mana_port_context *apc)
|
|
{
|
|
struct gdma_context *gc = apc->ac->gdma_dev->gdma_context;
|
|
device_t dev = gc->dev;
|
|
struct sysctl_ctx_list *ctx;
|
|
struct sysctl_oid *tree;
|
|
struct sysctl_oid_list *child;
|
|
struct mana_port_stats *port_stats;
|
|
char node_name[32];
|
|
|
|
struct sysctl_oid *port_node, *stats_node;
|
|
struct sysctl_oid_list *stats_list;
|
|
|
|
ctx = device_get_sysctl_ctx(dev);
|
|
tree = device_get_sysctl_tree(dev);
|
|
child = SYSCTL_CHILDREN(tree);
|
|
|
|
port_stats = &apc->port_stats;
|
|
|
|
snprintf(node_name, 32, "port%d", apc->port_idx);
|
|
|
|
port_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
|
|
node_name, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Port Name");
|
|
apc->port_list = SYSCTL_CHILDREN(port_node);
|
|
|
|
SYSCTL_ADD_BOOL(ctx, apc->port_list, OID_AUTO,
|
|
"enable_altq", CTLFLAG_RW, &apc->enable_tx_altq, 0,
|
|
"Choose alternative txq under heavy load");
|
|
|
|
SYSCTL_ADD_PROC(ctx, apc->port_list, OID_AUTO,
|
|
"bind_cleanup_thread_cpu",
|
|
CTLTYPE_U8 | CTLFLAG_RW | CTLFLAG_MPSAFE,
|
|
apc, 0, mana_sysctl_cleanup_thread_cpu, "I",
|
|
"Bind cleanup thread to a cpu. 0 disables it.");
|
|
|
|
stats_node = SYSCTL_ADD_NODE(ctx, apc->port_list, OID_AUTO,
|
|
"port_stats", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
|
|
"Statistics of port");
|
|
stats_list = SYSCTL_CHILDREN(stats_node);
|
|
|
|
SYSCTL_ADD_COUNTER_U64(ctx, stats_list, OID_AUTO, "rx_packets",
|
|
CTLFLAG_RD, &port_stats->rx_packets, "Packets received");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, stats_list, OID_AUTO, "tx_packets",
|
|
CTLFLAG_RD, &port_stats->tx_packets, "Packets transmitted");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, stats_list, OID_AUTO, "rx_bytes",
|
|
CTLFLAG_RD, &port_stats->rx_bytes, "Bytes received");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, stats_list, OID_AUTO, "tx_bytes",
|
|
CTLFLAG_RD, &port_stats->tx_bytes, "Bytes transmitted");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, stats_list, OID_AUTO, "rx_drops",
|
|
CTLFLAG_RD, &port_stats->rx_drops, "Receive packet drops");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, stats_list, OID_AUTO, "tx_drops",
|
|
CTLFLAG_RD, &port_stats->tx_drops, "Transmit packet drops");
|
|
}
|
|
|
|
void
|
|
mana_sysctl_add_queues(struct mana_port_context *apc)
|
|
{
|
|
struct sysctl_ctx_list *ctx = &apc->que_sysctl_ctx;
|
|
struct sysctl_oid_list *child = apc->port_list;
|
|
|
|
struct sysctl_oid *queue_node, *tx_node, *rx_node;
|
|
struct sysctl_oid_list *queue_list, *tx_list, *rx_list;
|
|
struct mana_txq *txq;
|
|
struct mana_rxq *rxq;
|
|
struct mana_stats *tx_stats, *rx_stats;
|
|
char que_name[32];
|
|
int i;
|
|
|
|
sysctl_ctx_init(ctx);
|
|
|
|
for (i = 0; i < apc->num_queues; i++) {
|
|
rxq = apc->rxqs[i];
|
|
txq = &apc->tx_qp[i].txq;
|
|
|
|
snprintf(que_name, 32, "queue%d", i);
|
|
|
|
queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
|
|
que_name, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
|
|
queue_list = SYSCTL_CHILDREN(queue_node);
|
|
|
|
/* TX stats */
|
|
tx_node = SYSCTL_ADD_NODE(ctx, queue_list, OID_AUTO,
|
|
"txq", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "TX queue");
|
|
tx_list = SYSCTL_CHILDREN(tx_node);
|
|
|
|
tx_stats = &txq->stats;
|
|
|
|
SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO, "count",
|
|
CTLFLAG_RD, &tx_stats->packets, "Packets sent");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO, "bytes",
|
|
CTLFLAG_RD, &tx_stats->bytes, "Bytes sent");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO, "queue_wakeups",
|
|
CTLFLAG_RD, &tx_stats->wakeup, "Queue wakeups");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO, "queue_stops",
|
|
CTLFLAG_RD, &tx_stats->stop, "Queue stops");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO, "mbuf_collapse",
|
|
CTLFLAG_RD, &tx_stats->collapse, "Mbuf collapse count");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
|
|
"mbuf_collapse_err", CTLFLAG_RD,
|
|
&tx_stats->collapse_err, "Mbuf collapse failures");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
|
|
"dma_mapping_err", CTLFLAG_RD,
|
|
&tx_stats->dma_mapping_err, "DMA mapping failures");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
|
|
"alt_chg", CTLFLAG_RD,
|
|
&tx_stats->alt_chg, "Switch to alternative txq");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
|
|
"alt_reset", CTLFLAG_RD,
|
|
&tx_stats->alt_reset, "Reset to self txq");
|
|
|
|
/* RX stats */
|
|
rx_node = SYSCTL_ADD_NODE(ctx, queue_list, OID_AUTO,
|
|
"rxq", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "RX queue");
|
|
rx_list = SYSCTL_CHILDREN(rx_node);
|
|
|
|
rx_stats = &rxq->stats;
|
|
|
|
SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO, "count",
|
|
CTLFLAG_RD, &rx_stats->packets, "Packets received");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO, "bytes",
|
|
CTLFLAG_RD, &rx_stats->bytes, "Bytes received");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
|
|
"mbuf_alloc_fail", CTLFLAG_RD,
|
|
&rx_stats->mbuf_alloc_fail, "Failed mbuf allocs");
|
|
SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
|
|
"dma_mapping_err", CTLFLAG_RD,
|
|
&rx_stats->dma_mapping_err, "DMA mapping errors");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Free all queues' sysctl trees attached to the port's tree.
|
|
*/
|
|
void
|
|
mana_sysctl_free_queues(struct mana_port_context *apc)
|
|
{
|
|
sysctl_ctx_free(&apc->que_sysctl_ctx);
|
|
}
|
|
|
|
static int
|
|
mana_sysctl_cleanup_thread_cpu(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct mana_port_context *apc = arg1;
|
|
bool bind_cpu = false;
|
|
uint8_t val;
|
|
int err;
|
|
|
|
val = 0;
|
|
err = sysctl_wire_old_buffer(req, sizeof(val));
|
|
if (err == 0) {
|
|
val = apc->bind_cleanup_thread_cpu;
|
|
err = sysctl_handle_8(oidp, &val, 0, req);
|
|
}
|
|
|
|
if (err != 0 || req->newptr == NULL)
|
|
return (err);
|
|
|
|
if (val != 0)
|
|
bind_cpu = true;
|
|
|
|
if (bind_cpu != apc->bind_cleanup_thread_cpu) {
|
|
apc->bind_cleanup_thread_cpu = bind_cpu;
|
|
err = mana_restart(apc);
|
|
}
|
|
|
|
return (err);
|
|
}
|