aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl4965-base.c
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2008-01-14 20:46:18 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:09:57 -0500
commit5a66926aa9230810704fd5a127966215fd58881e (patch)
tree347aa0458a71130357afcd89bb17a264cf728302 /drivers/net/wireless/iwlwifi/iwl4965-base.c
parent3058f02137359efb412975cf94a9fa7c25413387 (diff)
iwlwifi: delay firmware loading from pci_probe to network interface open
This patch moves the firmware loading (read firmware from disk and load it into the device SRAM) from pci_probe time to the first network interface open time. There are two reasons for doing this: 1. To support kernel buildin iwlwifi drivers. Because kernel initializes network devices subsystem before hard disk and SATA subsystem, it is impossible to get the firmware image from hard disk in the PCI probe handler. Thus delaying the firmware loading into the network interface open time is the way to go. Note, we only read the firmware image from hard disk the first time the interface is open. After this is succeeded, we cache the firmware image into the host memory. This is a performance gain when user open and close the interface multiple times and is necessary for device suspend and resume. 2. For better power saving. When the iwlwifi modules are loaded (or buildin the kernel) but the wireless network interface is not being used, it is a good practice the wireless device consumes as less power as possible. Unloading the firmware from the wireless device and unregister the driver's interrupt handler in the network interface close handler provides users a way to achieve this. User space network configuration tools (i.e NetworkManager) can also contribute here when it detects a wired cable is connected and close the wireless interface automatically. This patch also includes the pci_save/restore_state() fixed by Ian Schram upon the first version. Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: Ian Schram <ischram@telenet.be> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl4965-base.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c187
1 files changed, 110 insertions, 77 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index ad824c607f36..98f09e6e9f8c 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -6608,31 +6608,12 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv)
6608 } 6608 }
6609 6609
6610 iwl4965_init_geos(priv); 6610 iwl4965_init_geos(priv);
6611 iwl4965_reset_channel_flag(priv);
6611 6612
6612 if (iwl4965_is_rfkill(priv)) 6613 if (iwl4965_is_rfkill(priv))
6613 return; 6614 return;
6614 6615
6615 if (!priv->mac80211_registered) { 6616 ieee80211_start_queues(priv->hw);
6616 /* Unlock so any user space entry points can call back into
6617 * the driver without a deadlock... */
6618 mutex_unlock(&priv->mutex);
6619 iwl4965_rate_control_register(priv->hw);
6620 rc = ieee80211_register_hw(priv->hw);
6621 priv->hw->conf.beacon_int = 100;
6622 mutex_lock(&priv->mutex);
6623
6624 if (rc) {
6625 iwl4965_rate_control_unregister(priv->hw);
6626 IWL_ERROR("Failed to register network "
6627 "device (error %d)\n", rc);
6628 return;
6629 }
6630
6631 priv->mac80211_registered = 1;
6632
6633 iwl4965_reset_channel_flag(priv);
6634 } else
6635 ieee80211_start_queues(priv->hw);
6636 6617
6637 priv->active_rate = priv->rates_mask; 6618 priv->active_rate = priv->rates_mask;
6638 priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; 6619 priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
@@ -6663,7 +6644,9 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv)
6663 set_bit(STATUS_READY, &priv->status); 6644 set_bit(STATUS_READY, &priv->status);
6664 6645
6665 iwl4965_rf_kill_ct_config(priv); 6646 iwl4965_rf_kill_ct_config(priv);
6647
6666 IWL_DEBUG_INFO("ALIVE processing complete.\n"); 6648 IWL_DEBUG_INFO("ALIVE processing complete.\n");
6649 wake_up_interruptible(&priv->wait_command_queue);
6667 6650
6668 if (priv->error_recovering) 6651 if (priv->error_recovering)
6669 iwl4965_error_recovery(priv); 6652 iwl4965_error_recovery(priv);
@@ -6777,7 +6760,6 @@ static void iwl4965_down(struct iwl4965_priv *priv)
6777 6760
6778static int __iwl4965_up(struct iwl4965_priv *priv) 6761static int __iwl4965_up(struct iwl4965_priv *priv)
6779{ 6762{
6780 DECLARE_MAC_BUF(mac);
6781 int rc, i; 6763 int rc, i;
6782 u32 hw_rf_kill = 0; 6764 u32 hw_rf_kill = 0;
6783 6765
@@ -6822,7 +6804,7 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
6822 * This will be used to initialize the on-board processor's 6804 * This will be used to initialize the on-board processor's
6823 * data SRAM for a clean start when the runtime program first loads. */ 6805 * data SRAM for a clean start when the runtime program first loads. */
6824 memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, 6806 memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
6825 priv->ucode_data.len); 6807 priv->ucode_data.len);
6826 6808
6827 /* If platform's RF_KILL switch is set to KILL, 6809 /* If platform's RF_KILL switch is set to KILL,
6828 * wait for BIT_INT_RF_KILL interrupt before loading uCode 6810 * wait for BIT_INT_RF_KILL interrupt before loading uCode
@@ -6853,13 +6835,6 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
6853 /* start card; "initialize" will load runtime ucode */ 6835 /* start card; "initialize" will load runtime ucode */
6854 iwl4965_nic_start(priv); 6836 iwl4965_nic_start(priv);
6855 6837
6856 /* MAC Address location in EEPROM is same for 3945/4965 */
6857 get_eeprom_mac(priv, priv->mac_addr);
6858 IWL_DEBUG_INFO("MAC address: %s\n",
6859 print_mac(mac, priv->mac_addr));
6860
6861 SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
6862
6863 IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); 6838 IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
6864 6839
6865 return 0; 6840 return 0;
@@ -7365,23 +7340,73 @@ static void iwl4965_bg_scan_completed(struct work_struct *work)
7365 * 7340 *
7366 *****************************************************************************/ 7341 *****************************************************************************/
7367 7342
7343#define UCODE_READY_TIMEOUT (2 * HZ)
7344
7368static int iwl4965_mac_start(struct ieee80211_hw *hw) 7345static int iwl4965_mac_start(struct ieee80211_hw *hw)
7369{ 7346{
7370 struct iwl4965_priv *priv = hw->priv; 7347 struct iwl4965_priv *priv = hw->priv;
7348 int ret;
7371 7349
7372 IWL_DEBUG_MAC80211("enter\n"); 7350 IWL_DEBUG_MAC80211("enter\n");
7373 7351
7352 if (pci_enable_device(priv->pci_dev)) {
7353 IWL_ERROR("Fail to pci_enable_device\n");
7354 return -ENODEV;
7355 }
7356 pci_restore_state(priv->pci_dev);
7357 pci_enable_msi(priv->pci_dev);
7358
7359 ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
7360 DRV_NAME, priv);
7361 if (ret) {
7362 IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq);
7363 goto out_disable_msi;
7364 }
7365
7374 /* we should be verifying the device is ready to be opened */ 7366 /* we should be verifying the device is ready to be opened */
7375 mutex_lock(&priv->mutex); 7367 mutex_lock(&priv->mutex);
7376 7368
7377 priv->is_open = 1; 7369 memset(&priv->staging_rxon, 0, sizeof(struct iwl4965_rxon_cmd));
7370 /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
7371 * ucode filename and max sizes are card-specific. */
7378 7372
7379 if (!iwl4965_is_rfkill(priv)) 7373 if (!priv->ucode_code.len) {
7380 ieee80211_start_queues(priv->hw); 7374 ret = iwl4965_read_ucode(priv);
7375 if (ret) {
7376 IWL_ERROR("Could not read microcode: %d\n", ret);
7377 mutex_unlock(&priv->mutex);
7378 goto out_release_irq;
7379 }
7380 }
7381 7381
7382 IWL_DEBUG_INFO("Start UP work.\n");
7383 __iwl4965_up(priv);
7384
7385 priv->is_open = 1;
7382 mutex_unlock(&priv->mutex); 7386 mutex_unlock(&priv->mutex);
7387
7388 /* Wait for START_ALIVE from ucode. Otherwise callbacks from
7389 * mac80211 will not be run successfully. */
7390 ret = wait_event_interruptible_timeout(priv->wait_command_queue,
7391 test_bit(STATUS_READY, &priv->status),
7392 UCODE_READY_TIMEOUT);
7393 if (!ret) {
7394 if (!test_bit(STATUS_READY, &priv->status)) {
7395 IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n",
7396 jiffies_to_msecs(UCODE_READY_TIMEOUT));
7397 ret = -ETIMEDOUT;
7398 goto out_release_irq;
7399 }
7400 }
7401
7383 IWL_DEBUG_MAC80211("leave\n"); 7402 IWL_DEBUG_MAC80211("leave\n");
7384 return 0; 7403 return 0;
7404
7405out_release_irq:
7406 free_irq(priv->pci_dev->irq, priv);
7407out_disable_msi:
7408 pci_disable_msi(priv->pci_dev);
7409 return ret;
7385} 7410}
7386 7411
7387static void iwl4965_mac_stop(struct ieee80211_hw *hw) 7412static void iwl4965_mac_stop(struct ieee80211_hw *hw)
@@ -7390,23 +7415,25 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
7390 7415
7391 IWL_DEBUG_MAC80211("enter\n"); 7416 IWL_DEBUG_MAC80211("enter\n");
7392 7417
7393
7394 mutex_lock(&priv->mutex);
7395 /* stop mac, cancel any scan request and clear 7418 /* stop mac, cancel any scan request and clear
7396 * RXON_FILTER_ASSOC_MSK BIT 7419 * RXON_FILTER_ASSOC_MSK BIT
7397 */ 7420 */
7398 priv->is_open = 0; 7421 priv->is_open = 0;
7399 if (!iwl4965_is_ready_rf(priv)) { 7422
7400 IWL_DEBUG_MAC80211("leave - RF not ready\n"); 7423 if (iwl4965_is_ready_rf(priv)) {
7424 mutex_lock(&priv->mutex);
7425 iwl4965_scan_cancel_timeout(priv, 100);
7426 cancel_delayed_work(&priv->post_associate);
7401 mutex_unlock(&priv->mutex); 7427 mutex_unlock(&priv->mutex);
7402 return;
7403 } 7428 }
7404 7429
7405 iwl4965_scan_cancel_timeout(priv, 100); 7430 iwl4965_down(priv);
7406 cancel_delayed_work(&priv->post_associate); 7431
7407 priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; 7432 flush_workqueue(priv->workqueue);
7408 iwl4965_commit_rxon(priv); 7433 free_irq(priv->pci_dev->irq, priv);
7409 mutex_unlock(&priv->mutex); 7434 pci_disable_msi(priv->pci_dev);
7435 pci_save_state(priv->pci_dev);
7436 pci_disable_device(priv->pci_dev);
7410 7437
7411 IWL_DEBUG_MAC80211("leave\n"); 7438 IWL_DEBUG_MAC80211("leave\n");
7412} 7439}
@@ -7458,11 +7485,13 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
7458 IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr)); 7485 IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr));
7459 memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); 7486 memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
7460 } 7487 }
7461 iwl4965_set_mode(priv, conf->type);
7462 7488
7463 IWL_DEBUG_MAC80211("leave\n"); 7489 if (iwl4965_is_ready(priv))
7490 iwl4965_set_mode(priv, conf->type);
7491
7464 mutex_unlock(&priv->mutex); 7492 mutex_unlock(&priv->mutex);
7465 7493
7494 IWL_DEBUG_MAC80211("leave\n");
7466 return 0; 7495 return 0;
7467} 7496}
7468 7497
@@ -7564,9 +7593,9 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
7564 7593
7565 IWL_DEBUG_MAC80211("leave\n"); 7594 IWL_DEBUG_MAC80211("leave\n");
7566 7595
7567 mutex_unlock(&priv->mutex);
7568out: 7596out:
7569 clear_bit(STATUS_CONF_PENDING, &priv->status); 7597 clear_bit(STATUS_CONF_PENDING, &priv->status);
7598 mutex_unlock(&priv->mutex);
7570 return ret; 7599 return ret;
7571} 7600}
7572 7601
@@ -7651,6 +7680,9 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
7651 return 0; 7680 return 0;
7652 } 7681 }
7653 7682
7683 if (!iwl4965_is_alive(priv))
7684 return -EAGAIN;
7685
7654 mutex_lock(&priv->mutex); 7686 mutex_lock(&priv->mutex);
7655 7687
7656 if (conf->bssid) 7688 if (conf->bssid)
@@ -8995,6 +9027,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
8995 struct iwl4965_priv *priv; 9027 struct iwl4965_priv *priv;
8996 struct ieee80211_hw *hw; 9028 struct ieee80211_hw *hw;
8997 int i; 9029 int i;
9030 DECLARE_MAC_BUF(mac);
8998 9031
8999 /* Disabling hardware scan means that mac80211 will perform scans 9032 /* Disabling hardware scan means that mac80211 will perform scans
9000 * "the hard way", rather than using device's scan. */ 9033 * "the hard way", rather than using device's scan. */
@@ -9136,7 +9169,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
9136 /* Device-specific setup */ 9169 /* Device-specific setup */
9137 if (iwl4965_hw_set_hw_setting(priv)) { 9170 if (iwl4965_hw_set_hw_setting(priv)) {
9138 IWL_ERROR("failed to set hw settings\n"); 9171 IWL_ERROR("failed to set hw settings\n");
9139 mutex_unlock(&priv->mutex);
9140 goto out_iounmap; 9172 goto out_iounmap;
9141 } 9173 }
9142 9174
@@ -9161,50 +9193,53 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
9161 9193
9162 iwl4965_disable_interrupts(priv); 9194 iwl4965_disable_interrupts(priv);
9163 9195
9164 pci_enable_msi(pdev);
9165
9166 err = request_irq(pdev->irq, iwl4965_isr, IRQF_SHARED, DRV_NAME, priv);
9167 if (err) {
9168 IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
9169 goto out_disable_msi;
9170 }
9171
9172 mutex_lock(&priv->mutex);
9173
9174 err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); 9196 err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
9175 if (err) { 9197 if (err) {
9176 IWL_ERROR("failed to create sysfs device attributes\n"); 9198 IWL_ERROR("failed to create sysfs device attributes\n");
9177 mutex_unlock(&priv->mutex);
9178 goto out_release_irq; 9199 goto out_release_irq;
9179 } 9200 }
9180 9201
9181 /* fetch ucode file from disk, alloc and copy to bus-master buffers ... 9202 /* nic init */
9182 * ucode filename and max sizes are card-specific. */ 9203 iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS,
9183 err = iwl4965_read_ucode(priv); 9204 CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
9205
9206 iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
9207 err = iwl4965_poll_bit(priv, CSR_GP_CNTRL,
9208 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
9209 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
9210 if (err < 0) {
9211 IWL_DEBUG_INFO("Failed to init the card\n");
9212 goto out_remove_sysfs;
9213 }
9214 /* Read the EEPROM */
9215 err = iwl4965_eeprom_init(priv);
9184 if (err) { 9216 if (err) {
9185 IWL_ERROR("Could not read microcode: %d\n", err); 9217 IWL_ERROR("Unable to init EEPROM\n");
9186 mutex_unlock(&priv->mutex); 9218 goto out_remove_sysfs;
9187 goto out_pci_alloc;
9188 } 9219 }
9220 /* MAC Address location in EEPROM same for 3945/4965 */
9221 get_eeprom_mac(priv, priv->mac_addr);
9222 IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
9223 SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
9189 9224
9190 mutex_unlock(&priv->mutex); 9225 iwl4965_rate_control_register(priv->hw);
9191 9226 err = ieee80211_register_hw(priv->hw);
9192 IWL_DEBUG_INFO("Queueing UP work.\n"); 9227 if (err) {
9228 IWL_ERROR("Failed to register network device (error %d)\n", err);
9229 goto out_remove_sysfs;
9230 }
9193 9231
9194 queue_work(priv->workqueue, &priv->up); 9232 priv->hw->conf.beacon_int = 100;
9233 priv->mac80211_registered = 1;
9234 pci_save_state(pdev);
9235 pci_disable_device(pdev);
9195 9236
9196 return 0; 9237 return 0;
9197 9238
9198 out_pci_alloc: 9239 out_remove_sysfs:
9199 iwl4965_dealloc_ucode_pci(priv);
9200
9201 sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); 9240 sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
9202 9241
9203 out_release_irq: 9242 out_release_irq:
9204 free_irq(pdev->irq, priv);
9205
9206 out_disable_msi:
9207 pci_disable_msi(pdev);
9208 destroy_workqueue(priv->workqueue); 9243 destroy_workqueue(priv->workqueue);
9209 priv->workqueue = NULL; 9244 priv->workqueue = NULL;
9210 iwl4965_unset_hw_setting(priv); 9245 iwl4965_unset_hw_setting(priv);
@@ -9270,8 +9305,6 @@ static void iwl4965_pci_remove(struct pci_dev *pdev)
9270 destroy_workqueue(priv->workqueue); 9305 destroy_workqueue(priv->workqueue);
9271 priv->workqueue = NULL; 9306 priv->workqueue = NULL;
9272 9307
9273 free_irq(pdev->irq, priv);
9274 pci_disable_msi(pdev);
9275 pci_iounmap(pdev, priv->hw_base); 9308 pci_iounmap(pdev, priv->hw_base);
9276 pci_release_regions(pdev); 9309 pci_release_regions(pdev);
9277 pci_disable_device(pdev); 9310 pci_disable_device(pdev);