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