#define VS
#endif
-#define IWLWIFI_VERSION "1.2.22k" VD VS
+#define IWLWIFI_VERSION "1.2.23k" VD VS
#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation"
#define DRV_VERSION IWLWIFI_VERSION
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
!(cmd->meta.flags & CMD_SIZE_HUGE));
+
+ if (iwl3945_is_rfkill(priv)) {
+ IWL_DEBUG_INFO("Not sending command - RF KILL");
+ return -EIO;
+ }
+
if (iwl3945_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
IWL_ERROR("No space for Tx\n");
return -ENOSPC;
return priv->ibss_beacon->len;
}
-static int iwl3945_rate_index_from_plcp(int plcp)
-{
- int i = 0;
-
- for (i = 0; i < IWL_RATE_COUNT; i++)
- if (iwl3945_rates[i].plcp == plcp)
- return i;
- return -1;
-}
-
static u8 iwl3945_rate_get_lowest_plcp(int rate_mask)
{
u8 i;
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
*
IWL_ERROR("Time out reading EEPROM[%d]", addr);
return -ETIMEDOUT;
}
- e[addr / 2] = le16_to_cpu(r >> 16);
+ e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
}
return 0;
goto drop_unlock;
}
- if (!priv->interface_id) {
- IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+ if (!priv->vif) {
+ IWL_DEBUG_DROP("Dropping - !priv->vif\n");
goto drop_unlock;
}
#endif
/* drop all data frame if we are not associated */
- if (!iwl3945_is_associated(priv) && !priv->assoc_id &&
+ if ((!iwl3945_is_associated(priv) ||
+ ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id)) &&
((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
goto drop_unlock;
}
}
-void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv,
- struct iwl3945_rx_mem_buffer *rxb,
- void *data, short len,
- struct ieee80211_rx_status *stats,
- u16 phy_flags)
-{
- struct iwl3945_rt_rx_hdr *iwl3945_rt;
-
- /* First cache any information we need before we overwrite
- * the information provided in the skb from the hardware */
- s8 signal = stats->ssi;
- s8 noise = 0;
- int rate = stats->rate;
- u64 tsf = stats->mactime;
- __le16 phy_flags_hw = cpu_to_le16(phy_flags);
-
- /* We received data from the HW, so stop the watchdog */
- if (len > IWL_RX_BUF_SIZE - sizeof(*iwl3945_rt)) {
- IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
- return;
- }
-
- /* copy the frame data to write after where the radiotap header goes */
- iwl3945_rt = (void *)rxb->skb->data;
- memmove(iwl3945_rt->payload, data, len);
-
- iwl3945_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- iwl3945_rt->rt_hdr.it_pad = 0; /* always good to zero */
-
- /* total header + data */
- iwl3945_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl3945_rt));
-
- /* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, sizeof(*iwl3945_rt) + len);
-
- /* Big bitfield of all the fields we provide in radiotap */
- iwl3945_rt->rt_hdr.it_present =
- cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
- (1 << IEEE80211_RADIOTAP_ANTENNA));
-
- /* Zero the flags, we'll add to them as we go */
- iwl3945_rt->rt_flags = 0;
-
- iwl3945_rt->rt_tsf = cpu_to_le64(tsf);
-
- /* Convert to dBm */
- iwl3945_rt->rt_dbmsignal = signal;
- iwl3945_rt->rt_dbmnoise = noise;
-
- /* Convert the channel frequency and set the flags */
- iwl3945_rt->rt_channelMHz = cpu_to_le16(stats->freq);
- if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
- iwl3945_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
- else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
- iwl3945_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
- else /* 802.11g */
- iwl3945_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
-
- rate = iwl3945_rate_index_from_plcp(rate);
- if (rate == -1)
- iwl3945_rt->rt_rate = 0;
- else
- iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee;
-
- /* antenna number */
- iwl3945_rt->rt_antenna =
- le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
-
- /* set the preamble flag if we have it */
- if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
- iwl3945_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
- IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
- stats->flag |= RX_FLAG_RADIOTAP;
- ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
- rxb->skb = NULL;
-}
-
-
#define IWL_PACKET_RETRY_TIME HZ
int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
struct sk_buff *beacon;
/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
- beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+ beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL);
if (!beacon) {
IWL_ERROR("update beacon failed\n");
* more buffers it will schedule replenish */
break;
}
+
+ /* If radiotap head is required, reserve some headroom here.
+ * The physical head count is a variable rx_stats->phy_count.
+ * We reserve 4 bytes here. Plus these extra bytes, the
+ * headroom of the physical head should be enough for the
+ * radiotap head that iwl3945 supported. See iwl3945_rt.
+ */
+ skb_reserve(rxb->skb, 4);
+
priv->alloc_rxb_skb++;
list_del(element);
* Conversion assumes that levels are voltages (20*log), not powers (10*log). */
int iwl3945_calc_db_from_ratio(int sig_ratio)
{
- /* Anything above 1000:1 just report as 60 dB */
- if (sig_ratio > 1000)
+ /* 1000:1 or higher just report as 60 dB */
+ if (sig_ratio >= 1000)
return 60;
- /* Above 100:1, divide by 10 and use table,
+ /* 100:1 or higher, divide by 10 and use table,
* add 20 dB to make up for divide by 10 */
- if (sig_ratio > 100)
+ if (sig_ratio >= 100)
return (20 + (int)ratio2dB[sig_ratio/10]);
/* We shouldn't see this */
int reclaim;
unsigned long flags;
u8 fill_rx = 0;
- u32 count = 0;
+ u32 count = 8;
/* uCode's read index (stored in shared DRAM) indicates the last Rx
* buffer that the driver may process (last buffer filled by ucode). */
#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)
}
#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) {
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);
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. */
scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
/* NOTE: if we were doing 6Mb OFDM for scans we'd use
* power level:
- * scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+ * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3;
*/
}
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
static void iwl3945_dealloc_ucode_pci(struct iwl3945_priv *priv)
{
- if (priv->ucode_code.v_addr != NULL) {
- pci_free_consistent(priv->pci_dev,
- priv->ucode_code.len,
- priv->ucode_code.v_addr,
- priv->ucode_code.p_addr);
- priv->ucode_code.v_addr = NULL;
- }
- if (priv->ucode_data.v_addr != NULL) {
- pci_free_consistent(priv->pci_dev,
- priv->ucode_data.len,
- priv->ucode_data.v_addr,
- priv->ucode_data.p_addr);
- priv->ucode_data.v_addr = NULL;
- }
- if (priv->ucode_data_backup.v_addr != NULL) {
- pci_free_consistent(priv->pci_dev,
- priv->ucode_data_backup.len,
- priv->ucode_data_backup.v_addr,
- priv->ucode_data_backup.p_addr);
- priv->ucode_data_backup.v_addr = NULL;
- }
- if (priv->ucode_init.v_addr != NULL) {
- pci_free_consistent(priv->pci_dev,
- priv->ucode_init.len,
- priv->ucode_init.v_addr,
- priv->ucode_init.p_addr);
- priv->ucode_init.v_addr = NULL;
- }
- if (priv->ucode_init_data.v_addr != NULL) {
- pci_free_consistent(priv->pci_dev,
- priv->ucode_init_data.len,
- priv->ucode_init_data.v_addr,
- priv->ucode_init_data.p_addr);
- priv->ucode_init_data.v_addr = NULL;
- }
- if (priv->ucode_boot.v_addr != NULL) {
- pci_free_consistent(priv->pci_dev,
- priv->ucode_boot.len,
- priv->ucode_boot.v_addr,
- priv->ucode_boot.p_addr);
- priv->ucode_boot.v_addr = NULL;
- }
+ iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
+ iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
+ iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
+ iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
+ iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+ iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
}
/**
iwl3945_write32(priv, CSR_RESET, 0);
}
-static int iwl3945_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc)
-{
- desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr);
- return (desc->v_addr != NULL) ? 0 : -ENOMEM;
-}
-
/**
* iwl3945_read_ucode - Read uCode images from disk file.
*
* 1) unmodified from disk
* 2) backup cache for save/restore during power-downs */
priv->ucode_code.len = inst_size;
- iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
+ iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
priv->ucode_data.len = data_size;
- iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
+ iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
priv->ucode_data_backup.len = data_size;
- iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
+ iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
!priv->ucode_data_backup.v_addr)
/* Initialization instructions and data */
if (init_size && init_data_size) {
priv->ucode_init.len = init_size;
- iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
+ iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
priv->ucode_init_data.len = init_data_size;
- iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+ iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
goto err_pci_alloc;
/* Bootstrap (instructions only, no data) */
if (boot_size) {
priv->ucode_boot.len = boot_size;
- iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
+ iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
if (!priv->ucode_boot.v_addr)
goto err_pci_alloc;
/* 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);
-
if (iwl3945_is_rfkill(priv))
return;
- if (!priv->mac80211_registered) {
- /* Unlock so any user space entry points can call back into
- * the driver without a deadlock... */
- mutex_unlock(&priv->mutex);
- iwl3945_rate_control_register(priv->hw);
- rc = ieee80211_register_hw(priv->hw);
- priv->hw->conf.beacon_int = 100;
- mutex_lock(&priv->mutex);
-
- if (rc) {
- iwl3945_rate_control_unregister(priv->hw);
- IWL_ERROR("Failed to register network "
- "device (error %d)\n", rc);
- return;
- }
-
- priv->mac80211_registered = 1;
-
- iwl3945_reset_channel_flag(priv);
- } else
- ieee80211_start_queues(priv->hw);
+ ieee80211_start_queues(priv->hw);
priv->active_rate = priv->rates_mask;
priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
iwl3945_reg_txpower_periodic(priv);
IWL_DEBUG_INFO("ALIVE processing complete.\n");
+ wake_up_interruptible(&priv->wait_command_queue);
if (priv->error_recovering)
iwl3945_error_recovery(priv);
STATUS_RF_KILL_HW |
test_bit(STATUS_RF_KILL_SW, &priv->status) <<
STATUS_RF_KILL_SW |
+ test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+ STATUS_GEO_CONFIGURED |
test_bit(STATUS_IN_SUSPEND, &priv->status) <<
STATUS_IN_SUSPEND;
goto exit;
STATUS_RF_KILL_HW |
test_bit(STATUS_RF_KILL_SW, &priv->status) <<
STATUS_RF_KILL_SW |
+ test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+ STATUS_GEO_CONFIGURED |
test_bit(STATUS_IN_SUSPEND, &priv->status) <<
STATUS_IN_SUSPEND |
test_bit(STATUS_FW_ERROR, &priv->status) <<
static int __iwl3945_up(struct iwl3945_priv *priv)
{
- DECLARE_MAC_BUF(mac);
int rc, i;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
IWL_WARNING("Radio disabled by SW RF kill (module "
"parameter)\n");
- return 0;
+ return -ENODEV;
}
if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
return -EIO;
}
+ /* If platform's RF_KILL switch is NOT set to KILL */
+ if (iwl3945_read32(priv, CSR_GP_CNTRL) &
+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+ else {
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+ if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
+ IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+ return -ENODEV;
+ }
+ }
+
iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
rc = iwl3945_hw_nic_init(priv);
* This will be used to initialize the on-board processor's
* data SRAM for a clean start when the runtime program first loads. */
memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
- priv->ucode_data.len);
+ priv->ucode_data.len);
+
+ /* We return success when we resume from suspend and rf_kill is on. */
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status))
+ return 0;
for (i = 0; i < MAX_HW_RESTARTS; i++) {
/* start card; "initialize" will load runtime ucode */
iwl3945_nic_start(priv);
- /* MAC Address location in EEPROM is same for 3945/4965 */
- get_eeprom_mac(priv, priv->mac_addr);
- IWL_DEBUG_INFO("MAC address: %s\n",
- print_mac(mac, priv->mac_addr));
-
- SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
-
IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
return 0;
* that based on the direct_mask added to each channel entry */
scan->tx_cmd.len = cpu_to_le16(
iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
- IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
+ IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
mutex_lock(&priv->mutex);
- if (!priv->interface_id || !priv->is_open) {
+ if (!priv->vif || !priv->is_open) {
mutex_unlock(&priv->mutex);
return;
}
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- if (priv->cache_conf)
- iwl3945_mac_config(priv->hw, priv->cache_conf);
+ if (test_bit(STATUS_CONF_PENDING, &priv->status))
+ iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
ieee80211_scan_completed(priv->hw);
*
*****************************************************************************/
+#define UCODE_READY_TIMEOUT (2 * HZ)
+
static int iwl3945_mac_start(struct ieee80211_hw *hw)
{
struct iwl3945_priv *priv = hw->priv;
+ int ret;
IWL_DEBUG_MAC80211("enter\n");
+ if (pci_enable_device(priv->pci_dev)) {
+ IWL_ERROR("Fail to pci_enable_device\n");
+ return -ENODEV;
+ }
+ pci_restore_state(priv->pci_dev);
+ pci_enable_msi(priv->pci_dev);
+
+ ret = request_irq(priv->pci_dev->irq, iwl3945_isr, IRQF_SHARED,
+ DRV_NAME, priv);
+ if (ret) {
+ IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq);
+ goto out_disable_msi;
+ }
+
/* we should be verifying the device is ready to be opened */
mutex_lock(&priv->mutex);
- priv->is_open = 1;
+ memset(&priv->staging_rxon, 0, sizeof(struct iwl3945_rxon_cmd));
+ /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+ * ucode filename and max sizes are card-specific. */
- if (!iwl3945_is_rfkill(priv))
- ieee80211_start_queues(priv->hw);
+ if (!priv->ucode_code.len) {
+ ret = iwl3945_read_ucode(priv);
+ if (ret) {
+ IWL_ERROR("Could not read microcode: %d\n", ret);
+ mutex_unlock(&priv->mutex);
+ goto out_release_irq;
+ }
+ }
+
+ ret = __iwl3945_up(priv);
mutex_unlock(&priv->mutex);
+
+ if (ret)
+ goto out_release_irq;
+
+ IWL_DEBUG_INFO("Start UP work.\n");
+
+ if (test_bit(STATUS_IN_SUSPEND, &priv->status))
+ return 0;
+
+ /* Wait for START_ALIVE from ucode. Otherwise callbacks from
+ * mac80211 will not be run successfully. */
+ ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ test_bit(STATUS_READY, &priv->status),
+ UCODE_READY_TIMEOUT);
+ if (!ret) {
+ if (!test_bit(STATUS_READY, &priv->status)) {
+ IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n",
+ jiffies_to_msecs(UCODE_READY_TIMEOUT));
+ ret = -ETIMEDOUT;
+ goto out_release_irq;
+ }
+ }
+
+ priv->is_open = 1;
IWL_DEBUG_MAC80211("leave\n");
return 0;
+
+out_release_irq:
+ free_irq(priv->pci_dev->irq, priv);
+out_disable_msi:
+ pci_disable_msi(priv->pci_dev);
+ pci_disable_device(priv->pci_dev);
+ priv->is_open = 0;
+ IWL_DEBUG_MAC80211("leave - failed\n");
+ return ret;
}
static void iwl3945_mac_stop(struct ieee80211_hw *hw)
IWL_DEBUG_MAC80211("enter\n");
+ if (!priv->is_open) {
+ IWL_DEBUG_MAC80211("leave - skip\n");
+ return;
+ }
- mutex_lock(&priv->mutex);
- /* stop mac, cancel any scan request and clear
- * RXON_FILTER_ASSOC_MSK BIT
- */
priv->is_open = 0;
- if (!iwl3945_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211("leave - RF not ready\n");
+
+ if (iwl3945_is_ready_rf(priv)) {
+ /* stop mac, cancel any scan request and clear
+ * RXON_FILTER_ASSOC_MSK BIT
+ */
+ mutex_lock(&priv->mutex);
+ iwl3945_scan_cancel_timeout(priv, 100);
+ cancel_delayed_work(&priv->post_associate);
mutex_unlock(&priv->mutex);
- return;
}
- iwl3945_scan_cancel_timeout(priv, 100);
- cancel_delayed_work(&priv->post_associate);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl3945_commit_rxon(priv);
- mutex_unlock(&priv->mutex);
+ iwl3945_down(priv);
+
+ flush_workqueue(priv->workqueue);
+ free_irq(priv->pci_dev->irq, priv);
+ pci_disable_msi(priv->pci_dev);
+ pci_save_state(priv->pci_dev);
+ pci_disable_device(priv->pci_dev);
IWL_DEBUG_MAC80211("leave\n");
}
unsigned long flags;
DECLARE_MAC_BUF(mac);
- IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+ IWL_DEBUG_MAC80211("enter: type %d\n", conf->type);
- if (priv->interface_id) {
- IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+ if (priv->vif) {
+ IWL_DEBUG_MAC80211("leave - vif != NULL\n");
return -EOPNOTSUPP;
}
spin_lock_irqsave(&priv->lock, flags);
- priv->interface_id = conf->if_id;
+ priv->vif = conf->vif;
spin_unlock_irqrestore(&priv->lock, flags);
memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
}
- iwl3945_set_mode(priv, conf->type);
+ if (iwl3945_is_ready(priv))
+ iwl3945_set_mode(priv, conf->type);
- IWL_DEBUG_MAC80211("leave\n");
mutex_unlock(&priv->mutex);
+ IWL_DEBUG_MAC80211("leave\n");
return 0;
}
mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+ priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
if (!iwl3945_is_ready(priv)) {
IWL_DEBUG_MAC80211("leave - not ready\n");
ret = -EIO;
goto out;
}
- /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
- * what is exposed through include/ declarations */
if (unlikely(!iwl3945_param_disable_hw_scan &&
test_bit(STATUS_SCANNING, &priv->status))) {
-
- if (priv->cache_conf)
- IWL_DEBUG_MAC80211("leave - still scanning\n");
- else {
- /* Cache the configuration now so that we can
- * replay it after the hardware scan is finished. */
- priv->cache_conf = kmalloc(sizeof(*conf), GFP_KERNEL);
- if (priv->cache_conf) {
- memcpy(priv->cache_conf, conf, sizeof(*conf));
- IWL_DEBUG_MAC80211("leave - scanning\n");
- } else {
- IWL_DEBUG_MAC80211("leave - no memory\n");
- ret = -ENOMEM;
- }
- }
+ IWL_DEBUG_MAC80211("leave - scanning\n");
+ set_bit(STATUS_CONF_PENDING, &priv->status);
mutex_unlock(&priv->mutex);
- return ret;
+ return 0;
}
spin_lock_irqsave(&priv->lock, flags);
IWL_DEBUG_MAC80211("leave\n");
out:
- if (priv->cache_conf) {
- kfree(priv->cache_conf);
- priv->cache_conf = NULL;
- }
+ clear_bit(STATUS_CONF_PENDING, &priv->status);
mutex_unlock(&priv->mutex);
return ret;
}
{
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 */
* clear sta table, add BCAST sta... */
}
-static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
{
struct iwl3945_priv *priv = hw->priv;
return 0;
}
+ if (!iwl3945_is_alive(priv))
+ return -EAGAIN;
+
mutex_lock(&priv->mutex);
- IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
if (conf->bssid)
IWL_DEBUG_MAC80211("bssid: %s\n",
print_mac(mac, conf->bssid));
return 0;
}
- if (priv->interface_id != if_id) {
- IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+ if (priv->vif != vif) {
+ IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
mutex_unlock(&priv->mutex);
return 0;
}
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
iwl3945_commit_rxon(priv);
}
- if (priv->interface_id == conf->if_id) {
- priv->interface_id = 0;
+ if (priv->vif == conf->vif) {
+ priv->vif = NULL;
memset(priv->bssid, 0, ETH_ALEN);
memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
priv->essid_len = 0;
mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211("leave\n");
-
}
static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
struct iwl3945_priv *priv;
struct ieee80211_hw *hw;
int i;
+ DECLARE_MAC_BUF(mac);
/* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */
/* Device-specific setup */
if (iwl3945_hw_set_hw_setting(priv)) {
IWL_ERROR("failed to set hw settings\n");
- mutex_unlock(&priv->mutex);
goto out_iounmap;
}
iwl3945_disable_interrupts(priv);
- pci_enable_msi(pdev);
-
- err = request_irq(pdev->irq, iwl3945_isr, IRQF_SHARED, DRV_NAME, priv);
- if (err) {
- IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
- goto out_disable_msi;
- }
-
- mutex_lock(&priv->mutex);
-
err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
if (err) {
IWL_ERROR("failed to create sysfs device attributes\n");
- mutex_unlock(&priv->mutex);
goto out_release_irq;
}
- /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
- * ucode filename and max sizes are card-specific. */
- err = iwl3945_read_ucode(priv);
+ /* nic init */
+ iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+ iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ err = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (err < 0) {
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ goto out_remove_sysfs;
+ }
+ /* Read the EEPROM */
+ err = iwl3945_eeprom_init(priv);
if (err) {
- IWL_ERROR("Could not read microcode: %d\n", err);
- mutex_unlock(&priv->mutex);
- goto out_pci_alloc;
+ IWL_ERROR("Unable to init EEPROM\n");
+ goto out_remove_sysfs;
}
+ /* MAC Address location in EEPROM same for 3945/4965 */
+ get_eeprom_mac(priv, priv->mac_addr);
+ IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
+ SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
- mutex_unlock(&priv->mutex);
+ err = iwl3945_init_channel_map(priv);
+ if (err) {
+ IWL_ERROR("initializing regulatory failed: %d\n", err);
+ goto out_remove_sysfs;
+ }
- IWL_DEBUG_INFO("Queueing UP work.\n");
+ 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);
- queue_work(priv->workqueue, &priv->up);
+ 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_free_geos;
+ }
- return 0;
+ priv->hw->conf.beacon_int = 100;
+ priv->mac80211_registered = 1;
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
- out_pci_alloc:
- iwl3945_dealloc_ucode_pci(priv);
+ 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);
out_release_irq:
- free_irq(pdev->irq, priv);
-
- out_disable_msi:
- pci_disable_msi(pdev);
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
iwl3945_unset_hw_setting(priv);
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
- free_irq(pdev->irq, priv);
- pci_disable_msi(pdev);
pci_iounmap(pdev, priv->hw_base);
pci_release_regions(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);
{
struct iwl3945_priv *priv = pci_get_drvdata(pdev);
- set_bit(STATUS_IN_SUSPEND, &priv->status);
-
- /* Take down the device; powers it off, etc. */
- iwl3945_down(priv);
-
- if (priv->mac80211_registered)
- ieee80211_stop_queues(priv->hw);
+ if (priv->is_open) {
+ set_bit(STATUS_IN_SUSPEND, &priv->status);
+ iwl3945_mac_stop(priv->hw);
+ priv->is_open = 1;
+ }
- pci_save_state(pdev);
- pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
-static void iwl3945_resume(struct iwl3945_priv *priv)
-{
- unsigned long flags;
-
- /* The following it a temporary work around due to the
- * suspend / resume not fully initializing the NIC correctly.
- * Without all of the following, resume will not attempt to take
- * down the NIC (it shouldn't really need to) and will just try
- * and bring the NIC back up. However that fails during the
- * ucode verification process. This then causes iwl3945_down to be
- * called *after* iwl3945_hw_nic_init() has succeeded -- which
- * then lets the next init sequence succeed. So, we've
- * replicated all of that NIC init code here... */
-
- iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
-
- iwl3945_hw_nic_init(priv);
-
- iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
- iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR,
- CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
- iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
- iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
- iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
- /* tell the device to stop sending interrupts */
- iwl3945_disable_interrupts(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
- iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
- if (!iwl3945_grab_nic_access(priv)) {
- iwl3945_write_prph(priv, APMG_CLK_DIS_REG,
- APMG_CLK_VAL_DMA_CLK_RQT);
- iwl3945_release_nic_access(priv);
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- udelay(5);
-
- iwl3945_hw_nic_reset(priv);
-
- /* Bring the device back up */
- clear_bit(STATUS_IN_SUSPEND, &priv->status);
- queue_work(priv->workqueue, &priv->up);
-}
-
static int iwl3945_pci_resume(struct pci_dev *pdev)
{
struct iwl3945_priv *priv = pci_get_drvdata(pdev);
- int err;
-
- printk(KERN_INFO "Coming out of suspend...\n");
pci_set_power_state(pdev, PCI_D0);
- err = pci_enable_device(pdev);
- pci_restore_state(pdev);
- /*
- * Suspend/Resume resets the PCI configuration space, so we have to
- * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
- * from interfering with C3 CPU state. pci_restore_state won't help
- * here since it only restores the first 64 bytes pci config header.
- */
- pci_write_config_byte(pdev, 0x41, 0x00);
-
- iwl3945_resume(priv);
+ if (priv->is_open)
+ iwl3945_mac_start(priv->hw);
+ clear_bit(STATUS_IN_SUSPEND, &priv->status);
return 0;
}