2008-01-23 18:15:22

by Reinette Chatre

[permalink] [raw]
Subject: iwlwifi driver updates

This series containa few updates to the iwlwifi driver.

[PATCH] iwlwifi: Fix an invalid bitmask test in iwl3945 and iwl4965
[PATCH] iwl4965: fix return code indicating one interface is supported
[PATCH] iwlwifi: initialize geo/channel information during probe
[PATCH] iwlwifi: cleanup usage of inline functions
[PATCH] iwlwifi: do not schedule tasklet when rcv unused irq
[PATCH] iwlwifi: Fix uCode error on association


Thank you

Reinette


2008-01-23 18:15:24

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH] iwlwifi: Fix uCode error on association

From: Gregory Greenman <[email protected]>

The problem is that priv->assoc_id is set when assoc. resp frame is
received. But, when it is set, LQ cmd is still not sent to the uCode, it is
done from bg_post_assoc, which is called through a workqueue.

On the other hand, when a tx arrives at the moment when this flag is set,
but LQ is still not sent, the if condition in tx_skb will not hold and
the frame will not be dropped. Thus, it will be sent through
which is still not in the sta table in the uCoded.

Signed-off-by: Gregory Greenman <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-3945.h | 1 -
drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +-
drivers/net/wireless/iwlwifi/iwl4965-base.c | 6 ++++--
3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 4b07db9..1da14f9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -790,7 +790,6 @@ struct iwl3945_priv {
u16 active_rate_basic;

u8 call_post_assoc_from_beacon;
- u8 assoc_station_added;
/* Rate scaling data */
s8 data_retry_limit;
u8 retry_rate;
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index ea24e7b..322ad04 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2806,7 +2806,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
#endif

/* drop all data frame if we are not associated */
- if (!iwl3945_is_associated(priv) && !priv->assoc_id &&
+ if ((!iwl3945_is_associated(priv) || !priv->assoc_id) &&
((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
goto drop_unlock;
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 2e82af1..8c58ab0 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -2933,8 +2933,10 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
#endif

/* drop all data frame if we are not associated */
- if (!iwl4965_is_associated(priv) && !priv->assoc_id &&
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+ (!iwl4965_is_associated(priv) ||
+ !priv->assoc_id ||
+ !priv->assoc_station_added)) {
IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n");
goto drop_unlock;
}
--
1.5.3.4


2008-01-23 18:15:23

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH] iwl4965: fix return code indicating one interface is supported

This is a fix to patch "iwlwifi: fix iwl_mac_add_interface handler".
In that patch the return code was corrected for iwl3945, but not for
iwl4965.


Signed-off-by: Reinette Chatre <[email protected]>
Cc: Tomas Carnecky <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index bcaaec2..13fe5a1 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -7448,7 +7448,7 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,

if (priv->vif) {
IWL_DEBUG_MAC80211("leave - vif != NULL\n");
- return 0;
+ return -EOPNOTSUPP;
}

spin_lock_irqsave(&priv->lock, flags);
--
1.5.3.4


2008-01-23 18:15:23

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH] iwlwifi: do not schedule tasklet when rcv unused irq

From: Joonwoo Park <[email protected]>

The nic controller's scheduler interrupt (CSR_INT_BIT_SCD) indicates
to the driver that scheduler finished to transmit the frame/frames.
This bit is not used and the tasklet should thus not be scheduled upon
its receipt.

Signed-off-by: Joonwoo Park <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 2 +-
drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 2 +-
drivers/net/wireless/iwlwifi/iwl3945-base.c | 12 ++++++++----
drivers/net/wireless/iwlwifi/iwl4965-base.c | 12 ++++++++----
4 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index e4e4a85..f0a390a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -373,7 +373,7 @@ struct iwl3945_eeprom {
#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */
#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */
#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */
-#define CSR_INT_BIT_MAC_CLK_ACTV (1 << 26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */
#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */
#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */
#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index ff71c09..ffe1e9d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -465,7 +465,7 @@ struct iwl4965_eeprom {
#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */
#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */
#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */
-#define CSR_INT_BIT_MAC_CLK_ACTV (1 << 26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */
#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */
#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */
#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 1e9e953..ea24e7b 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -4759,8 +4759,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
#ifdef CONFIG_IWL3945_DEBUG
if (iwl3945_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
- if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
- IWL_DEBUG_ISR("Microcode started or stopped.\n");
+ if (inta & CSR_INT_BIT_SCD)
+ IWL_DEBUG_ISR("Scheduler finished to transmit "
+ "the frame/frames.\n");

/* Alive notification via Rx interrupt will do the real work */
if (inta & CSR_INT_BIT_ALIVE)
@@ -4768,7 +4769,7 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
}
#endif
/* Safely ignore these bits for debug checks below */
- inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+ inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);

/* HW RF KILL switch toggled (4965 only) */
if (inta & CSR_INT_BIT_RF_KILL) {
@@ -4904,8 +4905,11 @@ static irqreturn_t iwl3945_isr(int irq, void *data)
IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
inta, inta_mask, inta_fh);

+ inta &= ~CSR_INT_BIT_SCD;
+
/* iwl3945_irq_tasklet() will service interrupts and re-enable them */
- tasklet_schedule(&priv->irq_tasklet);
+ if (likely(inta || inta_fh))
+ tasklet_schedule(&priv->irq_tasklet);
unplugged:
spin_unlock(&priv->lock);

diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 9f23c3f..2e82af1 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -5137,8 +5137,9 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
#ifdef CONFIG_IWL4965_DEBUG
if (iwl4965_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
- if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
- IWL_DEBUG_ISR("Microcode started or stopped.\n");
+ if (inta & CSR_INT_BIT_SCD)
+ IWL_DEBUG_ISR("Scheduler finished to transmit "
+ "the frame/frames.\n");

/* Alive notification via Rx interrupt will do the real work */
if (inta & CSR_INT_BIT_ALIVE)
@@ -5146,7 +5147,7 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
}
#endif
/* Safely ignore these bits for debug checks below */
- inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+ inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);

/* HW RF KILL switch toggled */
if (inta & CSR_INT_BIT_RF_KILL) {
@@ -5275,8 +5276,11 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
inta, inta_mask, inta_fh);

+ inta &= ~CSR_INT_BIT_SCD;
+
/* iwl4965_irq_tasklet() will service interrupts and re-enable them */
- tasklet_schedule(&priv->irq_tasklet);
+ if (likely(inta || inta_fh))
+ tasklet_schedule(&priv->irq_tasklet);

unplugged:
spin_unlock(&priv->lock);
--
1.5.3.4


2008-01-23 18:15:24

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH] iwlwifi: cleanup usage of inline functions

Be consistent when using inline functions. If the function only used
once we move it to where it is used - no need for externs.

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

diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 76c4ed1..4fdeb53 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -2369,18 +2369,4 @@ struct pci_device_id iwl3945_hw_card_ids[] = {
{0}
};

-/*
- * Clear the OWNER_MSK, to establish driver (instead of uCode running on
- * embedded controller) as EEPROM reader; each read is a series of pulses
- * to/from the EEPROM chip, not a single event, so even reads could conflict
- * if they weren't arbitrated by some ownership mechanism. Here, the driver
- * simply claims ownership, which should be safe when this function is called
- * (i.e. before loading uCode!).
- */
-inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv)
-{
- _iwl3945_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
- return 0;
-}
-
MODULE_DEVICE_TABLE(pci, iwl3945_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 20b925f..4b07db9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -671,7 +671,6 @@ extern int iwl3945_hw_channel_switch(struct iwl3945_priv *priv, u16 channel);
/*
* Forward declare iwl-3945.c functions for iwl-base.c
*/
-extern int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv);
extern __le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv);
extern int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv);
extern void iwl3945_reg_txpower_periodic(struct iwl3945_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 04db34b..569347f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -4961,11 +4961,4 @@ int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv)
return rc;
}

-inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
-{
- iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-}
-
-
MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index 78bc148..9cb82be 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -750,7 +750,6 @@ struct iwl4965_priv;
* Forward declare iwl-4965.c functions for iwl-base.c
*/
extern int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv);
-extern void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv);

extern int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv,
struct iwl4965_tx_queue *txq,
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 5afc578..1e9e953 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -1557,6 +1557,20 @@ static void get_eeprom_mac(struct iwl3945_priv *priv, u8 *mac)
memcpy(mac, priv->eeprom.mac_address, 6);
}

+/*
+ * Clear the OWNER_MSK, to establish driver (instead of uCode running on
+ * embedded controller) as EEPROM reader; each read is a series of pulses
+ * to/from the EEPROM chip, not a single event, so even reads could conflict
+ * if they weren't arbitrated by some ownership mechanism. Here, the driver
+ * simply claims ownership, which should be safe when this function is called
+ * (i.e. before loading uCode!).
+ */
+static inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv)
+{
+ _iwl3945_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
+ return 0;
+}
+
/**
* iwl3945_eeprom_init - read EEPROM contents
*
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index bb2d4f5..9f23c3f 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -1639,6 +1639,12 @@ static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac)
memcpy(mac, priv->eeprom.mac_address, 6);
}

+static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
+{
+ iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+}
+
/**
* iwl4965_eeprom_init - read EEPROM contents
*
--
1.5.3.4


2008-01-23 18:15:23

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH] iwlwifi: Fix an invalid bitmask test in iwl3945 and iwl4965

From: Maarten Lankhorst <[email protected]>

Signed-off-by: Maarten Lankhorst <[email protected]>
Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +-
drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 61f9eb7..c9f2ce5 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -7120,7 +7120,7 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv)
{
int rc = 0;

- if (priv->status & STATUS_EXIT_PENDING)
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;

/* The following should be done only at AP bring up */
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 04217e9..bcaaec2 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -7580,7 +7580,7 @@ static void iwl4965_config_ap(struct iwl4965_priv *priv)
{
int rc = 0;

- if (priv->status & STATUS_EXIT_PENDING)
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;

/* The following should be done only at AP bring up */
--
1.5.3.4


2008-01-23 18:15:24

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH] iwlwifi: initialize geo/channel information during probe

The geo/channel information is obtained from the EEPROM, which is read
during probe. We can thus set up channel information at this time. This
helps us to support ioctl commands that rely on this before the interface
is brought up.

Clearly matches _init_channel_map with _free_channel_map and _init_geos
with _free_geos to ensure functions calling these routines can also call
their cleanup routines.

Fixes a few bugs:
- if channel information is not available when ioctl commands are
issued then we get a NULL pointer oops. Having channel information
set up during probe we can deal with ioctl commands without requiring
interface to be brought up.
This fixes bug: http://www.bughost.org/bugzilla/show_bug.cgi?id=1552
- Fix potential problem if user triggers probe/remove/probe sequence. The
value of priv->channel_count was used to determine if channel map is
set up. This value was never reset when channel map was removed.
- Fix memory leak: priv->modes need to be freed when device removed.

Signed-off-by: Reinette Chatre <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl3945-base.c | 54 ++++++++++++++++++++-------
drivers/net/wireless/iwlwifi/iwl4965-base.c | 54 ++++++++++++++++++++-------
2 files changed, 80 insertions(+), 28 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index c9f2ce5..5afc578 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -5146,6 +5146,15 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv)
return 0;
}

+/*
+ * iwl3945_free_channel_map - undo allocations in iwl3945_init_channel_map
+ */
+static void iwl3945_free_channel_map(struct iwl3945_priv *priv)
+{
+ kfree(priv->channel_info);
+ priv->channel_count = 0;
+}
+
/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
* sending probe req. This should be set long enough to hear probe responses
* from more than one AP. */
@@ -5471,6 +5480,17 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv)
return 0;
}

+/*
+ * iwl3945_free_geos - undo allocations in iwl3945_init_geos
+ */
+static void iwl3945_free_geos(struct iwl3945_priv *priv)
+{
+ kfree(priv->modes);
+ kfree(priv->ieee_channels);
+ kfree(priv->ieee_rates);
+ clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+}
+
/******************************************************************************
*
* uCode download functions
@@ -6130,15 +6150,6 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
/* Clear out the uCode error bit if it is set */
clear_bit(STATUS_FW_ERROR, &priv->status);

- rc = iwl3945_init_channel_map(priv);
- if (rc) {
- IWL_ERROR("initializing regulatory failed: %d\n", rc);
- return;
- }
-
- iwl3945_init_geos(priv);
- iwl3945_reset_channel_flag(priv);
-
if (iwl3945_is_rfkill(priv))
return;

@@ -8614,11 +8625,24 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);

+ err = iwl3945_init_channel_map(priv);
+ if (err) {
+ IWL_ERROR("initializing regulatory failed: %d\n", err);
+ goto out_remove_sysfs;
+ }
+
+ err = iwl3945_init_geos(priv);
+ if (err) {
+ IWL_ERROR("initializing geos failed: %d\n", err);
+ goto out_free_channel_map;
+ }
+ iwl3945_reset_channel_flag(priv);
+
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);
- goto out_remove_sysfs;
+ goto out_free_geos;
}

priv->hw->conf.beacon_int = 100;
@@ -8628,6 +8652,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e

return 0;

+ out_free_geos:
+ iwl3945_free_geos(priv);
+ out_free_channel_map:
+ iwl3945_free_channel_map(priv);
out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);

@@ -8702,10 +8730,8 @@ static void iwl3945_pci_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);

- kfree(priv->channel_info);
-
- kfree(priv->ieee_channels);
- kfree(priv->ieee_rates);
+ iwl3945_free_channel_map(priv);
+ iwl3945_free_geos(priv);

if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 13fe5a1..bb2d4f5 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -5576,6 +5576,15 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
return 0;
}

+/*
+ * iwl4965_free_channel_map - undo allocations in iwl4965_init_channel_map
+ */
+static void iwl4965_free_channel_map(struct iwl4965_priv *priv)
+{
+ kfree(priv->channel_info);
+ priv->channel_count = 0;
+}
+
/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
* sending probe req. This should be set long enough to hear probe responses
* from more than one AP. */
@@ -5909,6 +5918,17 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv)
return 0;
}

+/*
+ * iwl4965_free_geos - undo allocations in iwl4965_init_geos
+ */
+static void iwl4965_free_geos(struct iwl4965_priv *priv)
+{
+ kfree(priv->modes);
+ kfree(priv->ieee_channels);
+ kfree(priv->ieee_rates);
+ clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+}
+
/******************************************************************************
*
* uCode download functions
@@ -6560,15 +6580,6 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv)
/* Clear out the uCode error bit if it is set */
clear_bit(STATUS_FW_ERROR, &priv->status);

- rc = iwl4965_init_channel_map(priv);
- if (rc) {
- IWL_ERROR("initializing regulatory failed: %d\n", rc);
- return;
- }
-
- iwl4965_init_geos(priv);
- iwl4965_reset_channel_flag(priv);
-
if (iwl4965_is_rfkill(priv))
return;

@@ -9198,11 +9209,24 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);

+ err = iwl4965_init_channel_map(priv);
+ if (err) {
+ IWL_ERROR("initializing regulatory failed: %d\n", err);
+ goto out_remove_sysfs;
+ }
+
+ err = iwl4965_init_geos(priv);
+ if (err) {
+ IWL_ERROR("initializing geos failed: %d\n", err);
+ goto out_free_channel_map;
+ }
+ iwl4965_reset_channel_flag(priv);
+
iwl4965_rate_control_register(priv->hw);
err = ieee80211_register_hw(priv->hw);
if (err) {
IWL_ERROR("Failed to register network device (error %d)\n", err);
- goto out_remove_sysfs;
+ goto out_free_geos;
}

priv->hw->conf.beacon_int = 100;
@@ -9212,6 +9236,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e

return 0;

+ out_free_geos:
+ iwl4965_free_geos(priv);
+ out_free_channel_map:
+ iwl4965_free_channel_map(priv);
out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);

@@ -9286,10 +9314,8 @@ static void iwl4965_pci_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);

- kfree(priv->channel_info);
-
- kfree(priv->ieee_channels);
- kfree(priv->ieee_rates);
+ iwl4965_free_channel_map(priv);
+ iwl4965_free_geos(priv);

if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
--
1.5.3.4