|
@@ -1484,6 +1484,156 @@ bool iwl_good_ack_health(struct iwl_priv *priv,
|
|
|
}
|
|
|
|
|
|
|
|
|
+/*****************************************************************************
|
|
|
+ *
|
|
|
+ * sysfs attributes
|
|
|
+ *
|
|
|
+ *****************************************************************************/
|
|
|
+
|
|
|
+#ifdef CONFIG_IWLWIFI_DEBUG
|
|
|
+
|
|
|
+/*
|
|
|
+ * The following adds a new attribute to the sysfs representation
|
|
|
+ * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
|
|
|
+ * used for controlling the debug level.
|
|
|
+ *
|
|
|
+ * See the level definitions in iwl for details.
|
|
|
+ *
|
|
|
+ * The debug_level being managed using sysfs below is a per device debug
|
|
|
+ * level that is used instead of the global debug level if it (the per
|
|
|
+ * device debug level) is set.
|
|
|
+ */
|
|
|
+static ssize_t show_debug_level(struct device *d,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
+ return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
|
|
|
+}
|
|
|
+static ssize_t store_debug_level(struct device *d,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
+ unsigned long val;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = strict_strtoul(buf, 0, &val);
|
|
|
+ if (ret)
|
|
|
+ IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
|
|
|
+ else {
|
|
|
+ priv->debug_level = val;
|
|
|
+ if (iwl_alloc_traffic_mem(priv))
|
|
|
+ IWL_ERR(priv,
|
|
|
+ "Not enough memory to generate traffic log\n");
|
|
|
+ }
|
|
|
+ return strnlen(buf, count);
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
|
|
|
+ show_debug_level, store_debug_level);
|
|
|
+
|
|
|
+
|
|
|
+#endif /* CONFIG_IWLWIFI_DEBUG */
|
|
|
+
|
|
|
+
|
|
|
+static ssize_t show_temperature(struct device *d,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
+
|
|
|
+ if (!iwl_is_alive(priv))
|
|
|
+ return -EAGAIN;
|
|
|
+
|
|
|
+ return sprintf(buf, "%d\n", priv->temperature);
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
|
|
|
+
|
|
|
+static ssize_t show_tx_power(struct device *d,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
+
|
|
|
+ if (!iwl_is_ready_rf(priv))
|
|
|
+ return sprintf(buf, "off\n");
|
|
|
+ else
|
|
|
+ return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t store_tx_power(struct device *d,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
+ unsigned long val;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = strict_strtoul(buf, 10, &val);
|
|
|
+ if (ret)
|
|
|
+ IWL_INFO(priv, "%s is not in decimal form.\n", buf);
|
|
|
+ else {
|
|
|
+ ret = iwl_set_tx_power(priv, val, false);
|
|
|
+ if (ret)
|
|
|
+ IWL_ERR(priv, "failed setting tx power (0x%d).\n",
|
|
|
+ ret);
|
|
|
+ else
|
|
|
+ ret = count;
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
|
|
|
+
|
|
|
+static ssize_t show_rts_ht_protection(struct device *d,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
+
|
|
|
+ return sprintf(buf, "%s\n",
|
|
|
+ priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self");
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t store_rts_ht_protection(struct device *d,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
+ unsigned long val;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = strict_strtoul(buf, 10, &val);
|
|
|
+ if (ret)
|
|
|
+ IWL_INFO(priv, "Input is not in decimal form.\n");
|
|
|
+ else {
|
|
|
+ if (!iwl_is_associated(priv))
|
|
|
+ priv->cfg->use_rts_for_ht = val ? true : false;
|
|
|
+ else
|
|
|
+ IWL_ERR(priv, "Sta associated with AP - "
|
|
|
+ "Change protection mechanism is not allowed\n");
|
|
|
+ ret = count;
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO,
|
|
|
+ show_rts_ht_protection, store_rts_ht_protection);
|
|
|
+
|
|
|
+
|
|
|
+static struct attribute *iwl_sysfs_entries[] = {
|
|
|
+ &dev_attr_temperature.attr,
|
|
|
+ &dev_attr_tx_power.attr,
|
|
|
+ &dev_attr_rts_ht_protection.attr,
|
|
|
+#ifdef CONFIG_IWLWIFI_DEBUG
|
|
|
+ &dev_attr_debug_level.attr,
|
|
|
+#endif
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group iwl_attribute_group = {
|
|
|
+ .name = NULL, /* put in device directory */
|
|
|
+ .attrs = iwl_sysfs_entries,
|
|
|
+};
|
|
|
+
|
|
|
/******************************************************************************
|
|
|
*
|
|
|
* uCode download functions
|
|
@@ -1965,6 +2115,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
|
|
|
if (err)
|
|
|
IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
|
|
|
|
|
|
+ err = sysfs_create_group(&priv->pci_dev->dev.kobj,
|
|
|
+ &iwl_attribute_group);
|
|
|
+ if (err) {
|
|
|
+ IWL_ERR(priv, "failed to create sysfs device attributes\n");
|
|
|
+ goto out_unbind;
|
|
|
+ }
|
|
|
+
|
|
|
/* We have our copies now, allow OS release its copies */
|
|
|
release_firmware(ucode_raw);
|
|
|
complete(&priv->_agn.firmware_loading_complete);
|
|
@@ -3262,141 +3419,6 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/*****************************************************************************
|
|
|
- *
|
|
|
- * sysfs attributes
|
|
|
- *
|
|
|
- *****************************************************************************/
|
|
|
-
|
|
|
-#ifdef CONFIG_IWLWIFI_DEBUG
|
|
|
-
|
|
|
-/*
|
|
|
- * The following adds a new attribute to the sysfs representation
|
|
|
- * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
|
|
|
- * used for controlling the debug level.
|
|
|
- *
|
|
|
- * See the level definitions in iwl for details.
|
|
|
- *
|
|
|
- * The debug_level being managed using sysfs below is a per device debug
|
|
|
- * level that is used instead of the global debug level if it (the per
|
|
|
- * device debug level) is set.
|
|
|
- */
|
|
|
-static ssize_t show_debug_level(struct device *d,
|
|
|
- struct device_attribute *attr, char *buf)
|
|
|
-{
|
|
|
- struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
- return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
|
|
|
-}
|
|
|
-static ssize_t store_debug_level(struct device *d,
|
|
|
- struct device_attribute *attr,
|
|
|
- const char *buf, size_t count)
|
|
|
-{
|
|
|
- struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
- unsigned long val;
|
|
|
- int ret;
|
|
|
-
|
|
|
- ret = strict_strtoul(buf, 0, &val);
|
|
|
- if (ret)
|
|
|
- IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
|
|
|
- else {
|
|
|
- priv->debug_level = val;
|
|
|
- if (iwl_alloc_traffic_mem(priv))
|
|
|
- IWL_ERR(priv,
|
|
|
- "Not enough memory to generate traffic log\n");
|
|
|
- }
|
|
|
- return strnlen(buf, count);
|
|
|
-}
|
|
|
-
|
|
|
-static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
|
|
|
- show_debug_level, store_debug_level);
|
|
|
-
|
|
|
-
|
|
|
-#endif /* CONFIG_IWLWIFI_DEBUG */
|
|
|
-
|
|
|
-
|
|
|
-static ssize_t show_temperature(struct device *d,
|
|
|
- struct device_attribute *attr, char *buf)
|
|
|
-{
|
|
|
- struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
-
|
|
|
- if (!iwl_is_alive(priv))
|
|
|
- return -EAGAIN;
|
|
|
-
|
|
|
- return sprintf(buf, "%d\n", priv->temperature);
|
|
|
-}
|
|
|
-
|
|
|
-static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
|
|
|
-
|
|
|
-static ssize_t show_tx_power(struct device *d,
|
|
|
- struct device_attribute *attr, char *buf)
|
|
|
-{
|
|
|
- struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
-
|
|
|
- if (!iwl_is_ready_rf(priv))
|
|
|
- return sprintf(buf, "off\n");
|
|
|
- else
|
|
|
- return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
|
|
|
-}
|
|
|
-
|
|
|
-static ssize_t store_tx_power(struct device *d,
|
|
|
- struct device_attribute *attr,
|
|
|
- const char *buf, size_t count)
|
|
|
-{
|
|
|
- struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
- unsigned long val;
|
|
|
- int ret;
|
|
|
-
|
|
|
- ret = strict_strtoul(buf, 10, &val);
|
|
|
- if (ret)
|
|
|
- IWL_INFO(priv, "%s is not in decimal form.\n", buf);
|
|
|
- else {
|
|
|
- ret = iwl_set_tx_power(priv, val, false);
|
|
|
- if (ret)
|
|
|
- IWL_ERR(priv, "failed setting tx power (0x%d).\n",
|
|
|
- ret);
|
|
|
- else
|
|
|
- ret = count;
|
|
|
- }
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
|
|
|
-
|
|
|
-static ssize_t show_rts_ht_protection(struct device *d,
|
|
|
- struct device_attribute *attr, char *buf)
|
|
|
-{
|
|
|
- struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
-
|
|
|
- return sprintf(buf, "%s\n",
|
|
|
- priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self");
|
|
|
-}
|
|
|
-
|
|
|
-static ssize_t store_rts_ht_protection(struct device *d,
|
|
|
- struct device_attribute *attr,
|
|
|
- const char *buf, size_t count)
|
|
|
-{
|
|
|
- struct iwl_priv *priv = dev_get_drvdata(d);
|
|
|
- unsigned long val;
|
|
|
- int ret;
|
|
|
-
|
|
|
- ret = strict_strtoul(buf, 10, &val);
|
|
|
- if (ret)
|
|
|
- IWL_INFO(priv, "Input is not in decimal form.\n");
|
|
|
- else {
|
|
|
- if (!iwl_is_associated(priv))
|
|
|
- priv->cfg->use_rts_for_ht = val ? true : false;
|
|
|
- else
|
|
|
- IWL_ERR(priv, "Sta associated with AP - "
|
|
|
- "Change protection mechanism is not allowed\n");
|
|
|
- ret = count;
|
|
|
- }
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO,
|
|
|
- show_rts_ht_protection, store_rts_ht_protection);
|
|
|
-
|
|
|
-
|
|
|
/*****************************************************************************
|
|
|
*
|
|
|
* driver setup and teardown
|
|
@@ -3550,21 +3572,6 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
|
|
|
kfree(priv->scan_cmd);
|
|
|
}
|
|
|
|
|
|
-static struct attribute *iwl_sysfs_entries[] = {
|
|
|
- &dev_attr_temperature.attr,
|
|
|
- &dev_attr_tx_power.attr,
|
|
|
- &dev_attr_rts_ht_protection.attr,
|
|
|
-#ifdef CONFIG_IWLWIFI_DEBUG
|
|
|
- &dev_attr_debug_level.attr,
|
|
|
-#endif
|
|
|
- NULL
|
|
|
-};
|
|
|
-
|
|
|
-static struct attribute_group iwl_attribute_group = {
|
|
|
- .name = NULL, /* put in device directory */
|
|
|
- .attrs = iwl_sysfs_entries,
|
|
|
-};
|
|
|
-
|
|
|
static struct ieee80211_ops iwl_hw_ops = {
|
|
|
.tx = iwl_mac_tx,
|
|
|
.start = iwl_mac_start,
|
|
@@ -3750,11 +3757,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
|
|
|
goto out_disable_msi;
|
|
|
}
|
|
|
- err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
|
|
|
- if (err) {
|
|
|
- IWL_ERR(priv, "failed to create sysfs device attributes\n");
|
|
|
- goto out_free_irq;
|
|
|
- }
|
|
|
|
|
|
iwl_setup_deferred_work(priv);
|
|
|
iwl_setup_rx_handlers(priv);
|
|
@@ -3788,15 +3790,13 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
|
|
|
err = iwl_request_firmware(priv, true);
|
|
|
if (err)
|
|
|
- goto out_remove_sysfs;
|
|
|
+ goto out_destroy_workqueue;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
- out_remove_sysfs:
|
|
|
+ out_destroy_workqueue:
|
|
|
destroy_workqueue(priv->workqueue);
|
|
|
priv->workqueue = NULL;
|
|
|
- sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
|
|
|
- out_free_irq:
|
|
|
free_irq(priv->pci_dev->irq, priv);
|
|
|
iwl_free_isr_ict(priv);
|
|
|
out_disable_msi:
|