diff options
author | Ron Rindjunsky <ron.rindjunsky@intel.com> | 2008-05-15 01:54:13 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-05-21 21:48:04 -0400 |
commit | 99da1b48fc77484aa8da85a45d9c3c1e00243659 (patch) | |
tree | 68e6f85319532e4eeaf0ad01b26751fc7336094d /drivers/net/wireless/iwlwifi/iwl-5000.c | |
parent | dbb983b70a4696666112591572ed49c48c58da26 (diff) |
iwlwifi: add ucode init flow handling for iwl5000
This patch adds all the handlers and functions needed for ucode
initialization flow.
Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-5000.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-5000.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b6bdffc5a424..5e818eedb0ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -46,6 +46,16 @@ | |||
46 | 46 | ||
47 | #define IWL5000_UCODE_API "-1" | 47 | #define IWL5000_UCODE_API "-1" |
48 | 48 | ||
49 | static const u16 iwl5000_default_queue_to_tx_fifo[] = { | ||
50 | IWL_TX_FIFO_AC3, | ||
51 | IWL_TX_FIFO_AC2, | ||
52 | IWL_TX_FIFO_AC1, | ||
53 | IWL_TX_FIFO_AC0, | ||
54 | IWL50_CMD_FIFO_NUM, | ||
55 | IWL_TX_FIFO_HCCA_1, | ||
56 | IWL_TX_FIFO_HCCA_2 | ||
57 | }; | ||
58 | |||
49 | static int iwl5000_apm_init(struct iwl_priv *priv) | 59 | static int iwl5000_apm_init(struct iwl_priv *priv) |
50 | { | 60 | { |
51 | int ret = 0; | 61 | int ret = 0; |
@@ -420,6 +430,151 @@ static int iwl5000_load_ucode(struct iwl_priv *priv) | |||
420 | return ret; | 430 | return ret; |
421 | } | 431 | } |
422 | 432 | ||
433 | static void iwl5000_init_alive_start(struct iwl_priv *priv) | ||
434 | { | ||
435 | int ret = 0; | ||
436 | |||
437 | /* Check alive response for "valid" sign from uCode */ | ||
438 | if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { | ||
439 | /* We had an error bringing up the hardware, so take it | ||
440 | * all the way back down so we can try again */ | ||
441 | IWL_DEBUG_INFO("Initialize Alive failed.\n"); | ||
442 | goto restart; | ||
443 | } | ||
444 | |||
445 | /* initialize uCode was loaded... verify inst image. | ||
446 | * This is a paranoid check, because we would not have gotten the | ||
447 | * "initialize" alive if code weren't properly loaded. */ | ||
448 | if (iwl_verify_ucode(priv)) { | ||
449 | /* Runtime instruction load was bad; | ||
450 | * take it all the way back down so we can try again */ | ||
451 | IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); | ||
452 | goto restart; | ||
453 | } | ||
454 | |||
455 | iwlcore_clear_stations_table(priv); | ||
456 | ret = priv->cfg->ops->lib->alive_notify(priv); | ||
457 | if (ret) { | ||
458 | IWL_WARNING("Could not complete ALIVE transition: %d\n", ret); | ||
459 | goto restart; | ||
460 | } | ||
461 | |||
462 | return; | ||
463 | |||
464 | restart: | ||
465 | /* real restart (first load init_ucode) */ | ||
466 | queue_work(priv->workqueue, &priv->restart); | ||
467 | } | ||
468 | |||
469 | static void iwl5000_set_wr_ptrs(struct iwl_priv *priv, | ||
470 | int txq_id, u32 index) | ||
471 | { | ||
472 | iwl_write_direct32(priv, HBUS_TARG_WRPTR, | ||
473 | (index & 0xff) | (txq_id << 8)); | ||
474 | iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(txq_id), index); | ||
475 | } | ||
476 | |||
477 | static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, | ||
478 | struct iwl_tx_queue *txq, | ||
479 | int tx_fifo_id, int scd_retry) | ||
480 | { | ||
481 | int txq_id = txq->q.id; | ||
482 | int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; | ||
483 | |||
484 | iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id), | ||
485 | (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) | | ||
486 | (tx_fifo_id << IWL50_SCD_QUEUE_STTS_REG_POS_TXF) | | ||
487 | (1 << IWL50_SCD_QUEUE_STTS_REG_POS_WSL) | | ||
488 | IWL50_SCD_QUEUE_STTS_REG_MSK); | ||
489 | |||
490 | txq->sched_retry = scd_retry; | ||
491 | |||
492 | IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n", | ||
493 | active ? "Activate" : "Deactivate", | ||
494 | scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); | ||
495 | } | ||
496 | |||
497 | static int iwl5000_alive_notify(struct iwl_priv *priv) | ||
498 | { | ||
499 | u32 a; | ||
500 | int i = 0; | ||
501 | unsigned long flags; | ||
502 | int ret; | ||
503 | |||
504 | spin_lock_irqsave(&priv->lock, flags); | ||
505 | |||
506 | ret = iwl_grab_nic_access(priv); | ||
507 | if (ret) { | ||
508 | spin_unlock_irqrestore(&priv->lock, flags); | ||
509 | return ret; | ||
510 | } | ||
511 | |||
512 | priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR); | ||
513 | a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET; | ||
514 | for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET; | ||
515 | a += 4) | ||
516 | iwl_write_targ_mem(priv, a, 0); | ||
517 | for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET; | ||
518 | a += 4) | ||
519 | iwl_write_targ_mem(priv, a, 0); | ||
520 | for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4) | ||
521 | iwl_write_targ_mem(priv, a, 0); | ||
522 | |||
523 | iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, | ||
524 | (priv->shared_phys + | ||
525 | offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10); | ||
526 | iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, | ||
527 | IWL50_SCD_QUEUECHAIN_SEL_ALL( | ||
528 | priv->hw_params.max_txq_num)); | ||
529 | iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); | ||
530 | |||
531 | /* initiate the queues */ | ||
532 | for (i = 0; i < priv->hw_params.max_txq_num; i++) { | ||
533 | iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(i), 0); | ||
534 | iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); | ||
535 | iwl_write_targ_mem(priv, priv->scd_base_addr + | ||
536 | IWL50_SCD_CONTEXT_QUEUE_OFFSET(i), 0); | ||
537 | iwl_write_targ_mem(priv, priv->scd_base_addr + | ||
538 | IWL50_SCD_CONTEXT_QUEUE_OFFSET(i) + | ||
539 | sizeof(u32), | ||
540 | ((SCD_WIN_SIZE << | ||
541 | IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & | ||
542 | IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | | ||
543 | ((SCD_FRAME_LIMIT << | ||
544 | IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & | ||
545 | IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); | ||
546 | } | ||
547 | |||
548 | iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK, | ||
549 | (1 << priv->hw_params.max_txq_num) - 1); | ||
550 | |||
551 | iwl_write_prph(priv, IWL50_SCD_TXFACT, | ||
552 | SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); | ||
553 | |||
554 | iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); | ||
555 | /* map qos queues to fifos one-to-one */ | ||
556 | for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) { | ||
557 | int ac = iwl5000_default_queue_to_tx_fifo[i]; | ||
558 | iwl_txq_ctx_activate(priv, i); | ||
559 | iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0); | ||
560 | } | ||
561 | /* TODO - need to initialize those FIFOs inside the loop above, | ||
562 | * not only mark them as active */ | ||
563 | iwl_txq_ctx_activate(priv, 4); | ||
564 | iwl_txq_ctx_activate(priv, 7); | ||
565 | iwl_txq_ctx_activate(priv, 8); | ||
566 | iwl_txq_ctx_activate(priv, 9); | ||
567 | |||
568 | iwl_release_nic_access(priv); | ||
569 | spin_unlock_irqrestore(&priv->lock, flags); | ||
570 | |||
571 | /* Ask for statistics now, the uCode will send notification | ||
572 | * periodically after association */ | ||
573 | iwl_send_statistics_request(priv, CMD_ASYNC); | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | |||
423 | static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) | 578 | static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) |
424 | { | 579 | { |
425 | if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || | 580 | if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || |
@@ -622,6 +777,8 @@ static struct iwl_lib_ops iwl5000_lib = { | |||
622 | .disable_tx_fifo = iwl5000_disable_tx_fifo, | 777 | .disable_tx_fifo = iwl5000_disable_tx_fifo, |
623 | .rx_handler_setup = iwl5000_rx_handler_setup, | 778 | .rx_handler_setup = iwl5000_rx_handler_setup, |
624 | .load_ucode = iwl5000_load_ucode, | 779 | .load_ucode = iwl5000_load_ucode, |
780 | .init_alive_start = iwl5000_init_alive_start, | ||
781 | .alive_notify = iwl5000_alive_notify, | ||
625 | .apm_ops = { | 782 | .apm_ops = { |
626 | .init = iwl5000_apm_init, | 783 | .init = iwl5000_apm_init, |
627 | .config = iwl5000_nic_config, | 784 | .config = iwl5000_nic_config, |