383 lines
9.7 KiB
C
383 lines
9.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright(c) 2022 - 2024 Mucse Corporation. */
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/module.h>
|
|
|
|
#include "rnpgbe.h"
|
|
|
|
/* This is the only thing that needs to be changed to adjust the
|
|
* maximum number of ports that the driver can manage.
|
|
*/
|
|
|
|
#define RNP_MAX_NIC 32
|
|
|
|
#define OPTION_UNSET -1
|
|
#define OPTION_DISABLED 0
|
|
#define OPTION_ENABLED 1
|
|
|
|
#define STRINGIFY(foo) #foo /* magic for getting defines into strings */
|
|
#define XSTRINGIFY(bar) STRINGIFY(bar)
|
|
|
|
/* All parameters are treated the same, as an integer array of values.
|
|
* This macro just reduces the need to repeat the same declaration code
|
|
* over and over (plus this helps to avoid typo bugs).
|
|
*/
|
|
|
|
#define RNP_PARAM_INIT \
|
|
{ \
|
|
[0 ... RNP_MAX_NIC] = OPTION_UNSET \
|
|
}
|
|
#define RNP_PARAM(X, desc) \
|
|
static int X[RNP_MAX_NIC + 1] = RNP_PARAM_INIT; \
|
|
static unsigned int num_##X; \
|
|
module_param_array_named(X, X, int, &num_##X, 0); \
|
|
MODULE_PARM_DESC(X, desc);
|
|
/* IntMode (Interrupt Mode)
|
|
*
|
|
* Valid Range: 0-2
|
|
* - 0 - Legacy Interrupt
|
|
* - 1 - MSI Interrupt
|
|
* - 2 - MSI-X Interrupt(s)
|
|
*
|
|
* Default Value: 2
|
|
*/
|
|
RNP_PARAM(IntMode, "Change Interrupt Mode (0=Legacy, 1=MSI, 2=MSI-X), default 2");
|
|
#define RNP_INT_LEGACY 0
|
|
#define RNP_INT_MSI 1
|
|
#define RNP_INT_MSIX 2
|
|
|
|
#if IS_ENABLED(CONFIG_PCI_IOV)
|
|
/* max_vfs - SR I/O Virtualization
|
|
*
|
|
* Valid Range: 0-63 for n10
|
|
* Valid Range: 0-7 for n400/n10
|
|
* - 0 Disables SR-IOV
|
|
* - 1-x - enables SR-IOV and sets the number of VFs enabled
|
|
*
|
|
* Default Value: 0
|
|
*/
|
|
|
|
RNP_PARAM(max_vfs, "Number of Virtual Functions: 0 = disable (default), "
|
|
"1-" XSTRINGIFY(MAX_SRIOV_VFS) " = enable this many VFs");
|
|
|
|
/* SRIOV_Mode (SRIOV Mode)
|
|
*
|
|
* Valid Range: 0-1
|
|
* - 0 - Legacy Interrupt
|
|
* - 1 - MSI Interrupt
|
|
* - 2 - MSI-X Interrupt(s)
|
|
*
|
|
* Default Value: 0
|
|
*/
|
|
RNP_PARAM(SRIOV_Mode, "Change SRIOV Mode (0=MAC_MODE, 1=VLAN_MODE), default 0");
|
|
#define RNP_SRIOV_MAC_MODE 0
|
|
#define RNP_SRIOV_VLAN_MODE 1
|
|
#endif
|
|
|
|
/* pf_msix_counts_set - Limit max msix counts
|
|
*
|
|
* Valid Range: 2-63 for n10
|
|
* Valid Range: 2-7 for n400/n10
|
|
*
|
|
* Default Value: 0 (un-limit)
|
|
*/
|
|
RNP_PARAM(pf_msix_counts_set, "Number of Max MSIX Count: (default un-limit)");
|
|
#define RNP_INT_MIN 2
|
|
#define RNP_INT_MAX 64
|
|
|
|
/* eee_timer - LPI tx expiration time in msec
|
|
*
|
|
* Valid Range: 100-10000
|
|
*
|
|
* Default Value: 4000
|
|
*/
|
|
RNP_PARAM(eee_timer, "LPI tx expiration time in msec: (default 1000)");
|
|
#define RNP_EEE_MIN (100)
|
|
#define RNP_EEE_DEFAULT (4000)
|
|
#define RNP_EEE_MAX (10000)
|
|
|
|
/* priv_rx_skip - priv header len
|
|
*
|
|
* Valid Range: [0, 16]
|
|
*
|
|
* Default Value: -
|
|
*/
|
|
RNP_PARAM(rx_skip, "rx_skip header in DW: (default 0)");
|
|
#define RNP_RX_SKIP_MIN (0)
|
|
#define RNP_RX_SKIP_DEFAULT (0)
|
|
#define RNP_RX_SKIP_MAX (16)
|
|
|
|
struct rnpgbe_option {
|
|
enum { enable_option, range_option, list_option } type;
|
|
const char *name;
|
|
const char *err;
|
|
const char *msg;
|
|
int def;
|
|
union {
|
|
struct { /* range_option info */
|
|
int min;
|
|
int max;
|
|
} r;
|
|
struct { /* list_option info */
|
|
int nr;
|
|
const struct rnpgbe_opt_list {
|
|
int i;
|
|
char *str;
|
|
} *p;
|
|
} l;
|
|
} arg;
|
|
};
|
|
|
|
static int rnpgbe_validate_option(struct net_device *netdev,
|
|
unsigned int *value,
|
|
struct rnpgbe_option *opt)
|
|
{
|
|
if (*value == OPTION_UNSET) {
|
|
netdev_info(netdev, "Invalid %s specified (%d), %s\n",
|
|
opt->name, *value, opt->err);
|
|
*value = opt->def;
|
|
return 0;
|
|
}
|
|
|
|
switch (opt->type) {
|
|
case enable_option:
|
|
switch (*value) {
|
|
case OPTION_ENABLED:
|
|
netdev_info(netdev, "%s Enabled\n", opt->name);
|
|
return 0;
|
|
case OPTION_DISABLED:
|
|
netdev_info(netdev, "%s Disabled\n", opt->name);
|
|
return 0;
|
|
}
|
|
break;
|
|
case range_option:
|
|
if ((*value >= opt->arg.r.min && *value <= opt->arg.r.max) ||
|
|
*value == opt->def) {
|
|
if (opt->msg)
|
|
netdev_info(netdev, "%s set to %d, %s\n",
|
|
opt->name, *value, opt->msg);
|
|
else
|
|
netdev_info(netdev, "%s set to %d\n", opt->name,
|
|
*value);
|
|
return 0;
|
|
}
|
|
break;
|
|
case list_option: {
|
|
int i;
|
|
|
|
for (i = 0; i < opt->arg.l.nr; i++) {
|
|
const struct rnpgbe_opt_list *ent = &opt->arg.l.p[i];
|
|
|
|
if (*value == ent->i) {
|
|
if (ent->str[0] != '\0')
|
|
netdev_info(netdev, "%s\n", ent->str);
|
|
return 0;
|
|
}
|
|
}
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
netdev_info(netdev, "Invalid %s specified (%d), %s\n", opt->name,
|
|
*value, opt->err);
|
|
*value = opt->def;
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* rnpgbe_check_options - Range Checking for Command Line Parameters
|
|
* @adapter: board private structure
|
|
*
|
|
* This routine checks all command line parameters for valid user
|
|
* input. If an invalid value is given, or if no user specified
|
|
* value exists, a default value is used. The final value is stored
|
|
* in a variable in the adapter structure.
|
|
**/
|
|
void rnpgbe_check_options(struct rnpgbe_adapter *adapter)
|
|
{
|
|
//unsigned int mdd;
|
|
int bd = adapter->bd_number;
|
|
u32 *aflags = &adapter->flags;
|
|
//struct rnpgbe_ring_feature *feature = adapter->ring_feature;
|
|
|
|
if (bd >= RNP_MAX_NIC) {
|
|
netdev_notice(adapter->netdev,
|
|
"Warning: no configuration for board #%d\n", bd);
|
|
netdev_notice(adapter->netdev,
|
|
"Using defaults for all values\n");
|
|
}
|
|
|
|
// try to setup new irq mode
|
|
{ /* Interrupt Mode */
|
|
unsigned int int_mode;
|
|
static struct rnpgbe_option opt = {
|
|
.type = range_option,
|
|
.name = "Interrupt Mode",
|
|
.err = "using default of " __MODULE_STRING(RNP_INT_MSIX),
|
|
.def = RNP_INT_MSIX,
|
|
.arg = { .r = { .min = RNP_INT_LEGACY,
|
|
.max = RNP_INT_MSIX } }
|
|
};
|
|
|
|
int_mode = IntMode[bd];
|
|
if (int_mode == OPTION_UNSET)
|
|
int_mode = RNP_INT_MSIX;
|
|
rnpgbe_validate_option(adapter->netdev, &int_mode,
|
|
&opt);
|
|
switch (int_mode) {
|
|
case RNP_INT_MSIX:
|
|
if (!(*aflags & RNP_FLAG_MSIX_CAPABLE)) {
|
|
netdev_info(adapter->netdev,
|
|
"Ignoring MSI-X setting; "
|
|
"support unavailable\n");
|
|
} else {
|
|
adapter->irq_mode = irq_mode_msix;
|
|
}
|
|
break;
|
|
case RNP_INT_MSI:
|
|
if (!(*aflags & RNP_FLAG_MSI_CAPABLE)) {
|
|
netdev_info(adapter->netdev,
|
|
"Ignoring MSI setting; "
|
|
"support unavailable\n");
|
|
} else {
|
|
adapter->irq_mode = irq_mode_msi;
|
|
}
|
|
break;
|
|
case RNP_INT_LEGACY:
|
|
if (!(*aflags & RNP_FLAG_LEGACY_CAPABLE)) {
|
|
netdev_info(adapter->netdev,
|
|
"Ignoring MSI setting; "
|
|
"support unavailable\n");
|
|
} else {
|
|
adapter->irq_mode = irq_mode_legency;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_PCI_IOV)
|
|
{ /* Single Root I/O Virtualization (SR-IOV) */
|
|
struct rnpgbe_hw *hw = &adapter->hw;
|
|
unsigned int vfs = max_vfs[bd];
|
|
static struct rnpgbe_option opt = {
|
|
.type = range_option,
|
|
.name = "I/O Virtualization (IOV)",
|
|
.err = "defaulting to Disabled",
|
|
.def = OPTION_DISABLED,
|
|
.arg = { .r = { .min = OPTION_DISABLED,
|
|
.max = OPTION_DISABLED } }
|
|
};
|
|
|
|
opt.arg.r.max = hw->max_vfs;
|
|
|
|
if (rnpgbe_validate_option(adapter->netdev, &vfs,
|
|
&opt)) {
|
|
vfs = 0;
|
|
DPRINTK(PROBE, INFO,
|
|
"max_vfs out of range Disabling SR-IOV.\n");
|
|
}
|
|
|
|
adapter->num_vfs = vfs;
|
|
|
|
if (vfs)
|
|
*aflags |= RNP_FLAG_SRIOV_ENABLED;
|
|
else
|
|
*aflags &= ~RNP_FLAG_SRIOV_ENABLED;
|
|
}
|
|
|
|
{ /* Interrupt Mode */
|
|
unsigned int sriov_mode;
|
|
static struct rnpgbe_option opt = {
|
|
.type = range_option,
|
|
.name = "SRIOV Mode",
|
|
.err = "using default of " __MODULE_STRING(RNP_SRIOV_MAC_MODE),
|
|
.def = RNP_SRIOV_MAC_MODE,
|
|
.arg = { .r = { .min = RNP_SRIOV_MAC_MODE,
|
|
.max = RNP_SRIOV_VLAN_MODE } }
|
|
};
|
|
|
|
sriov_mode = SRIOV_Mode[bd];
|
|
if (sriov_mode == OPTION_UNSET)
|
|
sriov_mode = RNP_SRIOV_MAC_MODE;
|
|
rnpgbe_validate_option(adapter->netdev, &sriov_mode,
|
|
&opt);
|
|
|
|
if (sriov_mode == RNP_SRIOV_VLAN_MODE)
|
|
adapter->priv_flags |=
|
|
RNP_PRIV_FLAG_SRIOV_VLAN_MODE;
|
|
}
|
|
#endif /* CONFIG_PCI_IOV */
|
|
|
|
{ /* max msix count setup */
|
|
unsigned int pf_msix_counts;
|
|
struct rnpgbe_hw *hw = &adapter->hw;
|
|
static struct rnpgbe_option opt = {
|
|
.type = range_option,
|
|
.name = "Limit Msix Count",
|
|
.err = "using default of Un-limit",
|
|
.def = OPTION_DISABLED,
|
|
.arg = { .r = { .min = RNP_INT_MIN,
|
|
.max = RNP_INT_MIN } }
|
|
};
|
|
|
|
opt.arg.r.max = hw->max_msix_vectors;
|
|
pf_msix_counts = pf_msix_counts_set[bd];
|
|
if (pf_msix_counts == OPTION_DISABLED)
|
|
pf_msix_counts = 0;
|
|
rnpgbe_validate_option(adapter->netdev, &pf_msix_counts,
|
|
&opt);
|
|
|
|
if (pf_msix_counts) {
|
|
if (hw->ops.update_msix_count)
|
|
hw->ops.update_msix_count(hw, pf_msix_counts);
|
|
}
|
|
}
|
|
|
|
{ /* LPI tx expiration time in msec */
|
|
unsigned int eee_timer_delay;
|
|
//struct rnpgbe_hw *hw = &adapter->hw;
|
|
static struct rnpgbe_option opt = {
|
|
.type = range_option,
|
|
.name = "eee timer exp",
|
|
.err = "using default of 1000",
|
|
.def = OPTION_DISABLED,
|
|
.arg = { .r = { .min = RNP_EEE_MIN,
|
|
.max = RNP_EEE_MAX } }
|
|
};
|
|
|
|
eee_timer_delay = eee_timer[bd];
|
|
if (eee_timer_delay == OPTION_DISABLED)
|
|
eee_timer_delay = RNP_EEE_DEFAULT;
|
|
rnpgbe_validate_option(adapter->netdev,
|
|
&eee_timer_delay, &opt);
|
|
adapter->eee_timer = eee_timer_delay;
|
|
}
|
|
|
|
{ /* rx_skip in DW */
|
|
unsigned int rx_skip_priv;
|
|
//struct rnpgbe_hw *hw = &adapter->hw;
|
|
static struct rnpgbe_option opt = {
|
|
.type = range_option,
|
|
.name = "rx_skip in DW",
|
|
.err = "using default of 0",
|
|
.def = OPTION_DISABLED,
|
|
.arg = { .r = { .min = RNP_RX_SKIP_MIN,
|
|
.max = RNP_RX_SKIP_MAX } }
|
|
};
|
|
|
|
rx_skip_priv = rx_skip[bd];
|
|
if (rx_skip_priv == OPTION_DISABLED)
|
|
rx_skip_priv = RNP_RX_SKIP_DEFAULT;
|
|
rnpgbe_validate_option(adapter->netdev, &rx_skip_priv,
|
|
&opt);
|
|
if (rx_skip_priv) {
|
|
adapter->priv_skip_count = rx_skip_priv - 1;
|
|
adapter->priv_flags |= RNP_PRIV_FLAG_RX_SKIP_EN;
|
|
} else {
|
|
adapter->priv_flags &= ~RNP_PRIV_FLAG_RX_SKIP_EN;
|
|
}
|
|
}
|
|
}
|