Replace the use of module parameters with data read from an ASCII parameter
file found through the request_firmware() framework.

The parameter file is an ASCII data file with lines in the form of
     <label>  <option>=<val>[,<option>=<val>...]
where the <label> specifies the driver name and/or a specific configuration
line to use and the following options define that configuration.  Blank
lines are ignored, as are line comments that start with '#'.

The parameter file is tagged as MODULE_FIRMWARE to be sure it gets
included when pulling the driver into an initrd image.  The possible
config options are tagged using MODULE_INFO to be sure there is still
some discoverability in configuration options.

Signed-off-by: Shannon Nelson <shannon.nel...@intel.com>
Cc: Jeff Kirsher <jeffrey.t.kirs...@intel.com>
Cc: David Woodhouse <dw...@infradead.org>
---

 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |  229 ++++++++++++++++++++++---
 1 files changed, 203 insertions(+), 26 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 20d6764..1670fc7 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -47,13 +47,16 @@
 #include <linux/if_bridge.h>
 #include <linux/prefetch.h>
 #include <scsi/fc/fc_fcoe.h>
+#include <linux/firmware.h>
+#include <linux/parser.h>
 
 #include "ixgbe.h"
 #include "ixgbe_common.h"
 #include "ixgbe_dcb_82599.h"
 #include "ixgbe_sriov.h"
 
-char ixgbe_driver_name[] = "ixgbe";
+#define IXGBE_DRIVER_NAME "ixgbe"
+char ixgbe_driver_name[] = IXGBE_DRIVER_NAME;
 static const char ixgbe_driver_string[] =
                              "Intel(R) 10 Gigabit PCI Express Network Driver";
 #ifdef IXGBE_FCOE
@@ -127,28 +130,202 @@ static struct notifier_block dca_notifier = {
 };
 #endif
 
-#ifdef CONFIG_PCI_IOV
-static unsigned int max_vfs;
-module_param(max_vfs, uint, 0);
-MODULE_PARM_DESC(max_vfs,
-                "Maximum number of virtual functions to allocate per physical 
function - default is zero and maximum value is 63");
-#endif /* CONFIG_PCI_IOV */
-
-static unsigned int allow_unsupported_sfp;
-module_param(allow_unsupported_sfp, uint, 0);
-MODULE_PARM_DESC(allow_unsupported_sfp,
-                "Allow unsupported and untested SFP+ modules on 82599-based 
adapters");
-
 #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
-static int debug = -1;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
 MODULE_AUTHOR("Intel Corporation, <linux.n...@intel.com>");
 MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+/*
+ * Firmware parameter processing
+ *
+ * This requests a parameter configuration file through the kernel
+ * firmware management service.  The parameter file is an ASCII data
+ * file with lines in the form of
+ *      <label>  <option>=<val>[,<option>=<val>...]
+ * where the <label> specifies a specific configuration to use
+ * and the following options define that configuration.  Blank lines
+ * are ignored, as are line comments that start with '#'.
+ *
+ * For this driver, we use the driver name as the label for the basic
+ * configuration, then use the port MAC address for port specific
+ * override configuration.
+ */
+#define IXGBE_FIRMWARE_FILE        IXGBE_DRIVER_NAME ".conf"
+MODULE_FIRMWARE(IXGBE_FIRMWARE_FILE);
+
+#define xstr(s) str(s)
+#define str(s)  #s
+
+enum {
+       Opt_debug,
+       Opt_allow_unsupported_sfp,
+#ifdef CONFIG_PCI_IOV
+       Opt_max_vfs,
+#endif
+};
+
+static const match_table_t tokens = {
+       { Opt_debug, "debug=%u" },
+       { Opt_allow_unsupported_sfp, "allow_unsupported_sfp" },
+#ifdef CONFIG_PCI_IOV
+       { Opt_max_vfs, "max_vfs=%u" },
+#endif
+
+       /* terminator token */
+       { 0, NULL },
+};
+MODULE_INFO(fw_option, "debug=N : Debug level (0=none,...,16=all)");
+MODULE_INFO(fw_option, "allow_unsupported_sfp : Allow unsupported and untested 
SFP+ modules on 82599-based adapters");
+MODULE_INFO(fw_option,
+           "max_vfs=N : Maximum number of virtual functions per physical 
function (default=0) - 0 <= N < "
+           xstr(IXGBE_MAX_VF_FUNCTIONS));
+
+/**
+ * ixgbe_parse_option_line - find ixgbe options
+ * @adapter: pointer to ixgbe_adapter
+ * @config_line: line of option information
+ * @line_len: length of the config line
+ *
+ **/
+static void ixgbe_parse_option_line(struct ixgbe_adapter *adapter,
+                                   char *config_line, int line_len)
+{
+       char *p;
+       char *next_option = config_line;
+       substring_t args[MAX_OPT_ARGS];
+       int value;
+
+       if (!config_line)
+               return;
+
+       while ((p = strsep(&next_option, ", \t\n")) != NULL) {
+               int token;
+
+               if (((p - config_line) >= line_len) || *p == '\0' || *p == '#')
+                       break;
+
+               /*
+                * Initialize args struct so we know whether arg was
+                * found; some options take optional arguments.
+                */
+               args[0].to = args[0].from = NULL;
+               token = match_token(p, tokens, args);
+               switch (token) {
+
+               case Opt_debug:
+                       if (match_int(args, &value))
+                               goto parse_error;
+                       adapter->msg_enable = netif_msg_init(value,
+                                                           DEFAULT_MSG_ENABLE);
+                       break;
+
+               case Opt_allow_unsupported_sfp:
+                       adapter->hw.allow_unsupported_sfp = true;
+                       break;
+
+#ifdef CONFIG_PCI_IOV
+               case Opt_max_vfs:
+                       if (match_int(args, &value))
+                               goto parse_error;
+
+                       if (adapter->hw.mac.type != ixgbe_mac_82598EB) {
+                               if (value < IXGBE_MAX_VF_FUNCTIONS)
+                                       adapter->num_vfs = value;
+                               else
+                                       goto parse_error;
+                       }
+                       break;
+
+#endif
+               default:
+                       goto parse_error;
+                       break;
+               }
+       }
+
+       return;
+
+parse_error:
+       e_dev_err("options error '%s'\n", p);
+       return;
+}
+
+/**
+ * ixgbe_find_config_line - scan config file for labeled option line
+ * @fw: pointer to firmware data
+ * @label: label to search for
+ *
+ * Returns pointer to the configuration options found, or NULL
+ **/
+static char *ixgbe_find_config_line(const struct firmware *fw,
+                                   const char *label)
+{
+       const char *p = fw->data;
+       const char *p_end = fw->data + fw->size;
+       int label_len = strlen(label);
+
+       while (p < p_end) {
+               /* ignore spaces and line comments */
+               p = skip_spaces(p);
+               if (p >= p_end)
+                       break;
+               if (*p == '#')
+                       goto scan_to_eol;
+
+               /* find tag match? */
+               if (!strncmp(p, label, min_t(int, label_len, (p_end - p)))) {
+
+                       /* skip over the tag to find the options */
+                       p += label_len;
+                       p = skip_spaces(p);
+                       if (p >= p_end)
+                               break;
+                       if (*p != '#')
+                               return (char *)p;
+               }
+
+scan_to_eol:
+               while (p < p_end && *p != '\n')
+                       p++;
+               if (p < p_end && *p == '\n')
+                       p++;
+       }
+
+       return NULL;
+}
+
+/**
+ * ixgbe_check_options - find and check configuration parameters
+ * @adapter: pointer to ixgbe_adapter
+ * @label: the configuration tag to search for
+ **/
+void ixgbe_check_options(struct ixgbe_adapter *adapter, const char *label)
+{
+       char *config_line;
+       char *line_end;
+       int line_len, remaining;
+       int ret;
+       const struct firmware *fw;
+
+       ret = request_firmware(&fw, IXGBE_FIRMWARE_FILE, &adapter->pdev->dev);
+       if (ret)
+               return;
+
+       config_line = ixgbe_find_config_line(fw, label);
+       if (config_line) {
+               remaining = fw->size - (config_line - (char *)fw->data);
+               line_end = strnchr(config_line, remaining, '\n');
+               if (line_end)
+                       line_len = line_end - config_line;
+               else
+                       line_len = remaining;
+               ixgbe_parse_option_line(adapter, config_line, line_len);
+       }
+       release_firmware(fw);
+}
+
 static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
 {
        if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
@@ -4572,12 +4749,6 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
        hw->fc.disable_fc_autoneg =
                (ixgbe_device_supports_autoneg_fc(hw) == 0) ? false : true;
 
-#ifdef CONFIG_PCI_IOV
-       /* assign number of SR-IOV VFs */
-       if (hw->mac.type != ixgbe_mac_82598EB)
-               adapter->num_vfs = (max_vfs > 63) ? 0 : max_vfs;
-
-#endif
        /* enable itr by default in dynamic mode */
        adapter->rx_itr_setting = 1;
        adapter->tx_itr_setting = 1;
@@ -7197,6 +7368,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
        u8 part_str[IXGBE_PBANUM_LENGTH];
        unsigned int indices = num_possible_cpus();
        unsigned int dcb_max = 0;
+       char mac_str[20];
 #ifdef IXGBE_FCOE
        u16 device_caps;
 #endif
@@ -7279,7 +7451,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
        adapter->pdev = pdev;
        hw = &adapter->hw;
        hw->back = adapter;
-       adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
+       adapter->msg_enable = netif_msg_init(-1, DEFAULT_MSG_ENABLE);
 
        hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
                              pci_resource_len(pdev, 0));
@@ -7324,6 +7496,9 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
        if (err)
                goto err_sw_init;
 
+       /* look for generic options in userland config file */
+       ixgbe_check_options(adapter, ixgbe_driver_name);
+
        /* Make it possible the adapter to be woken up via WOL */
        switch (adapter->hw.mac.type) {
        case ixgbe_mac_82599EB:
@@ -7344,12 +7519,14 @@ static int ixgbe_probe(struct pci_dev *pdev, const 
struct pci_device_id *ent)
                        e_crit(probe, "Fan has stopped, replace the adapter\n");
        }
 
-       if (allow_unsupported_sfp)
-               hw->allow_unsupported_sfp = allow_unsupported_sfp;
-
        /* reset_hw fills in the perm_addr as well */
        hw->phy.reset_if_overtemp = true;
        err = hw->mac.ops.reset_hw(hw);
+
+       /* look for mac specific options in userland config file */
+       snprintf(mac_str, sizeof(mac_str)-1, "%pM", adapter->hw.mac.addr);
+       ixgbe_check_options(adapter, mac_str);
+
        hw->phy.reset_if_overtemp = false;
        if (err == IXGBE_ERR_SFP_NOT_PRESENT &&
            hw->mac.type == ixgbe_mac_82598EB) {

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to