2008-03-28 23:25:25

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 0/8] iwlwifi driver updates including one mac80211 change

This patch series contains bug fixes as well as new rfkill features.

The series includes on patch to mac80211 that enables a driver to
send status events to mac. This patch also changes iwlwifi to make
use of this new feature.

[PATCH 1/8] iwlwifi: add notification infrastructure to iwlcore
[PATCH 2/8] iwlwifi: hook iwlwifi with Linux rfkill
[PATCH 3/8] mac80211: enable driver to notify mac of status, change iwlwifi
[PATCH 4/8] iwlwifi: fix race condition during driver unload
[PATCH 5/8] iwlwifi: move rate registration to module load
[PATCH 6/8] iwlwifi: unregister to upper stack before releasing resources
[PATCH 7/8] iwlwifi: LED initialize before registering
[PATCH 8/8] iwlwifi: Fix synchronous host command


Thank you

Reinette



2008-03-28 23:42:05

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 3/8] mac80211: enable driver to notify mac of status, change iwlwifi


> /**
> + * enum ieee80211_notification_type - Low level driver notification
> + * @TYPE_RE_ASSOC: start the re-association sequence

That I can understand, for whatever reason you want it to re-associate.
But please use a different prefix, not TYPE_, maybe something like
IEEE80211_NOTIFY_*

> + * @TYPE_DISCONNECT: disconnect from current association

That doesn't seem to make sense.

> + * @TYPE_RESET: low level driver HW problem reset

Nor that? Half-implemented?

Do you think suspend/resume should go through this interface as well? If
so, a hardware reset could just do a suspend/resume cycle and ignore
everything coming in during the suspend?

During suspend, I'd think the hardware should actually be deconfigured
completely and then re-configured completely for resume.

> +/*

Should be /**

> + * ieee80211_notify_mac - low level driver notification
> + * @hw: pointer as obtained from ieee80211_alloc_hw().
> + * @notification_types: enum ieee80211_notification_types
> + *
> + * This function must be called by low level driver to sync mac80211
> + * with low level state.
> + */
> +void ieee80211_notify_mac(struct ieee80211_hw *hw,
> + enum ieee80211_notification_types notif_type);

I also think that the description could be more detailed. This seems to
indicate that somehow it's easy to get out of sync, it shouldn't be the
common case for that to happen!

> + default:
> + break;
> + }
> +}
> +EXPORT_SYMBOL(ieee80211_notify_mac);

Please don't add default statements like that, just handle all cases,
that allows the compiler warnings to actually help coding.

johannes


Attachments:
signature.asc (828.00 B)
This is a digitally signed message part

2008-03-28 23:25:33

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 3/8] mac80211: enable driver to notify mac of status, change iwlwifi

From: Mohamed Abbas <[email protected]>

Add new API to MAC80211 to allow low level driver to
notify MAC with driver status like comming from suspend
and HW rfkill. Modify iwlwifi driver to use new API.

Signed-off-by: Mohamed Abbas <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 +
drivers/net/wireless/iwlwifi/iwl4965-base.c | 1 +
include/net/mac80211.h | 24 ++++++++++++++++++++++
net/mac80211/ieee80211_sta.c | 29 +++++++++++++++++++++++++++
4 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index ab635dc..02b4245 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -5869,6 +5869,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
if (priv->error_recovering)
iwl3945_error_recovery(priv);

+ ieee80211_notify_mac(priv->hw, TYPE_RE_ASSOC);
return;

restart:
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 7f56565..96daece 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -5733,6 +5733,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
iwl4965_error_recovery(priv);

iwlcore_low_level_notify(priv, IWLCORE_START_EVT);
+ ieee80211_notify_mac(priv->hw, TYPE_RE_ASSOC);
return;

restart:
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 48428a6..0679adc 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -74,6 +74,20 @@
*/

/**
+ * enum ieee80211_notification_type - Low level driver notification
+ * @TYPE_RE_ASSOC: start the re-association sequence
+ * @TYPE_DISCONNECT: disconnect from current association
+ * @TYPE_RESET: low level driver HW problem reset
+ */
+enum ieee80211_notification_types {
+ TYPE_RE_ASSOC,
+ TYPE_DISCONNECT,
+ TYPE_RESET,
+ /* keep last */
+ NUM_IEEE80211_NOTIFICATION_TYPES
+};
+
+/**
* struct ieee80211_ht_bss_info - describing BSS's HT characteristics
*
* This structure describes most essential parameters needed
@@ -1663,4 +1677,14 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid);
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
u16 tid);

+/*
+ * ieee80211_notify_mac - low level driver notification
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @notification_types: enum ieee80211_notification_types
+ *
+ * This function must be called by low level driver to sync mac80211
+ * with low level state.
+ */
+void ieee80211_notify_mac(struct ieee80211_hw *hw,
+ enum ieee80211_notification_types notif_type);
#endif /* MAC80211_H */
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index f9cf2f1..b1c9a5a 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -4216,3 +4216,32 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason)
ieee80211_set_disassoc(dev, ifsta, 0);
return 0;
}
+
+void ieee80211_notify_mac(struct ieee80211_hw *hw,
+ enum ieee80211_notification_types notif_type)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_sub_if_data *sdata;
+
+ switch (notif_type) {
+ case TYPE_RE_ASSOC:
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+
+ /* No need to wake the master device. */
+ if (sdata->dev == local->mdev)
+ continue;
+
+ if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
+ ieee80211_sta_req_auth(sdata->dev,
+ &sdata->u.sta);
+ }
+
+ }
+ rcu_read_unlock();
+ break;
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL(ieee80211_notify_mac);
--
1.5.3.4


2008-03-28 23:25:33

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 7/8] iwlwifi: LED initialize before registering

From: Tomas Winkler <[email protected]>

This patch initialize all fields in led before registering it
This fixes oops on initialization

Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-led.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index d59ad18..4fe5ee2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -238,18 +238,20 @@ static int iwl_leds_register_led(struct iwl_priv *priv,
led->led_dev.brightness_set = iwl4965_led_brightness_set;
led->led_dev.default_trigger = trigger;

+ led->priv = priv;
+ led->type = type;
+
ret = led_classdev_register(device, &led->led_dev);
if (ret) {
IWL_ERROR("Error: failed to register led handler.\n");
return ret;
}

- led->priv = priv;
- led->type = type;
led->registered = 1;

if (set_led && led->led_on)
led->led_on(priv, IWL_LED_LINK);
+
return 0;
}

--
1.5.3.4


2008-03-28 23:25:34

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 5/8] iwlwifi: move rate registration to module load

Having rate registration during module load enables the use of
error checking as well as reliable registration/unregistration
pairing. Previously this was not possible as rate registration
was done during _probe where _probe could be run for more than
one device on the system.

Signed-off-by: Reinette Chatre <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 6 +++---
drivers/net/wireless/iwlwifi/iwl-3945-rs.h | 4 ++--
drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 6 +++---
drivers/net/wireless/iwlwifi/iwl-4965-rs.h | 4 ++--
drivers/net/wireless/iwlwifi/iwl-4965.c | 1 -
drivers/net/wireless/iwlwifi/iwl3945-base.c | 23 ++++++++++++++++++-----
drivers/net/wireless/iwlwifi/iwl4965-base.c | 22 ++++++++++++++++++----
7 files changed, 46 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 157e572..8559f25 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -976,12 +976,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
iwl3945_rates[rs_sta->start_rate].plcp);
}

-void iwl3945_rate_control_register(struct ieee80211_hw *hw)
+int iwl3945_rate_control_register(void)
{
- ieee80211_rate_control_register(&rs_ops);
+ return ieee80211_rate_control_register(&rs_ops);
}

-void iwl3945_rate_control_unregister(struct ieee80211_hw *hw)
+void iwl3945_rate_control_unregister(void)
{
ieee80211_rate_control_unregister(&rs_ops);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
index e88b1d3..f085d33 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
@@ -202,7 +202,7 @@ extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
* ieee80211_register_hw
*
*/
-extern void iwl3945_rate_control_register(struct ieee80211_hw *hw);
+extern int iwl3945_rate_control_register(void);

/**
* iwl3945_rate_control_unregister - Unregister the rate control callbacks
@@ -210,6 +210,6 @@ extern void iwl3945_rate_control_register(struct ieee80211_hw *hw);
* This should be called after calling ieee80211_unregister_hw, but before
* the driver is unloaded.
*/
-extern void iwl3945_rate_control_unregister(struct ieee80211_hw *hw);
+extern void iwl3945_rate_control_unregister(void);

#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index 735eadd..90ecf26 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -2822,12 +2822,12 @@ void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
priv->lq_mngr.lq_ready = 1;
}

-void iwl4965_rate_control_register(struct ieee80211_hw *hw)
+int iwl4965_rate_control_register(void)
{
- ieee80211_rate_control_register(&rs_ops);
+ return ieee80211_rate_control_register(&rs_ops);
}

-void iwl4965_rate_control_unregister(struct ieee80211_hw *hw)
+void iwl4965_rate_control_unregister(void)
{
ieee80211_rate_control_unregister(&rs_ops);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
index ae827e1..866e378 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
@@ -288,7 +288,7 @@ extern void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
* ieee80211_register_hw
*
*/
-extern void iwl4965_rate_control_register(struct ieee80211_hw *hw);
+extern int iwl4965_rate_control_register(void);

/**
* iwl4965_rate_control_unregister - Unregister the rate control callbacks
@@ -296,6 +296,6 @@ extern void iwl4965_rate_control_register(struct ieee80211_hw *hw);
* This should be called after calling ieee80211_unregister_hw, but before
* the driver is unloaded.
*/
-extern void iwl4965_rate_control_unregister(struct ieee80211_hw *hw);
+extern void iwl4965_rate_control_unregister(void);

#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 3ab5d82..add6311 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -177,7 +177,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv)
goto err_free_channel_map;
}

- iwl4965_rate_control_register(priv->hw);
ret = ieee80211_register_hw(priv->hw);
if (ret) {
IWL_ERROR("Failed to register network device (error %d)\n",
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index ed85db7..af7233e 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -8157,7 +8157,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
goto out_free_channel_map;
}

- iwl3945_rate_control_register(priv->hw);
err = ieee80211_register_hw(priv->hw);
if (err) {
IWL_ERROR("Failed to register network device (error %d)\n", err);
@@ -8242,7 +8241,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)

if (priv->mac80211_registered) {
ieee80211_unregister_hw(priv->hw);
- iwl3945_rate_control_unregister(priv->hw);
}

/*netif_stop_queue(dev); */
@@ -8323,21 +8321,35 @@ static int __init iwl3945_init(void)
int ret;
printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+
+ ret = iwl3945_rate_control_register();
+ if (ret) {
+ IWL_ERROR("Unable to register rate control algorithm: %d\n", ret);
+ return ret;
+ }
+
ret = pci_register_driver(&iwl3945_driver);
if (ret) {
IWL_ERROR("Unable to initialize PCI module\n");
- return ret;
+ goto error_register;
}
#ifdef CONFIG_IWL3945_DEBUG
ret = driver_create_file(&iwl3945_driver.driver, &driver_attr_debug_level);
if (ret) {
IWL_ERROR("Unable to create driver sysfs file\n");
- pci_unregister_driver(&iwl3945_driver);
- return ret;
+ goto error_debug;
}
#endif

return ret;
+
+#ifdef CONFIG_IWL3945_DEBUG
+error_debug:
+ pci_unregister_driver(&iwl3945_driver);
+#endif
+error_register:
+ iwl3945_rate_control_unregister();
+ return ret;
}

static void __exit iwl3945_exit(void)
@@ -8346,6 +8358,7 @@ static void __exit iwl3945_exit(void)
driver_remove_file(&iwl3945_driver.driver, &driver_attr_debug_level);
#endif
pci_unregister_driver(&iwl3945_driver);
+ iwl3945_rate_control_unregister();
}

module_param_named(antenna, iwl3945_param_antenna, int, 0444);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 7f2dca3..3ea8c7e 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -8244,7 +8244,6 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)

if (priv->mac80211_registered) {
ieee80211_unregister_hw(priv->hw);
- iwl4965_rate_control_unregister(priv->hw);
}

/*netif_stop_queue(dev); */
@@ -8325,21 +8324,35 @@ static int __init iwl4965_init(void)
int ret;
printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+
+ ret = iwl4965_rate_control_register();
+ if (ret) {
+ IWL_ERROR("Unable to register rate control algorithm: %d\n", ret);
+ return ret;
+ }
+
ret = pci_register_driver(&iwl4965_driver);
if (ret) {
IWL_ERROR("Unable to initialize PCI module\n");
- return ret;
+ goto error_register;
}
#ifdef CONFIG_IWLWIFI_DEBUG
ret = driver_create_file(&iwl4965_driver.driver, &driver_attr_debug_level);
if (ret) {
IWL_ERROR("Unable to create driver sysfs file\n");
- pci_unregister_driver(&iwl4965_driver);
- return ret;
+ goto error_debug;
}
#endif

return ret;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+error_debug:
+ pci_unregister_driver(&iwl4965_driver);
+#endif
+error_register:
+ iwl4965_rate_control_unregister();
+ return ret;
}

static void __exit iwl4965_exit(void)
@@ -8348,6 +8361,7 @@ static void __exit iwl4965_exit(void)
driver_remove_file(&iwl4965_driver.driver, &driver_attr_debug_level);
#endif
pci_unregister_driver(&iwl4965_driver);
+ iwl4965_rate_control_unregister();
}

module_exit(iwl4965_exit);
--
1.5.3.4


2008-03-28 23:25:25

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 1/8] iwlwifi: add notification infrastructure to iwlcore

From: Mohamed Abbas <[email protected]>

This patch add notification function to be called by low level
iwl driver to notify iwlcore with current state. This function
will call iwlcore subsystem with the new state. This will
help make the code more consistent and easy to extend. For example
the rf-kill need to know when the driver in init, start, stop or
remove state. Instead doing the same call in 3945 and 4965, we
just do it from this function.

Signed-off-by: Mohamed Abbas <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-core.c | 21 +++++++++++++++++++++
drivers/net/wireless/iwlwifi/iwl-core.h | 9 +++++++++
drivers/net/wireless/iwlwifi/iwl4965-base.c | 6 ++++++
3 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index da51349..342a269 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -249,3 +249,24 @@ int iwl_setup(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_setup);

+/* Low level driver call this function to update iwlcore with
+ * driver status.
+ */
+int iwlcore_low_level_notify(struct iwl_priv *priv,
+ enum iwlcore_card_notify notify)
+{
+ switch (notify) {
+ case IWLCORE_INIT_EVT:
+ break;
+ case IWLCORE_START_EVT:
+ break;
+ case IWLCORE_STOP_EVT:
+ break;
+ case IWLCORE_REMOVE_EVT:
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(iwlcore_low_level_notify);
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index ce7f90e..4dfa059 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -146,4 +146,13 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
struct iwl_cmd *cmd,
struct sk_buff *skb));

+enum iwlcore_card_notify {
+ IWLCORE_INIT_EVT = 0,
+ IWLCORE_START_EVT = 1,
+ IWLCORE_STOP_EVT = 2,
+ IWLCORE_REMOVE_EVT = 3,
+};
+
+int iwlcore_low_level_notify(struct iwl_priv *priv,
+ enum iwlcore_card_notify notify);
#endif /* __iwl_core_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index cf56b95..5261b61 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -5724,6 +5724,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
if (priv->error_recovering)
iwl4965_error_recovery(priv);

+ iwlcore_low_level_notify(priv, IWLCORE_START_EVT);
return;

restart:
@@ -5747,6 +5748,8 @@ static void __iwl4965_down(struct iwl_priv *priv)

iwl_leds_unregister(priv);

+ iwlcore_low_level_notify(priv, IWLCORE_STOP_EVT);
+
iwlcore_clear_stations_table(priv);

/* Unblock any waiting calls */
@@ -8167,6 +8170,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
pci_save_state(pdev);
pci_disable_device(pdev);

+ /* notify iwlcore to init */
+ iwlcore_low_level_notify(priv, IWLCORE_INIT_EVT);
return 0;

out_remove_sysfs:
@@ -8209,6 +8214,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
}
}

+ iwlcore_low_level_notify(priv, IWLCORE_REMOVE_EVT);
iwl_dbgfs_unregister(priv);
sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);

--
1.5.3.4


2008-03-28 23:25:34

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 6/8] iwlwifi: unregister to upper stack before releasing resources

From: Ron Rindjunsky <[email protected]>

This patch fixes an early release of driver's resources before upper stack
was notified that low-level driver shuts down.

Signed-off-by: Ron Rindjunsky <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl4965-base.c | 8 +++++---
1 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 3ea8c7e..6b69429 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -8208,6 +8208,11 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)

IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");

+ if (priv->mac80211_registered) {
+ ieee80211_unregister_hw(priv->hw);
+ priv->mac80211_registered = 0;
+ }
+
set_bit(STATUS_EXIT_PENDING, &priv->status);

iwl4965_down(priv);
@@ -8242,9 +8247,6 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
iwl4965_unset_hw_setting(priv);
iwlcore_clear_stations_table(priv);

- if (priv->mac80211_registered) {
- ieee80211_unregister_hw(priv->hw);
- }

/*netif_stop_queue(dev); */
flush_workqueue(priv->workqueue);
--
1.5.3.4


2008-03-28 23:25:32

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 2/8] iwlwifi: hook iwlwifi with Linux rfkill

From: Mohamed Abbas <[email protected]>

This patch hook IWL with Linux rfkill.

Signed-off-by: Mohamed Abbas <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/Kconfig | 6 +
drivers/net/wireless/iwlwifi/Makefile | 4 +
drivers/net/wireless/iwlwifi/iwl-4965.c | 1 +
drivers/net/wireless/iwlwifi/iwl-4965.h | 5 +
drivers/net/wireless/iwlwifi/iwl-core.c | 4 +
drivers/net/wireless/iwlwifi/iwl-core.h | 1 +
drivers/net/wireless/iwlwifi/iwl-rfkill.c | 174 +++++++++++++++++++++++++++
drivers/net/wireless/iwlwifi/iwl-rfkill.h | 56 +++++++++
drivers/net/wireless/iwlwifi/iwl4965-base.c | 54 +++-----
9 files changed, 271 insertions(+), 34 deletions(-)
create mode 100644 drivers/net/wireless/iwlwifi/iwl-rfkill.c
create mode 100644 drivers/net/wireless/iwlwifi/iwl-rfkill.h

diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index c26ca74..4a5c8c0 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -9,6 +9,12 @@ config IWLWIFI_LEDS
This option enables LEDS for the iwlwifi drivers


+config IWLCORE_RFKILL
+ boolean "IWLWIFI RF kill support"
+ depends on IWLCORE
+ select RFKILL
+ select RFKILL_INPUT
+
config IWL4965
tristate "Intel Wireless WiFi 4965AGN"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 64fca4d..2751e8a 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -9,6 +9,10 @@ ifeq ($(CONFIG_IWLWIFI_LEDS),y)
iwlcore-objs += iwl-led.o
endif

+ifeq ($(CONFIG_IWLCORE_RFKILL),y)
+ iwlcore-objs += iwl-rfkill.o
+endif
+
obj-$(CONFIG_IWL3945) += iwl3945.o
iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o

diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index e5f64d7..3ab5d82 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -4961,6 +4961,7 @@ static struct iwl_lib_ops iwl4965_lib = {
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
},
+ .radio_kill_sw = iwl4965_radio_kill_sw,
};

static struct iwl_ops iwl4965_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index 069e591..ca864fa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -40,6 +40,7 @@
extern struct pci_device_id iwl4965_hw_card_ids[];

#define DRV_NAME "iwl4965"
+#include "iwl-rfkill.h"
#include "iwl-eeprom.h"
#include "iwl-4965-hw.h"
#include "iwl-csr.h"
@@ -739,6 +740,7 @@ extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index
extern int iwl4965_queue_space(const struct iwl4965_queue *q);
struct iwl_priv;

+extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio);
/*
* Forward declare iwl-4965.c functions for iwl-base.c
*/
@@ -1050,6 +1052,9 @@ struct iwl_priv {
* 4965's initialize alive response contains some calibration data. */
struct iwl4965_init_alive_resp card_alive_init;
struct iwl4965_alive_resp card_alive;
+#ifdef CONFIG_IWLCORE_RFKILL
+ struct iwl_rfkill_mngr rfkill_mngr;
+#endif

#ifdef CONFIG_IWL4965_LEDS
struct iwl4965_led led[IWL_LED_TRG_MAX];
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 342a269..49fb52f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -35,6 +35,7 @@ struct iwl_priv; /* FIXME: remove */
#include "iwl-debug.h"
#include "iwl-eeprom.h"
#include "iwl-core.h"
+#include "iwl-rfkill.h"

#include "iwl-4965.h" /* FIXME: remove */

@@ -257,12 +258,15 @@ int iwlcore_low_level_notify(struct iwl_priv *priv,
{
switch (notify) {
case IWLCORE_INIT_EVT:
+ iwl_rfkill_init(priv);
break;
case IWLCORE_START_EVT:
break;
case IWLCORE_STOP_EVT:
break;
case IWLCORE_REMOVE_EVT:
+ iwl_rfkill_unregister(priv);
+ iwl_rfkill_free(priv);
break;
}

diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 4dfa059..5efafe1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -91,6 +91,7 @@ struct iwl_lib_ops {
int (*init_drv)(struct iwl_priv *priv);
/* eeprom operations (as defined in iwl-eeprom.h) */
struct iwl_eeprom_ops eeprom_ops;
+ void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio);
};

struct iwl_ops {
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
new file mode 100644
index 0000000..66abf52
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
@@ -0,0 +1,174 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <[email protected]>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+
+#include <net/mac80211.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-core.h"
+#include "iwl-4965.h"
+#include "iwl-helpers.h"
+
+
+static inline int iwl_is_rfkill(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+ test_bit(STATUS_RF_KILL_SW, &priv->status);
+}
+
+
+/* software rf-kill from user */
+static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
+{
+ struct iwl_priv *priv = data;
+ int err = 0;
+
+ if (!priv->rfkill_mngr.rfkill)
+ return 0;
+
+ IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state);
+ mutex_lock(&priv->mutex);
+
+ switch (state) {
+ case RFKILL_STATE_ON:
+ priv->cfg->ops->lib->radio_kill_sw(priv, 0);
+ /* if HW rf-kill is set dont allow ON state */
+ if (iwl_is_rfkill(priv))
+ err = -EBUSY;
+ break;
+ case RFKILL_STATE_OFF:
+ priv->cfg->ops->lib->radio_kill_sw(priv, 1);
+ if (!iwl_is_rfkill(priv))
+ err = -EBUSY;
+ break;
+ }
+ mutex_unlock(&priv->mutex);
+
+ return err;
+}
+
+int iwl_rfkill_init(struct iwl_priv *priv)
+{
+ struct device *device = wiphy_dev(priv->hw->wiphy);
+ int ret = 0;
+
+ BUG_ON(device == NULL);
+
+ priv->rfkill_mngr.rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
+ if (!priv->rfkill_mngr.rfkill) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ priv->rfkill_mngr.rfkill->name = priv->cfg->name;
+ priv->rfkill_mngr.rfkill->data = priv;
+ priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON;
+ priv->rfkill_mngr.rfkill->toggle_radio = iwl_rfkill_soft_rf_kill;
+ priv->rfkill_mngr.rfkill->user_claim_unsupported = 1;
+
+ priv->rfkill_mngr.rfkill->dev.class->suspend = NULL;
+ priv->rfkill_mngr.rfkill->dev.class->resume = NULL;
+
+ priv->rfkill_mngr.input_dev = input_allocate_device();
+ if (!priv->rfkill_mngr.input_dev) {
+ ret = -ENOMEM;
+ goto freed_rfkill;
+ }
+
+ priv->rfkill_mngr.input_dev->name = priv->cfg->name;
+ priv->rfkill_mngr.input_dev->phys = wiphy_name(priv->hw->wiphy);
+ priv->rfkill_mngr.input_dev->id.bustype = BUS_HOST;
+ priv->rfkill_mngr.input_dev->id.vendor = priv->pci_dev->vendor;
+ priv->rfkill_mngr.input_dev->dev.parent = device;
+ priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit);
+
+ ret = rfkill_register(priv->rfkill_mngr.rfkill);
+ if (ret)
+ goto free_input_dev;
+
+ ret = input_register_device(priv->rfkill_mngr.input_dev);
+ if (ret)
+ goto unregister_rfkill;
+
+ return ret;
+
+unregister_rfkill:
+ rfkill_unregister(priv->rfkill_mngr.rfkill);
+
+free_input_dev:
+ input_free_device(priv->rfkill_mngr.input_dev);
+ priv->rfkill_mngr.input_dev = NULL;
+
+freed_rfkill:
+ rfkill_free(priv->rfkill_mngr.rfkill);
+ priv->rfkill_mngr.rfkill = NULL;
+
+error:
+ return ret;
+}
+EXPORT_SYMBOL(iwl_rfkill_init);
+
+void iwl_rfkill_unregister(struct iwl_priv *priv)
+{
+
+ if (priv->rfkill_mngr.input_dev)
+ input_unregister_device(priv->rfkill_mngr.input_dev);
+
+ if (priv->rfkill_mngr.rfkill)
+ rfkill_unregister(priv->rfkill_mngr.rfkill);
+}
+EXPORT_SYMBOL(iwl_rfkill_unregister);
+
+
+void iwl_rfkill_free(struct iwl_priv *priv)
+{
+ if (priv->rfkill_mngr.input_dev)
+ input_free_device(priv->rfkill_mngr.input_dev);
+
+ if (priv->rfkill_mngr.rfkill)
+ rfkill_free(priv->rfkill_mngr.rfkill);
+}
+EXPORT_SYMBOL(iwl_rfkill_free);
+
+/* set rf-kill to the right state. */
+void iwl_rfkill_set_hw_state(struct iwl_priv *priv)
+{
+
+ if (!priv->rfkill_mngr.rfkill)
+ return;
+
+ if (!iwl_is_rfkill(priv))
+ priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON;
+ else
+ priv->rfkill_mngr.rfkill->state = RFKILL_STATE_OFF;
+}
+EXPORT_SYMBOL(iwl_rfkill_set_hw_state);
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h
new file mode 100644
index 0000000..a5cbc5a
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <[email protected]>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+#ifndef __iwl_rf_kill_h__
+#define __iwl_rf_kill_h__
+
+struct iwl_priv;
+
+#include <linux/rfkill.h>
+#include <linux/input.h>
+
+
+#ifdef CONFIG_IWLCORE_RFKILL
+struct iwl_rfkill_mngr {
+ struct rfkill *rfkill;
+ struct input_dev *input_dev;
+};
+
+void iwl_rfkill_set_hw_state(struct iwl_priv *priv);
+void iwl_rfkill_free(struct iwl_priv *priv);
+void iwl_rfkill_unregister(struct iwl_priv *priv);
+int iwl_rfkill_init(struct iwl_priv *priv);
+#else
+static inline void iwl_rfkill_set_hw_state(struct iwl_priv *priv) {}
+static inline void iwl_rfkill_free(struct iwl_priv *priv) {}
+static inline void iwl_rfkill_unregister(struct iwl_priv *priv) {}
+static inline int iwl_rfkill_init(struct iwl_priv *priv) { return 0; }
+#endif
+
+
+
+#endif /* __iwl_rf_kill_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 5261b61..7f56565 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -2607,7 +2607,7 @@ static void iwl4965_set_rate(struct iwl_priv *priv)
(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
}

-static void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
{
unsigned long flags;

@@ -2625,8 +2625,16 @@ static void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_SW_BIT_RFKILL);
spin_unlock_irqrestore(&priv->lock, flags);
- iwl4965_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+ /* call the host command only if no hw rf-kill set */
+ if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+ iwl4965_send_card_state(priv,
+ CARD_STATE_CMD_DISABLE,
+ 0);
set_bit(STATUS_RF_KILL_SW, &priv->status);
+
+ /* make sure mac80211 stop sending Tx frame */
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
}
return;
}
@@ -5852,6 +5860,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
IWL_WARNING("Radio disabled by SW RF kill (module "
"parameter)\n");
+ iwl_rfkill_set_hw_state(priv);
return -ENODEV;
}

@@ -5867,11 +5876,13 @@ static int __iwl4965_up(struct iwl_priv *priv)
else {
set_bit(STATUS_RF_KILL_HW, &priv->status);
if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
+ iwl_rfkill_set_hw_state(priv);
IWL_WARNING("Radio disabled by HW RF Kill switch\n");
return -ENODEV;
}
}

+ iwl_rfkill_set_hw_state(priv);
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);

rc = iwl4965_hw_nic_init(priv);
@@ -5985,6 +5996,9 @@ static void iwl4965_bg_rf_kill(struct work_struct *work)
if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
queue_work(priv->workqueue, &priv->restart);
} else {
+ /* make sure mac80211 stop sending Tx frame */
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);

if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
IWL_DEBUG_RF_KILL("Can not turn radio back on - "
@@ -5994,6 +6008,8 @@ static void iwl4965_bg_rf_kill(struct work_struct *work)
"Kill switch must be turned off for "
"wireless networking to work.\n");
}
+ iwl_rfkill_set_hw_state(priv);
+
mutex_unlock(&priv->mutex);
}

@@ -6674,7 +6690,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
}
#endif

- iwl4965_radio_kill_sw(priv, !conf->radio_enabled);
+ if (priv->cfg->ops->lib->radio_kill_sw)
+ priv->cfg->ops->lib->radio_kill_sw(priv, !conf->radio_enabled);

if (!conf->radio_enabled) {
IWL_DEBUG_MAC80211("leave - radio disabled\n");
@@ -7449,36 +7466,6 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,

#endif /* CONFIG_IWLWIFI_DEBUG */

-static ssize_t show_rf_kill(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- /*
- * 0 - RF kill not enabled
- * 1 - SW based RF kill active (sysfs)
- * 2 - HW based RF kill active
- * 3 - Both HW and SW based RF kill active
- */
- struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
- int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
- (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
-
- return sprintf(buf, "%i\n", val);
-}
-
-static ssize_t store_rf_kill(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-
- mutex_lock(&priv->mutex);
- iwl4965_radio_kill_sw(priv, buf[0] == '1');
- mutex_unlock(&priv->mutex);
-
- return count;
-}
-
-static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);

static ssize_t show_temperature(struct device *d,
struct device_attribute *attr, char *buf)
@@ -7964,7 +7951,6 @@ static struct attribute *iwl4965_sysfs_entries[] = {
#endif
&dev_attr_power_level.attr,
&dev_attr_retry_rate.attr,
- &dev_attr_rf_kill.attr,
&dev_attr_rs_window.attr,
&dev_attr_statistics.attr,
&dev_attr_status.attr,
--
1.5.3.4


2008-03-28 23:25:33

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 4/8] iwlwifi: fix race condition during driver unload

From: Mohamed Abbas <[email protected]>

This patch fixed the OOPS when load the driver while rf-kill is on then
unload the driver right after load. a race condition caused the interupt
handler to schedule the tasklet which will run right after the driver pci_remove
causing invalid poiter OOPS.

Signed-off-by: Mohamed Abbas <[email protected]>
Signed-off-by: Joonwoo Park <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl3945-base.c | 34 +++++++++++++++++++++++++-
drivers/net/wireless/iwlwifi/iwl4965-base.c | 32 +++++++++++++++++++++++-
2 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 02b4245..ed85db7 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -4153,6 +4153,16 @@ static void iwl3945_enable_interrupts(struct iwl3945_priv *priv)
iwl3945_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
}

+
+/* call this function to flush any scheduled tasklet */
+static inline void iwl_synchronize_irq(struct iwl3945_priv *priv)
+{
+ /* wait to make sure we flush pedding tasklet*/
+ synchronize_irq(priv->pci_dev->irq);
+ tasklet_kill(&priv->irq_tasklet);
+}
+
+
static inline void iwl3945_disable_interrupts(struct iwl3945_priv *priv)
{
clear_bit(STATUS_INT_ENABLED, &priv->status);
@@ -4552,7 +4562,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
}

/* Re-enable all interrupts */
- iwl3945_enable_interrupts(priv);
+ /* only Re-enable if disabled by irq */
+ if (test_bit(STATUS_INT_ENABLED, &priv->status))
+ iwl3945_enable_interrupts(priv);

#ifdef CONFIG_IWL3945_DEBUG
if (iwl3945_debug_level & (IWL_DL_ISR)) {
@@ -4616,7 +4628,9 @@ unplugged:

none:
/* re-enable interrupts here since we don't have anything to service. */
- iwl3945_enable_interrupts(priv);
+ /* only Re-enable if disabled by irq */
+ if (test_bit(STATUS_INT_ENABLED, &priv->status))
+ iwl3945_enable_interrupts(priv);
spin_unlock(&priv->lock);
return IRQ_NONE;
}
@@ -5906,7 +5920,10 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
iwl3945_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);

/* tell the device to stop sending interrupts */
+ spin_lock_irqsave(&priv->lock, flags);
iwl3945_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ iwl_synchronize_irq(priv);

if (priv->mac80211_registered)
ieee80211_stop_queues(priv->hw);
@@ -7944,6 +7961,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
struct ieee80211_hw *hw;
struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
int i;
+ unsigned long flags;
DECLARE_MAC_BUF(mac);

/* Disabling hardware scan means that mac80211 will perform scans
@@ -8094,7 +8112,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->power_mode = IWL_POWER_AC;
priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;

+ spin_lock_irqsave(&priv->lock, flags);
iwl3945_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);

err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
if (err) {
@@ -8181,6 +8201,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
struct iwl3945_priv *priv = pci_get_drvdata(pdev);
struct list_head *p, *q;
int i;
+ unsigned long flags;

if (!priv)
return;
@@ -8191,6 +8212,15 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)

iwl3945_down(priv);

+ /* make sure we flush any pending irq or
+ * tasklet for the driver
+ */
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl3945_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_synchronize_irq(priv);
+
/* Free MAC hash list for ADHOC */
for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 96daece..7f2dca3 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -4285,6 +4285,14 @@ static void iwl4965_enable_interrupts(struct iwl_priv *priv)
iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
}

+/* call this function to flush any scheduled tasklet */
+static inline void iwl_synchronize_irq(struct iwl_priv *priv)
+{
+ /* wait to make sure we flush pedding tasklet*/
+ synchronize_irq(priv->pci_dev->irq);
+ tasklet_kill(&priv->irq_tasklet);
+}
+
static inline void iwl4965_disable_interrupts(struct iwl_priv *priv)
{
clear_bit(STATUS_INT_ENABLED, &priv->status);
@@ -4668,7 +4676,9 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
}

/* Re-enable all interrupts */
- iwl4965_enable_interrupts(priv);
+ /* only Re-enable if diabled by irq */
+ if (test_bit(STATUS_INT_ENABLED, &priv->status))
+ iwl4965_enable_interrupts(priv);

#ifdef CONFIG_IWLWIFI_DEBUG
if (iwl_debug_level & (IWL_DL_ISR)) {
@@ -4733,7 +4743,9 @@ static irqreturn_t iwl4965_isr(int irq, void *data)

none:
/* re-enable interrupts here since we don't have anything to service. */
- iwl4965_enable_interrupts(priv);
+ /* only Re-enable if diabled by irq */
+ if (test_bit(STATUS_INT_ENABLED, &priv->status))
+ iwl4965_enable_interrupts(priv);
spin_unlock(&priv->lock);
return IRQ_NONE;
}
@@ -5773,7 +5785,10 @@ static void __iwl4965_down(struct iwl_priv *priv)
iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);

/* tell the device to stop sending interrupts */
+ spin_lock_irqsave(&priv->lock, flags);
iwl4965_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ iwl_synchronize_irq(priv);

if (priv->mac80211_registered)
ieee80211_stop_queues(priv->hw);
@@ -7997,6 +8012,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
struct iwl_priv *priv;
struct ieee80211_hw *hw;
struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
+ unsigned long flags;
DECLARE_MAC_BUF(mac);

/************************
@@ -8134,7 +8150,9 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
/********************
* 8. Setup services
********************/
+ spin_lock_irqsave(&priv->lock, flags);
iwl4965_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);

err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
if (err) {
@@ -8183,6 +8201,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
struct iwl_priv *priv = pci_get_drvdata(pdev);
struct list_head *p, *q;
int i;
+ unsigned long flags;

if (!priv)
return;
@@ -8193,6 +8212,15 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)

iwl4965_down(priv);

+ /* make sure we flush any pending irq or
+ * tasklet for the driver
+ */
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl4965_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_synchronize_irq(priv);
+
/* Free MAC hash list for ADHOC */
for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
--
1.5.3.4


2008-03-28 23:25:34

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 8/8] iwlwifi: Fix synchronous host command

From: Tomas Winkler <[email protected]>

This patch replaces static variable from send_cmd_sync
with flag in priv->status. It was used for reentrance protection
but clearly made it impossible to stuck more cards into the same machine

In addition it force check of return values of synchronous commands
commands that doesn't requires return value async commands have to be used

Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Yi Zhu <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-3945.h | 35 ++++++++++++++-------------
drivers/net/wireless/iwlwifi/iwl-4965.c | 8 +++---
drivers/net/wireless/iwlwifi/iwl-4965.h | 35 ++++++++++++++-------------
drivers/net/wireless/iwlwifi/iwl-core.h | 6 +++-
drivers/net/wireless/iwlwifi/iwl-hcmd.c | 8 +++---
drivers/net/wireless/iwlwifi/iwl3945-base.c | 8 +++---
6 files changed, 52 insertions(+), 48 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index d7ccf13..ac12269 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -401,23 +401,24 @@ struct iwl3945_rx_queue {
#define MIN_B_CHANNELS 1

#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
-#define STATUS_INT_ENABLED 1
-#define STATUS_RF_KILL_HW 2
-#define STATUS_RF_KILL_SW 3
-#define STATUS_INIT 4
-#define STATUS_ALIVE 5
-#define STATUS_READY 6
-#define STATUS_TEMPERATURE 7
-#define STATUS_GEO_CONFIGURED 8
-#define STATUS_EXIT_PENDING 9
-#define STATUS_IN_SUSPEND 10
-#define STATUS_STATISTICS 11
-#define STATUS_SCANNING 12
-#define STATUS_SCAN_ABORTING 13
-#define STATUS_SCAN_HW 14
-#define STATUS_POWER_PMI 15
-#define STATUS_FW_ERROR 16
-#define STATUS_CONF_PENDING 17
+#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
+#define STATUS_INT_ENABLED 2
+#define STATUS_RF_KILL_HW 3
+#define STATUS_RF_KILL_SW 4
+#define STATUS_INIT 5
+#define STATUS_ALIVE 6
+#define STATUS_READY 7
+#define STATUS_TEMPERATURE 8
+#define STATUS_GEO_CONFIGURED 9
+#define STATUS_EXIT_PENDING 10
+#define STATUS_IN_SUSPEND 11
+#define STATUS_STATISTICS 12
+#define STATUS_SCANNING 13
+#define STATUS_SCAN_ABORTING 14
+#define STATUS_SCAN_HW 15
+#define STATUS_POWER_PMI 16
+#define STATUS_FW_ERROR 17
+#define STATUS_CONF_PENDING 18

#define MAX_TID_COUNT 9

diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index add6311..51a1449 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -1314,8 +1314,8 @@ void iwl4965_chain_noise_reset(struct iwl_priv *priv)
cmd.diff_gain_a = 0;
cmd.diff_gain_b = 0;
cmd.diff_gain_c = 0;
- iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
- sizeof(cmd), &cmd);
+ iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
+ sizeof(cmd), &cmd, NULL);
msleep(4);
data->state = IWL_CHAIN_NOISE_ACCUMULATE;
IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
@@ -4563,8 +4563,8 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
/* Update the rate scaling for control frame Tx to AP */
link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_setting.bcast_sta_id;

- iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd),
- &link_cmd);
+ iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
+ sizeof(link_cmd), &link_cmd, NULL);
}

#ifdef CONFIG_IWL4965_HT
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index ca864fa..8c14e9a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -415,23 +415,24 @@ struct iwl4965_rx_queue {
#define MIN_B_CHANNELS 1

#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
-#define STATUS_INT_ENABLED 1
-#define STATUS_RF_KILL_HW 2
-#define STATUS_RF_KILL_SW 3
-#define STATUS_INIT 4
-#define STATUS_ALIVE 5
-#define STATUS_READY 6
-#define STATUS_TEMPERATURE 7
-#define STATUS_GEO_CONFIGURED 8
-#define STATUS_EXIT_PENDING 9
-#define STATUS_IN_SUSPEND 10
-#define STATUS_STATISTICS 11
-#define STATUS_SCANNING 12
-#define STATUS_SCAN_ABORTING 13
-#define STATUS_SCAN_HW 14
-#define STATUS_POWER_PMI 15
-#define STATUS_FW_ERROR 16
-#define STATUS_CONF_PENDING 17
+#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
+#define STATUS_INT_ENABLED 2
+#define STATUS_RF_KILL_HW 3
+#define STATUS_RF_KILL_SW 4
+#define STATUS_INIT 5
+#define STATUS_ALIVE 6
+#define STATUS_READY 7
+#define STATUS_TEMPERATURE 8
+#define STATUS_GEO_CONFIGURED 9
+#define STATUS_EXIT_PENDING 10
+#define STATUS_IN_SUSPEND 11
+#define STATUS_STATISTICS 12
+#define STATUS_SCANNING 13
+#define STATUS_SCAN_ABORTING 14
+#define STATUS_SCAN_HW 15
+#define STATUS_POWER_PMI 16
+#define STATUS_FW_ERROR 17
+#define STATUS_CONF_PENDING 18

#define MAX_TID_COUNT 9

diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 5efafe1..64f4df5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -138,9 +138,11 @@ int iwl_setup(struct iwl_priv *priv);
*****************************************************/

const char *get_cmd_string(u8 cmd);
-int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+int __must_check iwl_send_cmd_sync(struct iwl_priv *priv,
+ struct iwl_host_cmd *cmd);
int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
-int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data);
+int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id,
+ u16 len, const void *data);
int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
const void *data,
int (*callback)(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 51c9949..1f8c299 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -151,17 +151,17 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{
int cmd_idx;
int ret;
- static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */

BUG_ON(cmd->meta.flags & CMD_ASYNC);

/* A synchronous command can not have a callback set. */
BUG_ON(cmd->meta.u.callback != NULL);

- if (atomic_xchg(&entry, 1)) {
+ if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
IWL_ERROR("Error sending %s: Already sending a host command\n",
get_cmd_string(cmd->id));
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}

set_bit(STATUS_HCMD_ACTIVE, &priv->status);
@@ -231,7 +231,7 @@ fail:
cmd->meta.u.skb = NULL;
}
out:
- atomic_set(&entry, 0);
+ clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
return ret;
}
EXPORT_SYMBOL(iwl_send_cmd_sync);
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index af7233e..dc9ff50 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -733,17 +733,17 @@ static int iwl3945_send_cmd_sync(struct iwl3945_priv *priv, struct iwl3945_host_
{
int cmd_idx;
int ret;
- static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */

BUG_ON(cmd->meta.flags & CMD_ASYNC);

/* A synchronous command can not have a callback set. */
BUG_ON(cmd->meta.u.callback != NULL);

- if (atomic_xchg(&entry, 1)) {
+ if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
IWL_ERROR("Error sending %s: Already sending a host command\n",
get_cmd_string(cmd->id));
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}

set_bit(STATUS_HCMD_ACTIVE, &priv->status);
@@ -813,7 +813,7 @@ fail:
cmd->meta.u.skb = NULL;
}
out:
- atomic_set(&entry, 0);
+ clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
return ret;
}

--
1.5.3.4


2008-04-01 11:48:10

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/8] iwlwifi: hook iwlwifi with Linux rfkill


> +ifeq ($(CONFIG_IWLCORE_RFKILL),y)
> + iwlcore-objs += iwl-rfkill.o
> +endif

Btw, you should be able to rewrite that as

iwlcore-objs-$(CONFIG_IWLCORE_RFKILL) += iwl-rfkill.o

and make the Makefile much more concise.

johannes


Attachments:
signature.asc (828.00 B)
This is a digitally signed message part