2026-01-29 22:25:33 +08:00

358 lines
8.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2022 - 2023 Mucse Corporation. */
#include <linux/types.h>
#include <linux/module.h>
#include "rnp.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 (2 = MSI-X), default 2");
#define RNP_INT_LEGACY 0
#define RNP_INT_MSI 1
#define RNP_INT_MSIX 2
#ifdef 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)");
/* 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
struct rnp_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 rnp_opt_list {
int i;
char *str;
} *p;
} l;
} arg;
};
static int rnp_validate_option(struct net_device *netdev,
unsigned int *value, struct rnp_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 rnp_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:
BUG();
}
netdev_info(netdev, "Invalid %s specified (%d), %s\n", opt->name,
*value, opt->err);
*value = opt->def;
return -1;
}
/**
* rnp_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 rnp_check_options(struct rnp_adapter *adapter)
{
//unsigned int mdd;
int bd = adapter->bd_number;
u32 *aflags = &adapter->flags;
//struct rnp_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 rnp_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 } }
};
if (num_IntMode > bd) {
int_mode = IntMode[bd];
if (int_mode == OPTION_UNSET)
int_mode = RNP_INT_MSIX;
rnp_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;
}
} else {
/* default settings */
// msix -> msi -> Legacy
if (*aflags & RNP_FLAG_MSIX_CAPABLE)
adapter->irq_mode = irq_mode_msix;
else if (*aflags & RNP_FLAG_MSI_CAPABLE)
adapter->irq_mode = irq_mode_msi;
else
adapter->irq_mode = irq_mode_legency;
}
}
#ifdef CONFIG_PCI_IOV
{ /* Single Root I/O Virtualization (SR-IOV) */
struct rnp_hw *hw = &adapter->hw;
static struct rnp_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 (num_max_vfs > bd) {
unsigned int vfs = max_vfs[bd];
if (rnp_validate_option(adapter->netdev, &vfs,
&opt)) {
vfs = 0;
DPRINTK(PROBE, INFO,
"max_vfs out of range");
DPRINTK(PROBE, INFO,
"Disabling SR-IOV.\n");
}
adapter->num_vfs = vfs;
if (vfs)
*aflags |= RNP_FLAG_SRIOV_ENABLED;
else
*aflags &= ~RNP_FLAG_SRIOV_ENABLED;
} else {
if (opt.def == OPTION_DISABLED) {
adapter->num_vfs = 0;
*aflags &= ~RNP_FLAG_SRIOV_ENABLED;
} else {
adapter->num_vfs = opt.def;
*aflags |= RNP_FLAG_SRIOV_ENABLED;
}
}
}
{ /* Interrupt Mode */
unsigned int sriov_mode;
static struct rnp_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 } }
};
if (num_SRIOV_Mode > bd) {
sriov_mode = SRIOV_Mode[bd];
if (sriov_mode == OPTION_UNSET)
sriov_mode = RNP_SRIOV_MAC_MODE;
rnp_validate_option(adapter->netdev, &sriov_mode,
&opt);
if (sriov_mode == RNP_SRIOV_VLAN_MODE)
adapter->priv_flags |=
RNP_PRIV_FLAG_SRIOV_VLAN_MODE;
} else {
/* default settings */
// msix -> msi -> Legacy
adapter->priv_flags &=
(~RNP_PRIV_FLAG_SRIOV_VLAN_MODE);
}
}
#endif // CONFIG_PCI_IOV
{ /* max msix count setup */
int pf_msix_counts;
struct rnp_hw *hw = &adapter->hw;
static struct rnp_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;
if (num_pf_msix_counts_set > bd) {
pf_msix_counts = pf_msix_counts_set[bd];
if (pf_msix_counts == OPTION_DISABLED)
pf_msix_counts = 0;
rnp_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);
}
}
}
}