Commit 534f0e29 authored by John W. Linville's avatar John W. Linville

Merge branch 'wireless-next-2.6' of...

Merge branch 'wireless-next-2.6' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-2.6
parents e55034e9 4cd2bf76
...@@ -483,8 +483,6 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv) ...@@ -483,8 +483,6 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv)
/* init calibration handlers */ /* init calibration handlers */
priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
iwlagn_rx_calib_result; iwlagn_rx_calib_result;
priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
iwlagn_rx_calib_complete;
priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
/* set up notification wait support */ /* set up notification wait support */
...@@ -2256,34 +2254,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) ...@@ -2256,34 +2254,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
/* notification wait support */ /* notification wait support */
void iwlagn_init_notification_wait(struct iwl_priv *priv, void iwlagn_init_notification_wait(struct iwl_priv *priv,
struct iwl_notification_wait *wait_entry, struct iwl_notification_wait *wait_entry,
u8 cmd,
void (*fn)(struct iwl_priv *priv, void (*fn)(struct iwl_priv *priv,
struct iwl_rx_packet *pkt), struct iwl_rx_packet *pkt,
u8 cmd) void *data),
void *fn_data)
{ {
wait_entry->fn = fn; wait_entry->fn = fn;
wait_entry->fn_data = fn_data;
wait_entry->cmd = cmd; wait_entry->cmd = cmd;
wait_entry->triggered = false; wait_entry->triggered = false;
wait_entry->aborted = false;
spin_lock_bh(&priv->_agn.notif_wait_lock); spin_lock_bh(&priv->_agn.notif_wait_lock);
list_add(&wait_entry->list, &priv->_agn.notif_waits); list_add(&wait_entry->list, &priv->_agn.notif_waits);
spin_unlock_bh(&priv->_agn.notif_wait_lock); spin_unlock_bh(&priv->_agn.notif_wait_lock);
} }
signed long iwlagn_wait_notification(struct iwl_priv *priv, int iwlagn_wait_notification(struct iwl_priv *priv,
struct iwl_notification_wait *wait_entry, struct iwl_notification_wait *wait_entry,
unsigned long timeout) unsigned long timeout)
{ {
int ret; int ret;
ret = wait_event_timeout(priv->_agn.notif_waitq, ret = wait_event_timeout(priv->_agn.notif_waitq,
wait_entry->triggered, wait_entry->triggered || wait_entry->aborted,
timeout); timeout);
spin_lock_bh(&priv->_agn.notif_wait_lock); spin_lock_bh(&priv->_agn.notif_wait_lock);
list_del(&wait_entry->list); list_del(&wait_entry->list);
spin_unlock_bh(&priv->_agn.notif_wait_lock); spin_unlock_bh(&priv->_agn.notif_wait_lock);
return ret; if (wait_entry->aborted)
return -EIO;
/* return value is always >= 0 */
if (ret <= 0)
return -ETIMEDOUT;
return 0;
} }
void iwlagn_remove_notification(struct iwl_priv *priv, void iwlagn_remove_notification(struct iwl_priv *priv,
...@@ -2293,3 +2301,78 @@ void iwlagn_remove_notification(struct iwl_priv *priv, ...@@ -2293,3 +2301,78 @@ void iwlagn_remove_notification(struct iwl_priv *priv,
list_del(&wait_entry->list); list_del(&wait_entry->list);
spin_unlock_bh(&priv->_agn.notif_wait_lock); spin_unlock_bh(&priv->_agn.notif_wait_lock);
} }
int iwlagn_start_device(struct iwl_priv *priv)
{
int ret;
if (iwl_prepare_card_hw(priv)) {
IWL_WARN(priv, "Exit HW not ready\n");
return -EIO;
}
/* If platform's RF_KILL switch is NOT set to KILL */
if (iwl_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 (iwl_is_rfkill(priv)) {
wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
iwl_enable_interrupts(priv);
return -ERFKILL;
}
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
ret = iwlagn_hw_nic_init(priv);
if (ret) {
IWL_ERR(priv, "Unable to init nic\n");
return ret;
}
/* make sure rfkill handshake bits are cleared */
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
/* clear (again), then enable host interrupts */
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
iwl_enable_interrupts(priv);
/* really make sure rfkill handshake bits are cleared */
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
return 0;
}
void iwlagn_stop_device(struct iwl_priv *priv)
{
unsigned long flags;
/* stop and reset the on-board processor */
iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
/* tell the device to stop sending interrupts */
spin_lock_irqsave(&priv->lock, flags);
iwl_disable_interrupts(priv);
spin_unlock_irqrestore(&priv->lock, flags);
iwl_synchronize_irq(priv);
/* device going down, Stop using ICT table */
iwl_disable_ict(priv);
iwlagn_txq_ctx_stop(priv);
iwlagn_rxq_stop(priv);
/* Power-down device's busmaster DMA clocks */
iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
udelay(5);
/* Make sure (redundant) we've released our request to stay awake */
iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/* Stop the device, and put it in low power state */
iwl_apm_stop(priv);
}
...@@ -58,8 +58,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, ...@@ -58,8 +58,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
u8 old_dev_type = send->dev_type; u8 old_dev_type = send->dev_type;
int ret; int ret;
iwlagn_init_notification_wait(priv, &disable_wait, NULL, iwlagn_init_notification_wait(priv, &disable_wait,
REPLY_WIPAN_DEACTIVATION_COMPLETE); REPLY_WIPAN_DEACTIVATION_COMPLETE,
NULL, NULL);
send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
send->dev_type = RXON_DEV_TYPE_P2P; send->dev_type = RXON_DEV_TYPE_P2P;
...@@ -72,13 +73,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, ...@@ -72,13 +73,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
iwlagn_remove_notification(priv, &disable_wait); iwlagn_remove_notification(priv, &disable_wait);
} else { } else {
signed long wait_res; ret = iwlagn_wait_notification(priv, &disable_wait, HZ);
if (ret)
wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ);
if (wait_res == 0) {
IWL_ERR(priv, "Timed out waiting for PAN disable\n"); IWL_ERR(priv, "Timed out waiting for PAN disable\n");
ret = -EIO;
}
} }
return ret; return ret;
......
...@@ -161,47 +161,19 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, ...@@ -161,47 +161,19 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
} }
static int iwlagn_load_given_ucode(struct iwl_priv *priv, static int iwlagn_load_given_ucode(struct iwl_priv *priv,
struct fw_desc *inst_image, struct fw_img *image)
struct fw_desc *data_image)
{ {
int ret = 0; int ret = 0;
ret = iwlagn_load_section(priv, "INST", inst_image, ret = iwlagn_load_section(priv, "INST", &image->code,
IWLAGN_RTC_INST_LOWER_BOUND); IWLAGN_RTC_INST_LOWER_BOUND);
if (ret) if (ret)
return ret; return ret;
return iwlagn_load_section(priv, "DATA", data_image, return iwlagn_load_section(priv, "DATA", &image->data,
IWLAGN_RTC_DATA_LOWER_BOUND); IWLAGN_RTC_DATA_LOWER_BOUND);
} }
int iwlagn_load_ucode(struct iwl_priv *priv)
{
int ret = 0;
/* check whether init ucode should be loaded, or rather runtime ucode */
if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n");
ret = iwlagn_load_given_ucode(priv,
&priv->ucode_init, &priv->ucode_init_data);
if (!ret) {
IWL_DEBUG_INFO(priv, "Init ucode load complete.\n");
priv->ucode_type = UCODE_INIT;
}
} else {
IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. "
"Loading runtime ucode...\n");
ret = iwlagn_load_given_ucode(priv,
&priv->ucode_code, &priv->ucode_data);
if (!ret) {
IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n");
priv->ucode_type = UCODE_RT;
}
}
return ret;
}
/* /*
* Calibration * Calibration
*/ */
...@@ -297,33 +269,9 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv, ...@@ -297,33 +269,9 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv,
iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
} }
void iwlagn_rx_calib_complete(struct iwl_priv *priv, static int iwlagn_init_alive_start(struct iwl_priv *priv)
struct iwl_rx_mem_buffer *rxb)
{ {
IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n"); int ret;
queue_work(priv->workqueue, &priv->restart);
}
void iwlagn_init_alive_start(struct iwl_priv *priv)
{
int ret = 0;
/* initialize uCode was loaded... verify inst image.
* This is a paranoid check, because we would not have gotten the
* "initialize" alive if code weren't properly loaded. */
if (iwl_verify_ucode(priv, &priv->ucode_init)) {
/* Runtime instruction load was bad;
* take it all the way back down so we can try again */
IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n");
goto restart;
}
ret = iwlagn_alive_notify(priv);
if (ret) {
IWL_WARN(priv,
"Could not complete ALIVE transition: %d\n", ret);
goto restart;
}
if (priv->cfg->bt_params && if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) { priv->cfg->bt_params->advanced_bt_coexist) {
...@@ -333,24 +281,25 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) ...@@ -333,24 +281,25 @@ void iwlagn_init_alive_start(struct iwl_priv *priv)
* no need to close the envlope since we are going * no need to close the envlope since we are going
* to load the runtime uCode later. * to load the runtime uCode later.
*/ */
iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
if (ret)
return ret;
} }
iwlagn_send_calib_cfg(priv);
ret = iwlagn_send_calib_cfg(priv);
if (ret)
return ret;
/** /**
* temperature offset calibration is only needed for runtime ucode, * temperature offset calibration is only needed for runtime ucode,
* so prepare the value now. * so prepare the value now.
*/ */
if (priv->cfg->need_temp_offset_calib) if (priv->cfg->need_temp_offset_calib)
iwlagn_set_temperature_offset_calib(priv); return iwlagn_set_temperature_offset_calib(priv);
return;
restart: return 0;
/* real restart (first load init_ucode) */
queue_work(priv->workqueue, &priv->restart);
} }
static int iwlagn_send_wimax_coex(struct iwl_priv *priv) static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
...@@ -413,19 +362,22 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv) ...@@ -413,19 +362,22 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv)
IWL_ERR(priv, "failed to send BT prio tbl command\n"); IWL_ERR(priv, "failed to send BT prio tbl command\n");
} }
void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
{ {
struct iwl_bt_coex_prot_env_cmd env_cmd; struct iwl_bt_coex_prot_env_cmd env_cmd;
int ret;
env_cmd.action = action; env_cmd.action = action;
env_cmd.type = type; env_cmd.type = type;
if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
sizeof(env_cmd), &env_cmd)) sizeof(env_cmd), &env_cmd);
if (ret)
IWL_ERR(priv, "failed to send BT env command\n"); IWL_ERR(priv, "failed to send BT env command\n");
return ret;
} }
int iwlagn_alive_notify(struct iwl_priv *priv) static int iwlagn_alive_notify(struct iwl_priv *priv)
{ {
const struct queue_to_fifo_ac *queue_to_fifo; const struct queue_to_fifo_ac *queue_to_fifo;
struct iwl_rxon_context *ctx; struct iwl_rxon_context *ctx;
...@@ -604,15 +556,164 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, ...@@ -604,15 +556,164 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
* iwl_verify_ucode - determine which instruction image is in SRAM, * iwl_verify_ucode - determine which instruction image is in SRAM,
* and verify its contents * and verify its contents
*/ */
int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img)
{ {
if (!iwlcore_verify_inst_sparse(priv, fw_desc)) { if (!iwlcore_verify_inst_sparse(priv, &img->code)) {
IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n");
return 0; return 0;
} }
IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
iwl_print_mismatch_inst(priv, fw_desc); iwl_print_mismatch_inst(priv, &img->code);
return -EIO;
}
struct iwlagn_alive_data {
bool valid;
u8 subtype;
};
static void iwlagn_alive_fn(struct iwl_priv *priv,
struct iwl_rx_packet *pkt,
void *data)
{
struct iwlagn_alive_data *alive_data = data;
struct iwl_alive_resp *palive;
palive = &pkt->u.alive_frame;
IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision "
"0x%01X 0x%01X\n",
palive->is_valid, palive->ver_type,
palive->ver_subtype);
priv->device_pointers.error_event_table =
le32_to_cpu(palive->error_event_table_ptr);
priv->device_pointers.log_event_table =
le32_to_cpu(palive->log_event_table_ptr);
alive_data->subtype = palive->ver_subtype;
alive_data->valid = palive->is_valid == UCODE_VALID_OK;
}
#define UCODE_ALIVE_TIMEOUT HZ
#define UCODE_CALIB_TIMEOUT (2*HZ)
int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
struct fw_img *image,
int subtype, int alternate_subtype)
{
struct iwl_notification_wait alive_wait;
struct iwlagn_alive_data alive_data;
int ret;
enum iwlagn_ucode_subtype old_type;
ret = iwlagn_start_device(priv);
if (ret)
return ret;
iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE,
iwlagn_alive_fn, &alive_data);
old_type = priv->ucode_type;
priv->ucode_type = subtype;
ret = iwlagn_load_given_ucode(priv, image);
if (ret) {
priv->ucode_type = old_type;
iwlagn_remove_notification(priv, &alive_wait);
return ret;
}
/* Remove all resets to allow NIC to operate */
iwl_write32(priv, CSR_RESET, 0);
/*
* Some things may run in the background now, but we
* just wait for the ALIVE notification here.
*/
ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT);
if (ret) {
priv->ucode_type = old_type;
return ret;
}
if (!alive_data.valid) {
IWL_ERR(priv, "Loaded ucode is not valid!\n");
priv->ucode_type = old_type;
return -EIO; return -EIO;
}
if (alive_data.subtype != subtype &&
alive_data.subtype != alternate_subtype) {
IWL_ERR(priv,
"Loaded ucode is not expected type (got %d, expected %d)!\n",
alive_data.subtype, subtype);
priv->ucode_type = old_type;
return -EIO;
}
ret = iwl_verify_ucode(priv, image);
if (ret) {
priv->ucode_type = old_type;
return ret;
}
/* delay a bit to give rfkill time to run */
msleep(5);
ret = iwlagn_alive_notify(priv);
if (ret) {
IWL_WARN(priv,
"Could not complete ALIVE transition: %d\n", ret);
priv->ucode_type = old_type;
return ret;
}
return 0;
}
int iwlagn_run_init_ucode(struct iwl_priv *priv)
{
struct iwl_notification_wait calib_wait;
int ret;
lockdep_assert_held(&priv->mutex);
/* No init ucode required? Curious, but maybe ok */
if (!priv->ucode_init.code.len)
return 0;
if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED)
return 0;
iwlagn_init_notification_wait(priv, &calib_wait,
CALIBRATION_COMPLETE_NOTIFICATION,
NULL, NULL);
/* Will also start the device */
ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
UCODE_SUBTYPE_INIT, -1);
if (ret)
goto error;
ret = iwlagn_init_alive_start(priv);
if (ret)
goto error;
/*
* Some things may run in the background now, but we
* just wait for the calibration complete notification.
*/
ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT);
goto out;
error:
iwlagn_remove_notification(priv, &calib_wait);
out:
/* Whatever happened, stop the device */
iwlagn_stop_device(priv);
return ret;
} }
This diff is collapsed.
...@@ -120,6 +120,19 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv); ...@@ -120,6 +120,19 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv);
void iwl_free_isr_ict(struct iwl_priv *priv); void iwl_free_isr_ict(struct iwl_priv *priv);
irqreturn_t iwl_isr_ict(int irq, void *data); irqreturn_t iwl_isr_ict(int irq, void *data);
/* call this function to flush any scheduled tasklet */
static inline void iwl_synchronize_irq(struct iwl_priv *priv)
{
/* wait to make sure we flush pending tasklet*/
synchronize_irq(priv->pci_dev->irq);
tasklet_kill(&priv->irq_tasklet);
}
int iwl_prepare_card_hw(struct iwl_priv *priv);
int iwlagn_start_device(struct iwl_priv *priv);
void iwlagn_stop_device(struct iwl_priv *priv);
/* tx queue */ /* tx queue */
void iwlagn_set_wr_ptrs(struct iwl_priv *priv, void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
int txq_id, u32 index); int txq_id, u32 index);
...@@ -145,16 +158,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, ...@@ -145,16 +158,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
u32 changes); u32 changes);
/* uCode */ /* uCode */
int iwlagn_load_ucode(struct iwl_priv *priv);
void iwlagn_rx_calib_result(struct iwl_priv *priv, void iwlagn_rx_calib_result(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb); struct iwl_rx_mem_buffer *rxb);
void iwlagn_rx_calib_complete(struct iwl_priv *priv, int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
struct iwl_rx_mem_buffer *rxb);
void iwlagn_init_alive_start(struct iwl_priv *priv);
int iwlagn_alive_notify(struct iwl_priv *priv);
int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc);
void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
void iwlagn_send_prio_tbl(struct iwl_priv *priv); void iwlagn_send_prio_tbl(struct iwl_priv *priv);
int iwlagn_run_init_ucode(struct iwl_priv *priv);
int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
struct fw_img *image,
int subtype, int alternate_subtype);
/* lib */ /* lib */
void iwl_check_abort_status(struct iwl_priv *priv, void iwl_check_abort_status(struct iwl_priv *priv,
...@@ -325,10 +336,12 @@ void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); ...@@ -325,10 +336,12 @@ void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
void __acquires(wait_entry) void __acquires(wait_entry)
iwlagn_init_notification_wait(struct iwl_priv *priv, iwlagn_init_notification_wait(struct iwl_priv *priv,
struct iwl_notification_wait *wait_entry, struct iwl_notification_wait *wait_entry,
u8 cmd,
void (*fn)(struct iwl_priv *priv, void (*fn)(struct iwl_priv *priv,
struct iwl_rx_packet *pkt), struct iwl_rx_packet *pkt,
u8 cmd); void *data),
signed long __releases(wait_entry) void *fn_data);
int __must_check __releases(wait_entry)
iwlagn_wait_notification(struct iwl_priv *priv, iwlagn_wait_notification(struct iwl_priv *priv,
struct iwl_notification_wait *wait_entry, struct iwl_notification_wait *wait_entry,
unsigned long timeout); unsigned long timeout);
......
...@@ -386,7 +386,18 @@ struct iwl_tx_ant_config_cmd { ...@@ -386,7 +386,18 @@ struct iwl_tx_ant_config_cmd {
*****************************************************************************/ *****************************************************************************/
#define UCODE_VALID_OK cpu_to_le32(0x1) #define UCODE_VALID_OK cpu_to_le32(0x1)
#define INITIALIZE_SUBTYPE (9)
enum iwlagn_ucode_subtype {
UCODE_SUBTYPE_REGULAR = 0,
UCODE_SUBTYPE_REGULAR_NEW = 1,
UCODE_SUBTYPE_INIT = 9,
/*
* Not a valid subtype, the ucode has just a u8, so
* we can use something > 0xff for this value.
*/
UCODE_SUBTYPE_NONE_LOADED = 0x100,
};
/** /**
* REPLY_ALIVE = 0x1 (response only, not a command) * REPLY_ALIVE = 0x1 (response only, not a command)
...@@ -422,49 +433,61 @@ struct iwl_tx_ant_config_cmd { ...@@ -422,49 +433,61 @@ struct iwl_tx_ant_config_cmd {
* *
* 2) error_event_table_ptr indicates base of the error log. This contains * 2) error_event_table_ptr indicates base of the error log. This contains
* information about any uCode error that occurs. For agn, the format * information about any uCode error that occurs. For agn, the format
* of the error log is: * of the error log is defined by struct iwl_error_event_table.
*
* __le32 valid; (nonzero) valid, (0) log is empty
* __le32 error_id; type of error
* __le32 pc; program counter
* __le32 blink1; branch link
* __le32 blink2; branch link
* __le32 ilink1; interrupt link
* __le32 ilink2; interrupt link
* __le32 data1; error-specific data
* __le32 data2; error-specific data
* __le32 line; source code line of error
* __le32 bcon_time; beacon timer
* __le32 tsf_low; network timestamp function timer
* __le32 tsf_hi; network timestamp function timer
* __le32 gp1; GP1 timer register
* __le32 gp2; GP2 timer register
* __le32 gp3; GP3 timer register
* __le32 ucode_ver; uCode version
* __le32 hw_ver; HW Silicon version
* __le32 brd_ver; HW board version
* __le32 log_pc; log program counter
* __le32 frame_ptr; frame pointer
* __le32 stack_ptr; stack pointer
* __le32 hcmd; last host command
* __le32 isr0; isr status register LMPM_NIC_ISR0: rxtx_flag
* __le32 isr1; isr status register LMPM_NIC_ISR1: host_flag
* __le32 isr2; isr status register LMPM_NIC_ISR2: enc_flag
* __le32 isr3; isr status register LMPM_NIC_ISR3: time_flag
* __le32 isr4; isr status register LMPM_NIC_ISR4: wico interrupt
* __le32 isr_pref; isr status register LMPM_NIC_PREF_STAT
* __le32 wait_event; wait event() caller address
* __le32 l2p_control; L2pControlField
* __le32 l2p_duration; L2pDurationField
* __le32 l2p_mhvalid; L2pMhValidBits
* __le32 l2p_addr_match; L2pAddrMatchStat
* __le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL)
* __le32 u_timestamp; indicate when the date and time of the compilation
* __le32 reserved;
* *
* The Linux driver can print both logs to the system log when a uCode error * The Linux driver can print both logs to the system log when a uCode error
* occurs. * occurs.
*/ */
/*
* Note: This structure is read from the device with IO accesses,
* and the reading already does the endian conversion. As it is
* read with u32-sized accesses, any members with a different size
* need to be ordered correctly though!
*/
struct iwl_error_event_table {
u32 valid; /* (nonzero) valid, (0) log is empty */
u32 error_id; /* type of error */
u32 pc; /* program counter */
u32 blink1; /* branch link */
u32 blink2; /* branch link */
u32 ilink1; /* interrupt link */
u32 ilink2; /* interrupt link */
u32 data1; /* error-specific data */
u32 data2; /* error-specific data */
u32 line; /* source code line of error */
u32 bcon_time; /* beacon timer */
u32 tsf_low; /* network timestamp function timer */
u32 tsf_hi; /* network timestamp function timer */
u32 gp1; /* GP1 timer register */
u32 gp2; /* GP2 timer register */
u32 gp3; /* GP3 timer register */
u32 ucode_ver; /* uCode version */
u32 hw_ver; /* HW Silicon version */
u32 brd_ver; /* HW board version */
u32 log_pc; /* log program counter */
u32 frame_ptr; /* frame pointer */
u32 stack_ptr; /* stack pointer */
u32 hcmd; /* last host command header */
#if 0
/* no need to read the remainder, we don't use the values */
u32 isr0; /* isr status register LMPM_NIC_ISR0: rxtx_flag */
u32 isr1; /* isr status register LMPM_NIC_ISR1: host_flag */
u32 isr2; /* isr status register LMPM_NIC_ISR2: enc_flag */
u32 isr3; /* isr status register LMPM_NIC_ISR3: time_flag */
u32 isr4; /* isr status register LMPM_NIC_ISR4: wico interrupt */
u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
u32 wait_event; /* wait event() caller address */
u32 l2p_control; /* L2pControlField */
u32 l2p_duration; /* L2pDurationField */
u32 l2p_mhvalid; /* L2pMhValidBits */
u32 l2p_addr_match; /* L2pAddrMatchStat */
u32 lmpm_pmg_sel; /* indicate which clocks are turned on (LMPM_PMG_SEL) */
u32 u_timestamp; /* indicate when the date and time of the compilation */
u32 flow_handler; /* FH read/write pointers, RX credit */
#endif
} __packed;
struct iwl_alive_resp { struct iwl_alive_resp {
u8 ucode_minor; u8 ucode_minor;
u8 ucode_major; u8 ucode_major;
......
...@@ -867,6 +867,19 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, ...@@ -867,6 +867,19 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv,
} }
#endif #endif
static void iwlagn_abort_notification_waits(struct iwl_priv *priv)
{
unsigned long flags;
struct iwl_notification_wait *wait_entry;
spin_lock_irqsave(&priv->_agn.notif_wait_lock, flags);
list_for_each_entry(wait_entry, &priv->_agn.notif_waits, list)
wait_entry->aborted = true;
spin_unlock_irqrestore(&priv->_agn.notif_wait_lock, flags);
wake_up_all(&priv->_agn.notif_waitq);
}
void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
{ {
unsigned int reload_msec; unsigned int reload_msec;
...@@ -878,6 +891,8 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) ...@@ -878,6 +891,8 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
/* Cancel currently queued command. */ /* Cancel currently queued command. */
clear_bit(STATUS_HCMD_ACTIVE, &priv->status); clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
iwlagn_abort_notification_waits(priv);
/* Keep the restart process from trying to send host /* Keep the restart process from trying to send host
* commands by clearing the ready bit */ * commands by clearing the ready bit */
clear_bit(STATUS_READY, &priv->status); clear_bit(STATUS_READY, &priv->status);
......
...@@ -226,10 +226,10 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, ...@@ -226,10 +226,10 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
/* default is to dump the entire data segment */ /* default is to dump the entire data segment */
if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
priv->dbgfs_sram_offset = 0x800000; priv->dbgfs_sram_offset = 0x800000;
if (priv->ucode_type == UCODE_INIT) if (priv->ucode_type == UCODE_SUBTYPE_INIT)
priv->dbgfs_sram_len = priv->ucode_init_data.len; priv->dbgfs_sram_len = priv->ucode_init.data.len;
else else
priv->dbgfs_sram_len = priv->ucode_data.len; priv->dbgfs_sram_len = priv->ucode_rt.data.len;
} }
len = priv->dbgfs_sram_len; len = priv->dbgfs_sram_len;
......
...@@ -479,6 +479,10 @@ struct fw_desc { ...@@ -479,6 +479,10 @@ struct fw_desc {
u32 len; /* bytes */ u32 len; /* bytes */
}; };
struct fw_img {
struct fw_desc code, data;
};
/* v1/v2 uCode file layout */ /* v1/v2 uCode file layout */
struct iwl_ucode_header { struct iwl_ucode_header {
__le32 ver; /* major/minor/API/serial */ __le32 ver; /* major/minor/API/serial */
...@@ -794,12 +798,6 @@ struct iwl_calib_result { ...@@ -794,12 +798,6 @@ struct iwl_calib_result {
size_t buf_len; size_t buf_len;
}; };
enum ucode_type {
UCODE_NONE = 0,
UCODE_INIT,
UCODE_RT
};
/* Sensitivity calib data */ /* Sensitivity calib data */
struct iwl_sensitivity_data { struct iwl_sensitivity_data {
u32 auto_corr_ofdm; u32 auto_corr_ofdm;
...@@ -1105,10 +1103,12 @@ struct iwl_force_reset { ...@@ -1105,10 +1103,12 @@ struct iwl_force_reset {
struct iwl_notification_wait { struct iwl_notification_wait {
struct list_head list; struct list_head list;
void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt); void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt,
void *data);
void *fn_data;
u8 cmd; u8 cmd;
bool triggered; bool triggered, aborted;
}; };
enum iwl_rxon_context_id { enum iwl_rxon_context_id {
...@@ -1270,11 +1270,10 @@ struct iwl_priv { ...@@ -1270,11 +1270,10 @@ struct iwl_priv {
int fw_index; /* firmware we're trying to load */ int fw_index; /* firmware we're trying to load */
u32 ucode_ver; /* version of ucode, copy of u32 ucode_ver; /* version of ucode, copy of
iwl_ucode.ver */ iwl_ucode.ver */
struct fw_desc ucode_code; /* runtime inst */ struct fw_img ucode_rt;
struct fw_desc ucode_data; /* runtime data original */ struct fw_img ucode_init;
struct fw_desc ucode_init; /* initialization inst */
struct fw_desc ucode_init_data; /* initialization data */ enum iwlagn_ucode_subtype ucode_type;
enum ucode_type ucode_type;
u8 ucode_write_complete; /* the image write is complete */ u8 ucode_write_complete; /* the image write is complete */
char firmware_name[25]; char firmware_name[25];
...@@ -1472,8 +1471,6 @@ struct iwl_priv { ...@@ -1472,8 +1471,6 @@ struct iwl_priv {
struct tasklet_struct irq_tasklet; struct tasklet_struct irq_tasklet;
struct delayed_work init_alive_start;
struct delayed_work alive_start;
struct delayed_work scan_check; struct delayed_work scan_check;
/* TX Power */ /* TX Power */
...@@ -1506,7 +1503,6 @@ struct iwl_priv { ...@@ -1506,7 +1503,6 @@ struct iwl_priv {
struct timer_list statistics_periodic; struct timer_list statistics_periodic;
struct timer_list ucode_trace; struct timer_list ucode_trace;
struct timer_list watchdog; struct timer_list watchdog;
bool hw_ready;
struct iwl_event_log event_log; struct iwl_event_log event_log;
......
...@@ -64,30 +64,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd) ...@@ -64,30 +64,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd)
return --index & (n_bd - 1); return --index & (n_bd - 1);
} }
/* TODO: Move fw_desc functions to iwl-pci.ko */
static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
struct fw_desc *desc)
{
if (desc->v_addr)
dma_free_coherent(&pci_dev->dev, desc->len,
desc->v_addr, desc->p_addr);
desc->v_addr = NULL;
desc->len = 0;
}
static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev,
struct fw_desc *desc)
{
if (!desc->len) {
desc->v_addr = NULL;
return -EINVAL;
}
desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len,
&desc->p_addr, GFP_KERNEL);
return (desc->v_addr != NULL) ? 0 : -ENOMEM;
}
/* /*
* we have 8 bits used like this: * we have 8 bits used like this:
* *
......
...@@ -242,20 +242,32 @@ void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) ...@@ -242,20 +242,32 @@ void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
spin_unlock_irqrestore(&priv->reg_lock, flags); spin_unlock_irqrestore(&priv->reg_lock, flags);
} }
u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr,
void *buf, int words)
{ {
unsigned long flags; unsigned long flags;
u32 value; int offs;
u32 *vals = buf;
spin_lock_irqsave(&priv->reg_lock, flags); spin_lock_irqsave(&priv->reg_lock, flags);
iwl_grab_nic_access(priv); iwl_grab_nic_access(priv);
iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr);
rmb(); rmb();
value = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
for (offs = 0; offs < words; offs++)
vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
iwl_release_nic_access(priv); iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, flags); spin_unlock_irqrestore(&priv->reg_lock, flags);
}
u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
{
u32 value;
_iwl_read_targ_mem_words(priv, addr, &value, 1);
return value; return value;
} }
......
...@@ -76,6 +76,16 @@ void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, ...@@ -76,6 +76,16 @@ void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
u32 bits, u32 mask); u32 bits, u32 mask);
void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask);
void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr,
void *buf, int words);
#define iwl_read_targ_mem_words(priv, addr, buf, bufsize) \
do { \
BUILD_BUG_ON((bufsize) % sizeof(u32)); \
_iwl_read_targ_mem_words(priv, addr, buf, \
(bufsize) / sizeof(u32));\
} while (0)
u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr);
void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val);
#endif #endif
...@@ -225,55 +225,6 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) ...@@ -225,55 +225,6 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
* *
******************************************************************************/ ******************************************************************************/
static void iwl_rx_reply_alive(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_alive_resp *palive;
struct delayed_work *pwork;
palive = &pkt->u.alive_frame;
IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision "
"0x%01X 0x%01X\n",
palive->is_valid, palive->ver_type,
palive->ver_subtype);
priv->device_pointers.log_event_table =
le32_to_cpu(palive->log_event_table_ptr);
priv->device_pointers.error_event_table =
le32_to_cpu(palive->error_event_table_ptr);
if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
pwork = &priv->init_alive_start;
} else {
IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
pwork = &priv->alive_start;
}
/* We delay the ALIVE response by 5ms to
* give the HW RF Kill time to activate... */
if (palive->is_valid == UCODE_VALID_OK)
queue_delayed_work(priv->workqueue, pwork,
msecs_to_jiffies(5));
else {
IWL_WARN(priv, "%s uCode did not respond OK.\n",
(palive->ver_subtype == INITIALIZE_SUBTYPE) ?
"init" : "runtime");
/*
* If fail to load init uCode,
* let's try to load the init uCode again.
* We should not get into this situation, but if it
* does happen, we should not move on and loading "runtime"
* without proper calibrate the device.
*/
if (palive->ver_subtype == INITIALIZE_SUBTYPE)
priv->ucode_type = UCODE_NONE;
queue_work(priv->workqueue, &priv->restart);
}
}
static void iwl_rx_reply_error(struct iwl_priv *priv, static void iwl_rx_reply_error(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
...@@ -1125,7 +1076,6 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) ...@@ -1125,7 +1076,6 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
handlers = priv->rx_handlers; handlers = priv->rx_handlers;
handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
handlers[REPLY_ERROR] = iwl_rx_reply_error; handlers[REPLY_ERROR] = iwl_rx_reply_error;
handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif; handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment