// SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2022 - 2023 Mucse Corporation. */ #include #include #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); } } } }