7113afc84c
This patch has the driver for 10Gigabit Ethernet controller in AMD SoC. This driver is written compatible to the Iflib framework. The existing driver is for the old version of hardware. The submitted driver here is for the recent versions of the hardware where the Ethernet controller is PCI-E based. Submitted by: Rajesh Kumar <rajesh1.kumar@amd.com> MFC after: 1 month Relnotes: yes Differential Revision: https://reviews.freebsd.org/D25793
1716 lines
44 KiB
C
1716 lines
44 KiB
C
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
|
*
|
|
* Copyright (c) 2020 Advanced Micro Devices, Inc.
|
|
*
|
|
* 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 AUTHOR 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 AUTHOR 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.
|
|
*
|
|
* Contact Information :
|
|
* Rajesh Kumar <rajesh1.kumar@amd.com>
|
|
* Arpan Palit <Arpan.Palit@amd.com>
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/sbuf.h>
|
|
|
|
#include "xgbe.h"
|
|
#include "xgbe-common.h"
|
|
|
|
#define SYSCTL_BUF_LEN 64
|
|
|
|
typedef enum{
|
|
/* Coalesce flag */
|
|
rx_coalesce_usecs = 1,
|
|
rx_max_coalesced_frames,
|
|
rx_coalesce_usecs_irq,
|
|
rx_max_coalesced_frames_irq,
|
|
tx_coalesce_usecs,
|
|
tx_max_coalesced_frames,
|
|
tx_coalesce_usecs_irq,
|
|
tx_max_coalesced_frames_irq,
|
|
stats_block_coalesce_usecs,
|
|
use_adaptive_rx_coalesce,
|
|
use_adaptive_tx_coalesce,
|
|
pkt_rate_low,
|
|
rx_coalesce_usecs_low,
|
|
rx_max_coalesced_frames_low,
|
|
tx_coalesce_usecs_low,
|
|
tx_max_coalesced_frames_low,
|
|
pkt_rate_high,
|
|
rx_coalesce_usecs_high,
|
|
rx_max_coalesced_frames_high,
|
|
tx_coalesce_usecs_high,
|
|
tx_max_coalesced_frames_high,
|
|
rate_sample_interval,
|
|
|
|
/* Pasue flag */
|
|
autoneg,
|
|
tx_pause,
|
|
rx_pause,
|
|
|
|
/* link settings */
|
|
speed,
|
|
duplex,
|
|
|
|
/* Ring settings */
|
|
rx_pending,
|
|
rx_mini_pending,
|
|
rx_jumbo_pending,
|
|
tx_pending,
|
|
|
|
/* Channels settings */
|
|
rx_count,
|
|
tx_count,
|
|
other_count,
|
|
combined_count,
|
|
} sysctl_variable_t;
|
|
|
|
typedef enum {
|
|
SYSL_NONE,
|
|
SYSL_BOOL,
|
|
SYSL_S32,
|
|
SYSL_U8,
|
|
SYSL_U16,
|
|
SYSL_U32,
|
|
SYSL_U64,
|
|
SYSL_BE16,
|
|
SYSL_IP4,
|
|
SYSL_STR,
|
|
SYSL_FLAG,
|
|
SYSL_MAC,
|
|
} sysctl_type_t;
|
|
|
|
struct sysctl_info {
|
|
uint8_t name[32];
|
|
sysctl_type_t type;
|
|
sysctl_variable_t flag;
|
|
uint8_t support[16];
|
|
};
|
|
|
|
struct sysctl_op {
|
|
/* Coalesce options */
|
|
unsigned int rx_coalesce_usecs;
|
|
unsigned int rx_max_coalesced_frames;
|
|
unsigned int rx_coalesce_usecs_irq;
|
|
unsigned int rx_max_coalesced_frames_irq;
|
|
unsigned int tx_coalesce_usecs;
|
|
unsigned int tx_max_coalesced_frames;
|
|
unsigned int tx_coalesce_usecs_irq;
|
|
unsigned int tx_max_coalesced_frames_irq;
|
|
unsigned int stats_block_coalesce_usecs;
|
|
unsigned int use_adaptive_rx_coalesce;
|
|
unsigned int use_adaptive_tx_coalesce;
|
|
unsigned int pkt_rate_low;
|
|
unsigned int rx_coalesce_usecs_low;
|
|
unsigned int rx_max_coalesced_frames_low;
|
|
unsigned int tx_coalesce_usecs_low;
|
|
unsigned int tx_max_coalesced_frames_low;
|
|
unsigned int pkt_rate_high;
|
|
unsigned int rx_coalesce_usecs_high;
|
|
unsigned int rx_max_coalesced_frames_high;
|
|
unsigned int tx_coalesce_usecs_high;
|
|
unsigned int tx_max_coalesced_frames_high;
|
|
unsigned int rate_sample_interval;
|
|
|
|
/* Pasue options */
|
|
unsigned int autoneg;
|
|
unsigned int tx_pause;
|
|
unsigned int rx_pause;
|
|
|
|
/* Link settings options */
|
|
unsigned int speed;
|
|
unsigned int duplex;
|
|
|
|
/* Ring param options */
|
|
unsigned int rx_max_pending;
|
|
unsigned int rx_mini_max_pending;
|
|
unsigned int rx_jumbo_max_pending;
|
|
unsigned int tx_max_pending;
|
|
unsigned int rx_pending;
|
|
unsigned int rx_mini_pending;
|
|
unsigned int rx_jumbo_pending;
|
|
unsigned int tx_pending;
|
|
|
|
/* Channels options */
|
|
unsigned int max_rx;
|
|
unsigned int max_tx;
|
|
unsigned int max_other;
|
|
unsigned int max_combined;
|
|
unsigned int rx_count;
|
|
unsigned int tx_count;
|
|
unsigned int other_count;
|
|
unsigned int combined_count;
|
|
} sys_op;
|
|
|
|
#define GSTRING_LEN 32
|
|
|
|
struct xgbe_stats {
|
|
char stat_string[GSTRING_LEN];
|
|
int stat_size;
|
|
int stat_offset;
|
|
};
|
|
|
|
#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
|
|
|
|
#define XGMAC_MMC_STAT(_string, _var) \
|
|
{ _string, \
|
|
FIELD_SIZEOF(struct xgbe_mmc_stats, _var), \
|
|
offsetof(struct xgbe_prv_data, mmc_stats._var), \
|
|
}
|
|
|
|
#define XGMAC_EXT_STAT(_string, _var) \
|
|
{ _string, \
|
|
FIELD_SIZEOF(struct xgbe_ext_stats, _var), \
|
|
offsetof(struct xgbe_prv_data, ext_stats._var), \
|
|
}
|
|
static const struct xgbe_stats xgbe_gstring_stats[] = {
|
|
XGMAC_MMC_STAT("tx_bytes", txoctetcount_gb),
|
|
XGMAC_MMC_STAT("tx_packets", txframecount_gb),
|
|
XGMAC_MMC_STAT("tx_unicast_packets", txunicastframes_gb),
|
|
XGMAC_MMC_STAT("tx_broadcast_packets", txbroadcastframes_gb),
|
|
XGMAC_MMC_STAT("tx_multicast_packets", txmulticastframes_gb),
|
|
XGMAC_MMC_STAT("tx_vlan_packets", txvlanframes_g),
|
|
XGMAC_EXT_STAT("tx_vxlan_packets", tx_vxlan_packets),
|
|
XGMAC_EXT_STAT("tx_tso_packets", tx_tso_packets),
|
|
XGMAC_MMC_STAT("tx_64_byte_packets", tx64octets_gb),
|
|
XGMAC_MMC_STAT("tx_65_to_127_byte_packets", tx65to127octets_gb),
|
|
XGMAC_MMC_STAT("tx_128_to_255_byte_packets", tx128to255octets_gb),
|
|
XGMAC_MMC_STAT("tx_256_to_511_byte_packets", tx256to511octets_gb),
|
|
XGMAC_MMC_STAT("tx_512_to_1023_byte_packets", tx512to1023octets_gb),
|
|
XGMAC_MMC_STAT("tx_1024_to_max_byte_packets", tx1024tomaxoctets_gb),
|
|
XGMAC_MMC_STAT("tx_underflow_errors", txunderflowerror),
|
|
XGMAC_MMC_STAT("tx_pause_frames", txpauseframes),
|
|
|
|
XGMAC_MMC_STAT("rx_bytes", rxoctetcount_gb),
|
|
XGMAC_MMC_STAT("rx_packets", rxframecount_gb),
|
|
XGMAC_MMC_STAT("rx_unicast_packets", rxunicastframes_g),
|
|
XGMAC_MMC_STAT("rx_broadcast_packets", rxbroadcastframes_g),
|
|
XGMAC_MMC_STAT("rx_multicast_packets", rxmulticastframes_g),
|
|
XGMAC_MMC_STAT("rx_vlan_packets", rxvlanframes_gb),
|
|
XGMAC_EXT_STAT("rx_vxlan_packets", rx_vxlan_packets),
|
|
XGMAC_MMC_STAT("rx_64_byte_packets", rx64octets_gb),
|
|
XGMAC_MMC_STAT("rx_65_to_127_byte_packets", rx65to127octets_gb),
|
|
XGMAC_MMC_STAT("rx_128_to_255_byte_packets", rx128to255octets_gb),
|
|
XGMAC_MMC_STAT("rx_256_to_511_byte_packets", rx256to511octets_gb),
|
|
XGMAC_MMC_STAT("rx_512_to_1023_byte_packets", rx512to1023octets_gb),
|
|
XGMAC_MMC_STAT("rx_1024_to_max_byte_packets", rx1024tomaxoctets_gb),
|
|
XGMAC_MMC_STAT("rx_undersize_packets", rxundersize_g),
|
|
XGMAC_MMC_STAT("rx_oversize_packets", rxoversize_g),
|
|
XGMAC_MMC_STAT("rx_crc_errors", rxcrcerror),
|
|
XGMAC_MMC_STAT("rx_crc_errors_small_packets", rxrunterror),
|
|
XGMAC_MMC_STAT("rx_crc_errors_giant_packets", rxjabbererror),
|
|
XGMAC_MMC_STAT("rx_length_errors", rxlengtherror),
|
|
XGMAC_MMC_STAT("rx_out_of_range_errors", rxoutofrangetype),
|
|
XGMAC_MMC_STAT("rx_fifo_overflow_errors", rxfifooverflow),
|
|
XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror),
|
|
XGMAC_EXT_STAT("rx_csum_errors", rx_csum_errors),
|
|
XGMAC_EXT_STAT("rx_vxlan_csum_errors", rx_vxlan_csum_errors),
|
|
XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes),
|
|
XGMAC_EXT_STAT("rx_split_header_packets", rx_split_header_packets),
|
|
XGMAC_EXT_STAT("rx_buffer_unavailable", rx_buffer_unavailable),
|
|
};
|
|
|
|
#define XGBE_STATS_COUNT ARRAY_SIZE(xgbe_gstring_stats)
|
|
|
|
char** alloc_sysctl_buffer(void);
|
|
void get_val(char *buf, char **op, char **val, int *n_op);
|
|
void fill_data(struct sysctl_op *sys_op, int flag, unsigned int value);
|
|
|
|
static int
|
|
exit_bad_op(void)
|
|
{
|
|
|
|
printf("SYSCTL: bad command line option (s)\n");
|
|
return(-EINVAL);
|
|
}
|
|
|
|
static inline unsigned
|
|
fls_long(unsigned long l)
|
|
{
|
|
|
|
if (sizeof(l) == 4)
|
|
return (fls(l));
|
|
return (fls64(l));
|
|
}
|
|
|
|
static inline __attribute__((const))
|
|
unsigned long __rounddown_pow_of_two(unsigned long n)
|
|
{
|
|
|
|
return (1UL << (fls_long(n) - 1));
|
|
}
|
|
|
|
static inline int
|
|
get_ubuf(struct sysctl_req *req, char *ubuf)
|
|
{
|
|
int rc;
|
|
|
|
printf("%s: len:0x%li idx:0x%li\n", __func__, req->newlen,
|
|
req->newidx);
|
|
if (req->newlen >= SYSCTL_BUF_LEN)
|
|
return (-EINVAL);
|
|
|
|
rc = SYSCTL_IN(req, ubuf, req->newlen);
|
|
if (rc)
|
|
return (rc);
|
|
ubuf[req->newlen] = '\0';
|
|
|
|
return (0);
|
|
}
|
|
|
|
char**
|
|
alloc_sysctl_buffer(void)
|
|
{
|
|
char **buffer;
|
|
int i;
|
|
|
|
buffer = malloc(sizeof(char *)*32, M_AXGBE, M_WAITOK | M_ZERO);
|
|
for(i = 0; i < 32; i++)
|
|
buffer[i] = malloc(sizeof(char)*32, M_AXGBE, M_WAITOK | M_ZERO);
|
|
|
|
return (buffer);
|
|
}
|
|
|
|
void
|
|
get_val(char *buf, char **op, char **val, int *n_op)
|
|
{
|
|
int blen = strlen(buf);
|
|
int count = 0;
|
|
int i, j;
|
|
|
|
*n_op = 0;
|
|
for (i = 0; i < blen; i++) {
|
|
count++;
|
|
/* Get sysctl command option */
|
|
for (j = 0; buf[i] != ' '; j++) {
|
|
if (i >= blen)
|
|
break;
|
|
op[*n_op][j] = buf[i++];
|
|
}
|
|
op[*n_op][j+1] = '\0';
|
|
if (i >= strlen(buf))
|
|
goto out;
|
|
|
|
/* Get sysctl value*/
|
|
i++;
|
|
for (j = 0; buf[i] != ' '; j++) {
|
|
if (i >= blen)
|
|
break;
|
|
val[*n_op][j] = buf[i++];
|
|
}
|
|
val[*n_op][j+1] = '\0';
|
|
if (i >= strlen(buf))
|
|
goto out;
|
|
|
|
*n_op = count;
|
|
}
|
|
|
|
out:
|
|
*n_op = count;
|
|
}
|
|
|
|
void
|
|
fill_data(struct sysctl_op *sys_op, int flag, unsigned int value)
|
|
{
|
|
|
|
switch(flag) {
|
|
case 1:
|
|
sys_op->rx_coalesce_usecs = value;
|
|
break;
|
|
case 2:
|
|
sys_op->rx_max_coalesced_frames = value;
|
|
break;
|
|
case 3:
|
|
sys_op->rx_coalesce_usecs_irq = value;
|
|
break;
|
|
case 4:
|
|
sys_op->rx_max_coalesced_frames_irq = value;
|
|
break;
|
|
case 5:
|
|
sys_op->tx_coalesce_usecs = value;
|
|
break;
|
|
case 6:
|
|
sys_op->tx_max_coalesced_frames = value;
|
|
break;
|
|
case 7:
|
|
sys_op->tx_coalesce_usecs_irq = value;
|
|
break;
|
|
case 8:
|
|
sys_op->tx_max_coalesced_frames_irq = value;
|
|
break;
|
|
case 9:
|
|
sys_op->stats_block_coalesce_usecs = value;
|
|
break;
|
|
case 10:
|
|
sys_op->use_adaptive_rx_coalesce = value;
|
|
break;
|
|
case 11:
|
|
sys_op->use_adaptive_tx_coalesce = value;
|
|
break;
|
|
case 12:
|
|
sys_op->pkt_rate_low = value;
|
|
break;
|
|
case 13:
|
|
sys_op->rx_coalesce_usecs_low = value;
|
|
break;
|
|
case 14:
|
|
sys_op->rx_max_coalesced_frames_low = value;
|
|
break;
|
|
case 15:
|
|
sys_op->tx_coalesce_usecs_low = value;
|
|
break;
|
|
case 16:
|
|
sys_op->tx_max_coalesced_frames_low = value;
|
|
break;
|
|
case 17:
|
|
sys_op->pkt_rate_high = value;
|
|
break;
|
|
case 18:
|
|
sys_op->rx_coalesce_usecs_high = value;
|
|
break;
|
|
case 19:
|
|
sys_op->rx_max_coalesced_frames_high = value;
|
|
break;
|
|
case 20:
|
|
sys_op->tx_coalesce_usecs_high = value;
|
|
break;
|
|
case 21:
|
|
sys_op->tx_max_coalesced_frames_high = value;
|
|
break;
|
|
case 22:
|
|
sys_op->rate_sample_interval = value;
|
|
break;
|
|
case 23:
|
|
sys_op->autoneg = value;
|
|
break;
|
|
case 24:
|
|
sys_op->rx_pause = value;
|
|
break;
|
|
case 25:
|
|
sys_op->tx_pause = value;
|
|
break;
|
|
case 26:
|
|
sys_op->speed = value;
|
|
break;
|
|
case 27:
|
|
sys_op->duplex = value;
|
|
break;
|
|
case 28:
|
|
sys_op->rx_pending = value;
|
|
break;
|
|
case 29:
|
|
sys_op->rx_mini_pending = value;
|
|
break;
|
|
case 30:
|
|
sys_op->rx_jumbo_pending = value;
|
|
break;
|
|
case 31:
|
|
sys_op->tx_pending = value;
|
|
break;
|
|
default:
|
|
printf("Option error\n");
|
|
}
|
|
}
|
|
|
|
static int
|
|
parse_generic_sysctl(struct xgbe_prv_data *pdata, char *buf,
|
|
struct sysctl_info *info, unsigned int n_info)
|
|
{
|
|
struct sysctl_op *sys_op = pdata->sys_op;
|
|
unsigned int value;
|
|
char **op, **val;
|
|
int n_op = 0;
|
|
int rc = 0;
|
|
int i, idx;
|
|
|
|
op = alloc_sysctl_buffer();
|
|
val = alloc_sysctl_buffer();
|
|
get_val(buf, op, val, &n_op);
|
|
|
|
for (i = 0; i < n_op; i++) {
|
|
for (idx = 0; idx < n_info; idx++) {
|
|
if (strcmp(info[idx].name, op[i]) == 0) {
|
|
if (strcmp(info[idx].support,
|
|
"not-supported") == 0){
|
|
axgbe_printf(1, "ignoring not-supported "
|
|
"option \"%s\"\n", info[idx].name);
|
|
break;
|
|
}
|
|
switch(info[idx].type) {
|
|
case SYSL_BOOL: {
|
|
if (!strcmp(val[i], "on"))
|
|
fill_data(sys_op,
|
|
info[idx].flag, 1);
|
|
else if (!strcmp(val[i], "off"))
|
|
fill_data(sys_op,
|
|
info[idx].flag, 0);
|
|
else
|
|
rc = exit_bad_op();
|
|
break;
|
|
}
|
|
case SYSL_S32:
|
|
sscanf(val[i], "%u", &value);
|
|
fill_data(sys_op, info[idx].flag, value);
|
|
break;
|
|
case SYSL_U8:
|
|
if (!strcmp(val[i], "half"))
|
|
fill_data(sys_op,
|
|
info[idx].flag, DUPLEX_HALF);
|
|
else if (!strcmp(val[i], "full"))
|
|
fill_data(sys_op,
|
|
info[idx].flag, DUPLEX_FULL);
|
|
else
|
|
exit_bad_op();
|
|
default:
|
|
rc = exit_bad_op();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i = 0; i < 32; i++)
|
|
free(op[i], M_AXGBE);
|
|
free(op, M_AXGBE);
|
|
|
|
for(i = 0; i < 32; i++)
|
|
free(val[i], M_AXGBE);
|
|
free(val, M_AXGBE);
|
|
return (rc);
|
|
}
|
|
|
|
|
|
static int
|
|
sysctl_xgmac_reg_addr_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
unsigned int reg;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
axgbe_printf(2, "READ: %s: sysctl_xgmac_reg: 0x%x\n", __func__,
|
|
pdata->sysctl_xgmac_reg);
|
|
sbuf_printf(sb, "\nXGMAC reg_addr: 0x%x\n",
|
|
pdata->sysctl_xgmac_reg);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%x", ®);
|
|
axgbe_printf(2, "WRITE: %s: reg: 0x%x\n", __func__, reg);
|
|
pdata->sysctl_xgmac_reg = reg;
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_get_drv_info_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
struct xgbe_hw_features *hw_feat = &pdata->hw_feat;
|
|
ssize_t buf_size = 64;
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
sbuf_printf(sb, "\ndriver: %s", XGBE_DRV_NAME);
|
|
sbuf_printf(sb, "\nversion: %s", XGBE_DRV_VERSION);
|
|
sbuf_printf(sb, "\nfirmware-version: %d.%d.%d",
|
|
XGMAC_GET_BITS(hw_feat->version, MAC_VR, USERVER),
|
|
XGMAC_GET_BITS(hw_feat->version, MAC_VR, DEVID),
|
|
XGMAC_GET_BITS(hw_feat->version, MAC_VR, SNPSVER));
|
|
sbuf_printf(sb, "\nbus-info: %04d:%02d:%02d",
|
|
pdata->pcie_bus, pdata->pcie_device, pdata->pcie_func);
|
|
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
return (-EINVAL);
|
|
}
|
|
|
|
static int
|
|
sysctl_get_link_info_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
sbuf_printf(sb, "\nLink is %s", pdata->phy.link ? "Up" : "Down");
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (0);
|
|
}
|
|
|
|
return (-EINVAL);
|
|
}
|
|
|
|
#define COALESCE_SYSCTL_INFO(__coalop) \
|
|
{ \
|
|
{ "adaptive-rx", SYSL_BOOL, use_adaptive_rx_coalesce, "not-supported" }, \
|
|
{ "adaptive-tx", SYSL_BOOL, use_adaptive_tx_coalesce, "not-supported" }, \
|
|
{ "sample-interval", SYSL_S32, rate_sample_interval, "not-supported" }, \
|
|
{ "stats-block-usecs", SYSL_S32, stats_block_coalesce_usecs, "not-supported" }, \
|
|
{ "pkt-rate-low", SYSL_S32, pkt_rate_low, "not-supported" }, \
|
|
{ "pkt-rate-high", SYSL_S32, pkt_rate_high, "not-supported" }, \
|
|
{ "rx-usecs", SYSL_S32, rx_coalesce_usecs, "supported" }, \
|
|
{ "rx-frames", SYSL_S32, rx_max_coalesced_frames, "supported" }, \
|
|
{ "rx-usecs-irq", SYSL_S32, rx_coalesce_usecs_irq, "not-supported" }, \
|
|
{ "rx-frames-irq", SYSL_S32, rx_max_coalesced_frames_irq, "not-supported" }, \
|
|
{ "tx-usecs", SYSL_S32, tx_coalesce_usecs, "not-supported" }, \
|
|
{ "tx-frames", SYSL_S32, tx_max_coalesced_frames, "supported" }, \
|
|
{ "tx-usecs-irq", SYSL_S32, tx_coalesce_usecs_irq, "not-supported" }, \
|
|
{ "tx-frames-irq", SYSL_S32, tx_max_coalesced_frames_irq, "not-supported" }, \
|
|
{ "rx-usecs-low", SYSL_S32, rx_coalesce_usecs_low, "not-supported" }, \
|
|
{ "rx-frames-low", SYSL_S32, rx_max_coalesced_frames_low, "not-supported"}, \
|
|
{ "tx-usecs-low", SYSL_S32, tx_coalesce_usecs_low, "not-supported" }, \
|
|
{ "tx-frames-low", SYSL_S32, tx_max_coalesced_frames_low, "not-supported" }, \
|
|
{ "rx-usecs-high", SYSL_S32, rx_coalesce_usecs_high, "not-supported" }, \
|
|
{ "rx-frames-high", SYSL_S32, rx_max_coalesced_frames_high, "not-supported" }, \
|
|
{ "tx-usecs-high", SYSL_S32, tx_coalesce_usecs_high, "not-supported" }, \
|
|
{ "tx-frames-high", SYSL_S32, tx_max_coalesced_frames_high, "not-supported" }, \
|
|
}
|
|
|
|
static int
|
|
sysctl_coalesce_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
|
struct sysctl_op *sys_op = pdata->sys_op;
|
|
struct sysctl_info sysctl_coalesce[] = COALESCE_SYSCTL_INFO(coalop);
|
|
unsigned int rx_frames, rx_riwt, rx_usecs;
|
|
unsigned int tx_frames;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
sys_op->rx_coalesce_usecs = pdata->rx_usecs;
|
|
sys_op->rx_max_coalesced_frames = pdata->rx_frames;
|
|
sys_op->tx_max_coalesced_frames = pdata->tx_frames;
|
|
|
|
sbuf_printf(sb, "\nAdaptive RX: %s TX: %s\n",
|
|
sys_op->use_adaptive_rx_coalesce ? "on" : "off",
|
|
sys_op->use_adaptive_tx_coalesce ? "on" : "off");
|
|
|
|
sbuf_printf(sb, "stats-block-usecs: %u\n"
|
|
"sample-interval: %u\n"
|
|
"pkt-rate-low: %u\n"
|
|
"pkt-rate-high: %u\n"
|
|
"\n"
|
|
"rx-usecs: %u\n"
|
|
"rx-frames: %u\n"
|
|
"rx-usecs-irq: %u\n"
|
|
"rx-frames-irq: %u\n"
|
|
"\n"
|
|
"tx-usecs: %u\n"
|
|
"tx-frames: %u\n"
|
|
"tx-usecs-irq: %u\n"
|
|
"tx-frames-irq: %u\n"
|
|
"\n"
|
|
"rx-usecs-low: %u\n"
|
|
"rx-frames-low: %u\n"
|
|
"tx-usecs-low: %u\n"
|
|
"tx-frames-low: %u\n"
|
|
"\n"
|
|
"rx-usecs-high: %u\n"
|
|
"rx-frames-high: %u\n"
|
|
"tx-usecs-high: %u\n"
|
|
"tx-frames-high: %u\n",
|
|
sys_op->stats_block_coalesce_usecs,
|
|
sys_op->rate_sample_interval,
|
|
sys_op->pkt_rate_low,
|
|
sys_op->pkt_rate_high,
|
|
|
|
sys_op->rx_coalesce_usecs,
|
|
sys_op->rx_max_coalesced_frames,
|
|
sys_op->rx_coalesce_usecs_irq,
|
|
sys_op->rx_max_coalesced_frames_irq,
|
|
|
|
sys_op->tx_coalesce_usecs,
|
|
sys_op->tx_max_coalesced_frames,
|
|
sys_op->tx_coalesce_usecs_irq,
|
|
sys_op->tx_max_coalesced_frames_irq,
|
|
|
|
sys_op->rx_coalesce_usecs_low,
|
|
sys_op->rx_max_coalesced_frames_low,
|
|
sys_op->tx_coalesce_usecs_low,
|
|
sys_op->tx_max_coalesced_frames_low,
|
|
|
|
sys_op->rx_coalesce_usecs_high,
|
|
sys_op->rx_max_coalesced_frames_high,
|
|
sys_op->tx_coalesce_usecs_high,
|
|
sys_op->tx_max_coalesced_frames_high);
|
|
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (0);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
parse_generic_sysctl(pdata, buf, sysctl_coalesce,
|
|
ARRAY_SIZE(sysctl_coalesce));
|
|
|
|
rx_riwt = hw_if->usec_to_riwt(pdata, sys_op->rx_coalesce_usecs);
|
|
rx_usecs = sys_op->rx_coalesce_usecs;
|
|
rx_frames = sys_op->rx_max_coalesced_frames;
|
|
|
|
/* Use smallest possible value if conversion resulted in zero */
|
|
if (rx_usecs && !rx_riwt)
|
|
rx_riwt = 1;
|
|
|
|
/* Check the bounds of values for Rx */
|
|
if (rx_riwt > XGMAC_MAX_DMA_RIWT) {
|
|
axgbe_printf(2, "rx-usec is limited to %d usecs\n",
|
|
hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT));
|
|
return (-EINVAL);
|
|
}
|
|
if (rx_frames > pdata->rx_desc_count) {
|
|
axgbe_printf(2, "rx-frames is limited to %d frames\n",
|
|
pdata->rx_desc_count);
|
|
return (-EINVAL);
|
|
}
|
|
|
|
tx_frames = sys_op->tx_max_coalesced_frames;
|
|
|
|
/* Check the bounds of values for Tx */
|
|
if (tx_frames > pdata->tx_desc_count) {
|
|
axgbe_printf(2, "tx-frames is limited to %d frames\n",
|
|
pdata->tx_desc_count);
|
|
return (-EINVAL);
|
|
}
|
|
|
|
pdata->rx_riwt = rx_riwt;
|
|
pdata->rx_usecs = rx_usecs;
|
|
pdata->rx_frames = rx_frames;
|
|
hw_if->config_rx_coalesce(pdata);
|
|
|
|
pdata->tx_frames = tx_frames;
|
|
hw_if->config_tx_coalesce(pdata);
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_pauseparam_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
struct sysctl_op *sys_op = pdata->sys_op;
|
|
struct sysctl_info sysctl_pauseparam[] = {
|
|
{ "autoneg", SYSL_BOOL, autoneg, "supported" },
|
|
{ "rx", SYSL_BOOL, rx_pause, "supported" },
|
|
{ "tx", SYSL_BOOL, tx_pause, "supported" },
|
|
};
|
|
ssize_t buf_size = 512;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
sys_op->autoneg = pdata->phy.pause_autoneg;
|
|
sys_op->tx_pause = pdata->phy.tx_pause;
|
|
sys_op->rx_pause = pdata->phy.rx_pause;
|
|
|
|
sbuf_printf(sb,
|
|
"\nAutonegotiate: %s\n"
|
|
"RX: %s\n"
|
|
"TX: %s\n",
|
|
sys_op->autoneg ? "on" : "off",
|
|
sys_op->rx_pause ? "on" : "off",
|
|
sys_op->tx_pause ? "on" : "off");
|
|
|
|
if (pdata->phy.lp_advertising) {
|
|
int an_rx = 0, an_tx = 0;
|
|
|
|
if (pdata->phy.advertising & pdata->phy.lp_advertising &
|
|
ADVERTISED_Pause) {
|
|
an_tx = 1;
|
|
an_rx = 1;
|
|
} else if (pdata->phy.advertising &
|
|
pdata->phy.lp_advertising & ADVERTISED_Asym_Pause) {
|
|
if (pdata->phy.advertising & ADVERTISED_Pause)
|
|
an_rx = 1;
|
|
else if (pdata->phy.lp_advertising &
|
|
ADVERTISED_Pause)
|
|
an_tx = 1;
|
|
}
|
|
sbuf_printf(sb,
|
|
"\n->\nRX negotiated: %s\n"
|
|
"TX negotiated: %s\n",
|
|
an_rx ? "on" : "off",
|
|
an_tx ? "on" : "off");
|
|
}
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (0);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
parse_generic_sysctl(pdata, buf, sysctl_pauseparam,
|
|
ARRAY_SIZE(sysctl_pauseparam));
|
|
|
|
if (sys_op->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) {
|
|
axgbe_error("autoneg disabled, pause autoneg not available\n");
|
|
return (-EINVAL);
|
|
}
|
|
|
|
pdata->phy.pause_autoneg = sys_op->autoneg;
|
|
pdata->phy.tx_pause = sys_op->tx_pause;
|
|
pdata->phy.rx_pause = sys_op->rx_pause;
|
|
|
|
XGBE_CLR_ADV(&pdata->phy, Pause);
|
|
XGBE_CLR_ADV(&pdata->phy, Asym_Pause);
|
|
|
|
if (sys_op->rx_pause) {
|
|
XGBE_SET_ADV(&pdata->phy, Pause);
|
|
XGBE_SET_ADV(&pdata->phy, Asym_Pause);
|
|
}
|
|
|
|
if (sys_op->tx_pause) {
|
|
/* Equivalent to XOR of Asym_Pause */
|
|
if (XGBE_ADV(&pdata->phy, Asym_Pause))
|
|
XGBE_CLR_ADV(&pdata->phy, Asym_Pause);
|
|
else
|
|
XGBE_SET_ADV(&pdata->phy, Asym_Pause);
|
|
}
|
|
|
|
if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
|
|
rc = pdata->phy_if.phy_config_aneg(pdata);
|
|
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_link_ksettings_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
struct sysctl_op *sys_op = pdata->sys_op;
|
|
struct sysctl_info sysctl_linksettings[] = {
|
|
{ "autoneg", SYSL_BOOL, autoneg, "supported" },
|
|
{ "speed", SYSL_U32, speed, "supported" },
|
|
{ "duplex", SYSL_U8, duplex, "supported" },
|
|
};
|
|
ssize_t buf_size = 512;
|
|
char buf[buf_size], link_modes[16], speed_modes[16];
|
|
struct sbuf *sb;
|
|
uint32_t speed;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
sys_op->autoneg = pdata->phy.autoneg;
|
|
sys_op->speed = pdata->phy.speed;
|
|
sys_op->duplex = pdata->phy.duplex;
|
|
|
|
XGBE_LM_COPY(&pdata->phy, supported, &pdata->phy, supported);
|
|
XGBE_LM_COPY(&pdata->phy, advertising, &pdata->phy, advertising);
|
|
XGBE_LM_COPY(&pdata->phy, lp_advertising, &pdata->phy, lp_advertising);
|
|
|
|
switch (sys_op->speed) {
|
|
case 1:
|
|
strcpy(link_modes, "Unknown");
|
|
strcpy(speed_modes, "Unknown");
|
|
break;
|
|
case 2:
|
|
strcpy(link_modes, "10Gbps/Full");
|
|
strcpy(speed_modes, "10000");
|
|
break;
|
|
case 3:
|
|
strcpy(link_modes, "2.5Gbps/Full");
|
|
strcpy(speed_modes, "2500");
|
|
break;
|
|
case 4:
|
|
strcpy(link_modes, "1Gbps/Full");
|
|
strcpy(speed_modes, "1000");
|
|
break;
|
|
case 5:
|
|
strcpy(link_modes, "100Mbps/Full");
|
|
strcpy(speed_modes, "100");
|
|
break;
|
|
case 6:
|
|
strcpy(link_modes, "10Mbps/Full");
|
|
strcpy(speed_modes, "10");
|
|
break;
|
|
}
|
|
|
|
sbuf_printf(sb,
|
|
"\nlink_modes: %s\n"
|
|
"autonegotiation: %s\n"
|
|
"speed: %sMbps\n",
|
|
link_modes,
|
|
(sys_op->autoneg == AUTONEG_DISABLE) ? "off" : "on",
|
|
speed_modes);
|
|
|
|
switch (sys_op->duplex) {
|
|
case DUPLEX_HALF:
|
|
sbuf_printf(sb, "Duplex: Half\n");
|
|
break;
|
|
case DUPLEX_FULL:
|
|
sbuf_printf(sb, "Duplex: Full\n");
|
|
break;
|
|
default:
|
|
sbuf_printf(sb, "Duplex: Unknown\n");
|
|
break;
|
|
}
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (0);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
parse_generic_sysctl(pdata, buf, sysctl_linksettings,
|
|
ARRAY_SIZE(sysctl_linksettings));
|
|
|
|
speed = sys_op->speed;
|
|
|
|
if ((sys_op->autoneg != AUTONEG_ENABLE) &&
|
|
(sys_op->autoneg != AUTONEG_DISABLE)) {
|
|
axgbe_error("unsupported autoneg %hhu\n",
|
|
(unsigned char)sys_op->autoneg);
|
|
return (-EINVAL);
|
|
}
|
|
|
|
if (sys_op->autoneg == AUTONEG_DISABLE) {
|
|
if (!pdata->phy_if.phy_valid_speed(pdata, speed)) {
|
|
axgbe_error("unsupported speed %u\n", speed);
|
|
return (-EINVAL);
|
|
}
|
|
|
|
if (sys_op->duplex != DUPLEX_FULL) {
|
|
axgbe_error("unsupported duplex %hhu\n",
|
|
(unsigned char)sys_op->duplex);
|
|
return (-EINVAL);
|
|
}
|
|
}
|
|
|
|
pdata->phy.autoneg = sys_op->autoneg;
|
|
pdata->phy.speed = speed;
|
|
pdata->phy.duplex = sys_op->duplex;
|
|
|
|
if (sys_op->autoneg == AUTONEG_ENABLE)
|
|
XGBE_SET_ADV(&pdata->phy, Autoneg);
|
|
else
|
|
XGBE_CLR_ADV(&pdata->phy, Autoneg);
|
|
|
|
if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
|
|
rc = pdata->phy_if.phy_config_aneg(pdata);
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_ringparam_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
struct sysctl_op *sys_op = pdata->sys_op;
|
|
struct sysctl_info sysctl_ringparam[] = {
|
|
{ "rx", SYSL_S32, rx_pending, "supported" },
|
|
{ "rx-mini", SYSL_S32, rx_mini_pending, "supported" },
|
|
{ "rx-jumbo", SYSL_S32, rx_jumbo_pending, "supported" },
|
|
{ "tx", SYSL_S32, tx_pending, "supported" },
|
|
};
|
|
ssize_t buf_size = 512;
|
|
unsigned int rx, tx;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
sys_op->rx_max_pending = XGBE_RX_DESC_CNT_MAX;
|
|
sys_op->tx_max_pending = XGBE_TX_DESC_CNT_MAX;
|
|
sys_op->rx_pending = pdata->rx_desc_count;
|
|
sys_op->tx_pending = pdata->tx_desc_count;
|
|
|
|
sbuf_printf(sb,
|
|
"\nPre-set maximums:\n"
|
|
"RX: %u\n"
|
|
"RX Mini: %u\n"
|
|
"RX Jumbo: %u\n"
|
|
"TX: %u\n",
|
|
sys_op->rx_max_pending,
|
|
sys_op->rx_mini_max_pending,
|
|
sys_op->rx_jumbo_max_pending,
|
|
sys_op->tx_max_pending);
|
|
|
|
sbuf_printf(sb,
|
|
"\nCurrent hardware settings:\n"
|
|
"RX: %u\n"
|
|
"RX Mini: %u\n"
|
|
"RX Jumbo: %u\n"
|
|
"TX: %u\n",
|
|
sys_op->rx_pending,
|
|
sys_op->rx_mini_pending,
|
|
sys_op->rx_jumbo_pending,
|
|
sys_op->tx_pending);
|
|
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (0);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
parse_generic_sysctl(pdata, buf, sysctl_ringparam,
|
|
ARRAY_SIZE(sysctl_ringparam));
|
|
|
|
if (sys_op->rx_mini_pending || sys_op->rx_jumbo_pending) {
|
|
axgbe_error("unsupported ring parameter\n");
|
|
return (-EINVAL);
|
|
}
|
|
|
|
if ((sys_op->rx_pending < XGBE_RX_DESC_CNT_MIN) ||
|
|
(sys_op->rx_pending > XGBE_RX_DESC_CNT_MAX)) {
|
|
axgbe_error("rx ring param must be between %u and %u\n",
|
|
XGBE_RX_DESC_CNT_MIN, XGBE_RX_DESC_CNT_MAX);
|
|
return (-EINVAL);
|
|
}
|
|
|
|
if ((sys_op->tx_pending < XGBE_TX_DESC_CNT_MIN) ||
|
|
(sys_op->tx_pending > XGBE_TX_DESC_CNT_MAX)) {
|
|
axgbe_error("tx ring param must be between %u and %u\n",
|
|
XGBE_TX_DESC_CNT_MIN, XGBE_TX_DESC_CNT_MAX);
|
|
return (-EINVAL);
|
|
}
|
|
|
|
rx = __rounddown_pow_of_two(sys_op->rx_pending);
|
|
if (rx != sys_op->rx_pending)
|
|
axgbe_printf(1, "rx ring param rounded to power of 2: %u\n",
|
|
rx);
|
|
|
|
tx = __rounddown_pow_of_two(sys_op->tx_pending);
|
|
if (tx != sys_op->tx_pending)
|
|
axgbe_printf(1, "tx ring param rounded to power of 2: %u\n",
|
|
tx);
|
|
|
|
if ((rx == pdata->rx_desc_count) &&
|
|
(tx == pdata->tx_desc_count))
|
|
goto out;
|
|
|
|
pdata->rx_desc_count = rx;
|
|
pdata->tx_desc_count = tx;
|
|
|
|
/* TODO - restart dev */
|
|
}
|
|
|
|
out:
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
sysctl_channels_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
struct sysctl_op *sys_op = pdata->sys_op;
|
|
struct sysctl_info sysctl_channels[] = {
|
|
{ "rx", SYSL_S32, rx_count, "supported" },
|
|
{ "tx", SYSL_S32, tx_count, "supported" },
|
|
{ "other", SYSL_S32, other_count, "supported" },
|
|
{ "combined", SYSL_S32, combined_count, "supported" },
|
|
};
|
|
unsigned int rx, tx, combined;
|
|
ssize_t buf_size = 512;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
rx = min(pdata->hw_feat.rx_ch_cnt, pdata->rx_max_channel_count);
|
|
rx = min(rx, pdata->channel_irq_count);
|
|
tx = min(pdata->hw_feat.tx_ch_cnt, pdata->tx_max_channel_count);
|
|
tx = min(tx, pdata->channel_irq_count);
|
|
tx = min(tx, pdata->tx_max_q_count);
|
|
|
|
combined = min(rx, tx);
|
|
|
|
sys_op->max_combined = combined;
|
|
sys_op->max_rx = rx ? rx - 1 : 0;
|
|
sys_op->max_tx = tx ? tx - 1 : 0;
|
|
|
|
/* Get current settings based on device state */
|
|
rx = pdata->rx_ring_count;
|
|
tx = pdata->tx_ring_count;
|
|
|
|
combined = min(rx, tx);
|
|
rx -= combined;
|
|
tx -= combined;
|
|
|
|
sys_op->combined_count = combined;
|
|
sys_op->rx_count = rx;
|
|
sys_op->tx_count = tx;
|
|
|
|
sbuf_printf(sb,
|
|
"\nPre-set maximums:\n"
|
|
"RX: %u\n"
|
|
"TX: %u\n"
|
|
"Other: %u\n"
|
|
"Combined: %u\n",
|
|
sys_op->max_rx, sys_op->max_tx,
|
|
sys_op->max_other,
|
|
sys_op->max_combined);
|
|
|
|
sbuf_printf(sb,
|
|
"\nCurrent hardware settings:\n"
|
|
"RX: %u\n"
|
|
"TX: %u\n"
|
|
"Other: %u\n"
|
|
"Combined: %u\n",
|
|
sys_op->rx_count, sys_op->tx_count,
|
|
sys_op->other_count,
|
|
sys_op->combined_count);
|
|
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (0);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
parse_generic_sysctl(pdata, buf, sysctl_channels,
|
|
ARRAY_SIZE(sysctl_channels));
|
|
|
|
axgbe_error( "channel inputs: combined=%u, rx-only=%u,"
|
|
" tx-only=%u\n", sys_op->combined_count,
|
|
sys_op->rx_count, sys_op->tx_count);
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
static int
|
|
sysctl_mac_stats_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
int i;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
pdata->hw_if.read_mmc_stats(pdata);
|
|
for (i = 0; i < XGBE_STATS_COUNT; i++) {
|
|
sbuf_printf(sb, "\n %s: %lu",
|
|
xgbe_gstring_stats[i].stat_string,
|
|
*(uint64_t *)((uint8_t *)pdata + xgbe_gstring_stats[i].stat_offset));
|
|
}
|
|
for (i = 0; i < pdata->tx_ring_count; i++) {
|
|
sbuf_printf(sb,
|
|
"\n txq_packets[%d]: %lu"
|
|
"\n txq_bytes[%d]: %lu",
|
|
i, pdata->ext_stats.txq_packets[i],
|
|
i, pdata->ext_stats.txq_bytes[i]);
|
|
}
|
|
for (i = 0; i < pdata->rx_ring_count; i++) {
|
|
sbuf_printf(sb,
|
|
"\n rxq_packets[%d]: %lu"
|
|
"\n rxq_bytes[%d]: %lu",
|
|
i, pdata->ext_stats.rxq_packets[i],
|
|
i, pdata->ext_stats.rxq_bytes[i]);
|
|
}
|
|
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
return (-EINVAL);
|
|
}
|
|
|
|
static int
|
|
sysctl_xgmac_reg_value_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
unsigned int value;
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
value = XGMAC_IOREAD(pdata, pdata->sysctl_xgmac_reg);
|
|
axgbe_printf(2, "READ: %s: value: 0x%x\n", __func__, value);
|
|
sbuf_printf(sb, "\nXGMAC reg_value: 0x%x\n", value);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%x", &value);
|
|
axgbe_printf(2, "WRITE: %s: value: 0x%x\n", __func__, value);
|
|
XGMAC_IOWRITE(pdata, pdata->sysctl_xgmac_reg, value);
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_xpcs_mmd_reg_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
unsigned int reg;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
axgbe_printf(2, "READ: %s: xpcs_mmd: 0x%x\n", __func__,
|
|
pdata->sysctl_xpcs_mmd);
|
|
sbuf_printf(sb, "\nXPCS mmd_reg: 0x%x\n",
|
|
pdata->sysctl_xpcs_mmd);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%x", ®);
|
|
axgbe_printf(2, "WRITE: %s: mmd_reg: 0x%x\n", __func__, reg);
|
|
pdata->sysctl_xpcs_mmd = reg;
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_xpcs_reg_addr_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
unsigned int reg;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
axgbe_printf(2, "READ: %s: sysctl_xpcs_reg: 0x%x\n", __func__,
|
|
pdata->sysctl_xpcs_reg);
|
|
sbuf_printf(sb, "\nXPCS reg_addr: 0x%x\n",
|
|
pdata->sysctl_xpcs_reg);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%x", ®);
|
|
axgbe_printf(2, "WRITE: %s: reg: 0x%x\n", __func__, reg);
|
|
pdata->sysctl_xpcs_reg = reg;
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_xpcs_reg_value_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
unsigned int value;
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
value = XMDIO_READ(pdata, pdata->sysctl_xpcs_mmd,
|
|
pdata->sysctl_xpcs_reg);
|
|
axgbe_printf(2, "READ: %s: value: 0x%x\n", __func__, value);
|
|
sbuf_printf(sb, "\nXPCS reg_value: 0x%x\n", value);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%x", &value);
|
|
axgbe_printf(2, "WRITE: %s: value: 0x%x\n", __func__, value);
|
|
XMDIO_WRITE(pdata, pdata->sysctl_xpcs_mmd,
|
|
pdata->sysctl_xpcs_reg, value);
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_xprop_reg_addr_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
unsigned int reg;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
axgbe_printf(2, "READ: %s: sysctl_xprop_reg: 0x%x\n", __func__,
|
|
pdata->sysctl_xprop_reg);
|
|
sbuf_printf(sb, "\nXPROP reg_addr: 0x%x\n",
|
|
pdata->sysctl_xprop_reg);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%x", ®);
|
|
axgbe_printf(2, "WRITE: %s: reg: 0x%x\n", __func__, reg);
|
|
pdata->sysctl_xprop_reg = reg;
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_xprop_reg_value_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
unsigned int value;
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
value = XP_IOREAD(pdata, pdata->sysctl_xprop_reg);
|
|
axgbe_printf(2, "READ: %s: value: 0x%x\n", __func__, value);
|
|
sbuf_printf(sb, "\nXPROP reg_value: 0x%x\n", value);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%x", &value);
|
|
axgbe_printf(2, "WRITE: %s: value: 0x%x\n", __func__, value);
|
|
XP_IOWRITE(pdata, pdata->sysctl_xprop_reg, value);
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_xi2c_reg_addr_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
unsigned int reg;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
axgbe_printf(2, "READ: %s: sysctl_xi2c_reg: 0x%x\n", __func__,
|
|
pdata->sysctl_xi2c_reg);
|
|
sbuf_printf(sb, "\nXI2C reg_addr: 0x%x\n",
|
|
pdata->sysctl_xi2c_reg);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%x", ®);
|
|
axgbe_printf(2, "WRITE: %s: reg: 0x%x\n", __func__, reg);
|
|
pdata->sysctl_xi2c_reg = reg;
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_xi2c_reg_value_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
unsigned int value;
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
value = XI2C_IOREAD(pdata, pdata->sysctl_xi2c_reg);
|
|
axgbe_printf(2, "READ: %s: value: 0x%x\n", __func__, value);
|
|
sbuf_printf(sb, "\nXI2C reg_value: 0x%x\n", value);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%x", &value);
|
|
axgbe_printf(2, "WRITE: %s: value: 0x%x\n", __func__, value);
|
|
XI2C_IOWRITE(pdata, pdata->sysctl_xi2c_reg, value);
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_an_cdr_wr_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
unsigned int an_cdr_wr = 0;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
axgbe_printf(2, "READ: %s: an_cdr_wr: %d\n", __func__,
|
|
pdata->sysctl_an_cdr_workaround);
|
|
sbuf_printf(sb, "%d\n", pdata->sysctl_an_cdr_workaround);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%u", &an_cdr_wr);
|
|
axgbe_printf(2, "WRITE: %s: an_cdr_wr: 0x%d\n", __func__,
|
|
an_cdr_wr);
|
|
|
|
if (an_cdr_wr)
|
|
pdata->sysctl_an_cdr_workaround = 1;
|
|
else
|
|
pdata->sysctl_an_cdr_workaround = 0;
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
static int
|
|
sysctl_an_cdr_track_early_handler(SYSCTL_HANDLER_ARGS)
|
|
{
|
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
|
|
unsigned int an_cdr_track_early = 0;
|
|
ssize_t buf_size = 64;
|
|
char buf[buf_size];
|
|
struct sbuf *sb;
|
|
int rc = 0;
|
|
|
|
if (req->newptr == NULL) {
|
|
sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
|
|
if (sb == NULL) {
|
|
rc = sb->s_error;
|
|
return (rc);
|
|
}
|
|
|
|
axgbe_printf(2, "READ: %s: an_cdr_track_early %d\n", __func__,
|
|
pdata->sysctl_an_cdr_track_early);
|
|
sbuf_printf(sb, "%d\n", pdata->sysctl_an_cdr_track_early);
|
|
rc = sbuf_finish(sb);
|
|
sbuf_delete(sb);
|
|
return (rc);
|
|
}
|
|
|
|
rc = get_ubuf(req, buf);
|
|
if (rc == 0) {
|
|
sscanf(buf, "%u", &an_cdr_track_early);
|
|
axgbe_printf(2, "WRITE: %s: an_cdr_track_early: %d\n", __func__,
|
|
an_cdr_track_early);
|
|
|
|
if (an_cdr_track_early)
|
|
pdata->sysctl_an_cdr_track_early = 1;
|
|
else
|
|
pdata->sysctl_an_cdr_track_early = 0;
|
|
}
|
|
|
|
axgbe_printf(2, "%s: rc= %d\n", __func__, rc);
|
|
return (rc);
|
|
}
|
|
|
|
void
|
|
axgbe_sysctl_exit(struct xgbe_prv_data *pdata)
|
|
{
|
|
|
|
if (pdata->sys_op)
|
|
free(pdata->sys_op, M_AXGBE);
|
|
}
|
|
|
|
void
|
|
axgbe_sysctl_init(struct xgbe_prv_data *pdata)
|
|
{
|
|
struct sysctl_ctx_list *clist;
|
|
struct sysctl_oid_list *top;
|
|
struct sysctl_oid *parent;
|
|
struct sysctl_op *sys_op;
|
|
|
|
sys_op = malloc(sizeof(*sys_op), M_AXGBE, M_WAITOK | M_ZERO);
|
|
pdata->sys_op = sys_op;
|
|
|
|
clist = device_get_sysctl_ctx(pdata->dev);
|
|
parent = device_get_sysctl_tree(pdata->dev);
|
|
top = SYSCTL_CHILDREN(parent);
|
|
|
|
/* Set defaults */
|
|
pdata->sysctl_xgmac_reg = 0;
|
|
pdata->sysctl_xpcs_mmd = 1;
|
|
pdata->sysctl_xpcs_reg = 0;
|
|
|
|
SYSCTL_ADD_UINT(clist, top, OID_AUTO, "axgbe_debug_level", CTLFLAG_RWTUN,
|
|
&pdata->debug_level, 0, "axgbe log level -- higher is verbose");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xgmac_register",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_xgmac_reg_addr_handler, "IU",
|
|
"xgmac register addr");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xgmac_register_value",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_xgmac_reg_value_handler, "IU",
|
|
"xgmac register value");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xpcs_mmd",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_xpcs_mmd_reg_handler, "IU", "xpcs mmd register");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xpcs_register",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_xpcs_reg_addr_handler, "IU", "xpcs register");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xpcs_register_value",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_xpcs_reg_value_handler, "IU",
|
|
"xpcs register value");
|
|
|
|
if (pdata->xpcs_res) {
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xprop_register",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_xprop_reg_addr_handler,
|
|
"IU", "xprop register");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xprop_register_value",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_xprop_reg_value_handler,
|
|
"IU", "xprop register value");
|
|
}
|
|
|
|
if (pdata->xpcs_res) {
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xi2c_register",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_xi2c_reg_addr_handler,
|
|
"IU", "xi2c register");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xi2c_register_value",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_xi2c_reg_value_handler,
|
|
"IU", "xi2c register value");
|
|
}
|
|
|
|
if (pdata->vdata->an_cdr_workaround) {
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "an_cdr_workaround",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_an_cdr_wr_handler, "IU",
|
|
"an cdr workaround");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "an_cdr_track_early",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_an_cdr_track_early_handler, "IU",
|
|
"an cdr track early");
|
|
}
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "drv_info",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_get_drv_info_handler, "IU",
|
|
"xgbe drv info");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "link_info",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_get_link_info_handler, "IU",
|
|
"xgbe link info");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "coalesce_info",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_coalesce_handler, "IU",
|
|
"xgbe coalesce info");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "pauseparam_info",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_pauseparam_handler, "IU",
|
|
"xgbe pauseparam info");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "link_ksettings_info",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_link_ksettings_handler, "IU",
|
|
"xgbe link_ksettings info");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "ringparam_info",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_ringparam_handler, "IU",
|
|
"xgbe ringparam info");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "channels_info",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_channels_handler, "IU",
|
|
"xgbe channels info");
|
|
|
|
SYSCTL_ADD_PROC(clist, top, OID_AUTO, "mac_stats",
|
|
CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
|
|
pdata, 0, sysctl_mac_stats_handler, "IU",
|
|
"xgbe mac stats");
|
|
}
|