Skip to content

iwlwifi Startup

Aaron Mulder edited this page Mar 4, 2016 · 1 revision

Is this absurd, or what? I mean, I get that it's a complex, modern piece of hardware. But doing all this just to start it up seems a bit over the top. Still, it's what I'm looking at. When I come across a function, unless it's pretty trivial, I add it to the top-level list and write out the sub-steps that happen in that function. I'm mainly interested in other function calls, and not particular calculations or assignments (which I often ignore or just note as "logic") Bold items are working (or unneeded) in OS X.

Note that the first two are generic driver initialization calls. The work to activate a particular WiFi card starts with the third call (iwl_pci_probe).

Specific Setup

  • iwl-drv iwl_drv_init (module init)
    • Set up opmode lists (unneeded)
    • Call iwl_pci_register_driver
  • pcie/drv.c iwl_pci_register_driver
    • Set hardware matrix, probe/remove operations, suspend/resume operations
  • pcie/drv.c iwl_pci_probe
    • Set up PCIe iwl_trans_pcie_alloc
    • Check for 7265D config override
    • Start driver iwl_drv_start
    • Check ACPI for power limit
  • pcie/trans.c iwl_trans_pcie_alloc
    • allocate memory
    • configure locks and firmware write waitq
    • pci_enable_device
    • Set PCIe link state
    • Set PCIe bus mastering (need to confirm)
    • Set PCIe DMA mask to 36 bits
    • pci_request_regions
    • hw_base = pci_ioremap_bar
    • Write a PCI config byte
    • iwl_disable_interrupts
      • a few iwl_write32 writes = pcie_trans->ops->write32
    • pci_enable_msi
    • Read hardware revision
    • Nasty 8000-series workaround
      • iwl_pcie_prepare_card_hw
      • iwl_set_bit
      • iwl_poll_bit
      • iwl_trans_grab_nic_access
      • __iwl_read_prph
      • __iwl_write_prph
      • iwl_trans_release_nic_access
    • Initialize command wait queue
    • iwl_pcie_alloc_ict
    • request_threaded_irq to iwl_pcie_isr (primary) iwl_pcie_irq_handler (secondary)
  • pcie/rx.c iwl_pcie_alloc_ict
    • DMA zalloc coherent
    • checks and logging
  • pcie/rx.c iwl_pcie_isr
    • Make sure context is not null (doesn’t check for shared interrupts?)
    • Disable (but don’t clear) interrupts with iwl_write32
    • return IRQ_WAKE_THREAD (run secondary handler)
  • pcie/rx.c iwl_pcie_irq_handler
    • spinlock around
    • iwl_pcie_int_cause_ict (read details from ict DRAM table; lots of logic) or
    • iwl_pcie_int_cause_non_ict (iwl_read32; reportedly “expensive”)
    • do nothing except re-enable interrupts if interrupt to handle is 0
    • check that hardware still exists (?)
    • iwl_write32 to acknowledge all possible interrupts
    • Then service all interrups
      • CSR_INT_BIT_HW_ERR Hardware error
      • CSR_INT_BIT_SCD unused save log/stats
      • CSR_INT_BIT_ALIVE unused save log/stats
      • CSR_INT_BIT_RF_KILL Hardware RFKILL switch
      • CSR_INT_BIT_CT_KILL Hardware overheated and stopped itself
      • CSR_INT_BIT_SW_ERR Microcode error
      • CSR_INT_BIT_WAKEUP Microcode wakes up after power-down sleep
        • iwl_pcie_rxq_check_wrptr
        • iwl_pcie_txq_check_wrptrs
      • CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX | CSR_INT_BIT_RX_PERIODIC all microcode command responses include Tx command responses, Rx “responses” (frame-received notification), and other notifications from uCode come through here
        • iwl_pcie_rx_handle
      • CSR_INT_BIT_FH_TX “Tx” DMA channel used for loading microcode
        • ucode_write_complete = true
        • wake_up(ucode_write_waitq)
    • Them iwl_enable_interrupts and maybe iwl_enable_rfkill_int
  • iwl-drv.c iwl_drv_start
    • Malloc iwl_drv
    • Set up firmware completion var
    • Initialize driver list using this opmode (unneeded)
    • Request firmware
  • iwl-drv.c iwl_req_fw_callback
    • Allocate iwl_firmware_pieces
    • Parse firmware
    • Copy firmware into new memory
    • Select MVM ops (iwlwifi_opmode_table[MVM_OP_MODE])
    • _iwl_op_mode_start(driver and ops)
    • Set completion variable for firmware load
    • Free iwl_firmware_pieces
  • iwl-drv.c _iwl_op_mode_start
    • op->ops->start(trans, cfg, fw)
  • mvm/ops.c iwl_op_mode_mvm_start
    • ieee80211_alloc_hw(private area size, mac80211.c/iwl_mvm_hw_ops)
    • map the allocated private area to a set of operations and an iwl_mvm
    • Set the set of operations to either iwl_mvm_ops or iwl_mvm_ops_mq
    • Set some parameters
    • Configure locks and lists
    • Set up work units
    • Set up queues including d0i3_tx and d0i3_exit_waitq
    • iwl_trans_pcie_configure
    • Set up watchdog for the command queue
    • Configure transport layer iwl_trans_configure (trans->ops->configure)
    • Set variables on the transport
    • iwl_notification_wait_init (spinlock, list, waitqueue)
    • iwl_phy_db_init (kzalloc)
    • calc_min_backoff (just some logic)
    • iwl_mvm_tt_initialize (some logic, INIT_DELAYED_WORK)
    • iwl_trans_start_hw (trans->ops->start_hw; iwl_trans_pcie_start_hw)
    • iwl_run_init_mvm_ucode
    • iwl_mvm_scan_size (logic)
    • allocate scan_cmd memory
    • iwl_mvm_mac_setup_register
    • Set up rx_stats
    • iwl_mvm_tof_init (logic)
  • pcie/trans.c iwl_trans_pcie_configure
    • Shuffle data structures, copy memory
    • Initialize "dummy" netdevice, add network interface?
  • pcie/trans.c iwl_trans_pcie_start_hw
    • mutex lock plus:
    • iwl_pcie_prepare_card_hw
    • reset device (write reset flag)
    • iwl_pcie_apm_init
    • iwl_enable_rfkill_int (not needed)
    • more rfkill checks
  • pcie/trans.c iwl_pcie_prepare_card_hw
    • iwl_pcie_set_hw_ready
    • iwl_set_bit
    • keep retrying another set_bit plus iwl_pcie_set_hw_ready until success
  • pcie/trans.c iwl_pcie_set_hw_ready
    • iwl_set_bit
    • iwl_poll_bit with timeout
  • iwl_set_bit = pcie/trans.c set_bits_mask = iwl_trans_pcie_set_bits_mask
    • spinlock plus
    • iwl_read32
    • iwl_write32
  • pcie/trans.c iwl_pcie_apm_init
    • Set various bits
    • iwl_pcie_apm_config
    • More set bits, poll bit
    • More bit logic, waiting, etc.
  • pcie/trans.c iwl_pcie_apm_config (work around hardware bug)
    • Check PCIe capabilities
    • Set or clear bits
  • mvm/fw.c iwl_run_init_mvm_ucode
    • iwl_init_notification_wait (for init_complete, call iwl_wait_phy_db_entry)
    • iwl_mvm_load_ucode_wait_alive (IWL_UCODE_INIT)
    • iwl_send_bt_init_conf
    • iwl_nvm_init
    • iwl_mvm_load_nvm_to_nic (planning to not use)
    • iwl_nvm_check_version (logic)
    • Abort if rfkill set
    • iwl_send_tx_ant_cfg (= iwl_mvm_send_cmd_pdu) with arg iwl_nvm_get_valid_tx_ant (logic)
    • iwl_send_phy_cfg_cmd (= iwl_mvm_send_cmd_pdu)
    • iwl_wait_notification (wait for init_complete)
  • mvm/fw.c iwl_mvm_load_ucode_wait_alive
    • iwl_get_ucode_image (fetches from mvm->fw)
    • iwl_init_notification_wait (for alive_wait, calls iwl_alive_fn)
    • iwl_trans_start_fw (iwl_trans_pcie_start_fw)
    • Wait for alive_wait notification
    • iwl_trans_update_sf (no impl for pcie)
    • iwl_trans_fw_alive = iwl_trans_pcie_fw_alive
    • iwl_save_fw_paging
    • iwl_send_paging_cmd
    • Zero the queue_info, set refcount = 1, set queue stop count to 0
    • set mvm.ucode_loaded = true
  • mvm/fw.c iwl_alive_fn
    • Gets mvm from container_of notif_wait
    • Checks one of 3 formats for alive packet
    • Sets values from alive packet
  • pcie/trans.c iwl_trans_pcie_start_fw
    • mutex, then
    • make sure it’s not stopping
    • iwl_pcie_prepare_card_hw (above)
    • iwl_enable_rkfill_int (not needed)
    • iwl_trans_pcie_rf_kill (just stops device if HW rfkill set)
    • write bit
    • iwl_pcie_nic_init
    • write bits
    • iwl_enable_interrupts (iwl_write32)
    • iwl_pcie_load_given_ucode or iwl_pcie_load_given_ucode_8000
  • pcie/trans.c iwl_pcie_nic_init
    • spinlock around iwl_pcie_apm_init (above)
    • iwl_pcie_set_pwr (set bits depending on pci_pme_capable)
    • iwl_op_mode_nic_config (iwl_mvm_nic_config)
    • iwl_pcie_tx_init
    • set shadow register bit if configured accordingly
  • mvm/ops.c iwl_mvm_nic_config
    • Calculate a bunch of bits
    • iwl_trans_set_bits_mask (anove)
    • iwl_set_bits_mask_prph
  • pcie/tx.c iwl_pcie_tx_init
    • iwl_pcie_tx_alloc
    • spin_lock then
    • iwl_scd_deactivate_fifos (iwl_write_prph)
    • iwl_write_direct32 (iwl_trans_grab_nic_access/…release_nic_access)
    • iwl_pcie_txq_init (iwl_queue_init = calculations + iwl_write_direct32)
    • iwl_set_bits_prph
  • pcie/tx.c iwl_pcie_tx_alloc
    • iwl_pcie_alloc_dma_ptr (Scheduler BC Table) (dma_alloc_coherent)
    • iwl_pcie_alloc_dma_ptr (Keep Warm)
    • kcalloc # of queues * struct iwl_txq
    • For each queue: iwl_pcie_txq_alloc
  • pcie/tx.c iwl_pcie_txq_alloc
    • setup_timer (iwl_pcie_txq_stuck_timer)
    • kcalloc slots_num, sizeof struct iwl_pcie_txq_entry
    • If command queue, for each slot, kmalloc iwl_device_cmd
    • dma_alloc_coherent circular buffer of Transmit Frame Descriptors (TFDs)
    • dma_alloc_coherent scratchbuf_sz
  • pcie/trans.c iwl_trans_pcie_grab_nic_access (and release_nic_access)
    • Spinlock_irqsave/restore around
    • set/poll some bits
    • mmiowb to flush writes (does nothing by default, but arch-specific?)
  • pcie/trans.c iwl_pcie_load_given_ucode
    • iwl_pcie_load_cpu_sections
    • iwl_pcie_alloc_fw_monitor (only if requested via mod params on 7000 family)
    • iwl_pcie_apply_destination (if dbg_dest_tlv) Sets and clears bits, write prph, etc.
    • write32(CSR_RESET, 0) “release CPU reset"
    • 8000:
    • iwl_pcie_apply_destination (if dbg_dest_tlv) Sets and clears bits, write prph, etc.
    • iwl_pcie_rsa_race_bug_wa (read_prph/write_prph)
    • iwl_pcie_load_cpu_sections_8000
  • pcie/trans.c iwl_pcie_load_cpu_sections
    • logic, then loop of iwl_pcie_load_section
    • 8000: more read_direct32/write_direct32
  • pcie/trans.c iwl_pcie_alloc_fw_monitor (debug buffer)
    • dma_sync_single_for_device or:
    • get_order
    • alloc_ages
    • dma_map_page
    • check dma_mapping
  • pcie/trans.c iwl_trans_pcie_fw_alive
    • iwl_pcie_reset_ict
    • iwl_pcie_tx_start
  • pcie_trans.c iwl_pcie_reset_ict
    • spin lock around:
    • iwl_disable_interrupts
    • zero ict_tbl
    • iwl_write32
    • iwl_enable_interrupts
  • pcie/tx.c iwl_pcie_tx_start
    • zero queue fields
    • read_prph
    • write_mem, write_prph
    • iwl_trans_ac_txq_enable = iwl_trans_txq_enable_cfg = iwl_trans_pcie_txq_enable
    • iwl_scd_activate_fifos = write_prph
    • iwl_write_direct32/iwl_read_direct32
    • iwl_clear_bits_prph
  • pcie/tx.c iwl_trans_pcie_txq_enable
    • iwl_scd_enable_set_active 0 (disable scheduler all queues) = write_prph
    • iwl_scr_txq_set_inactive (stop TX queue) = write_prph
    • iwl_scd_txq_set_chain (set chain-building queue unless command queue) = set_bits_prph
    • iwl_pcie_txq_set_ratid_map (logic + read/write_mem32)+ iwl_scd_txq_enable_agg (set_bits_prph) or iwl_scd_txq_disable_agg (set_bits_prph)
    • iwl_write_direct32 / iwl_write_prph / iwl_trans_write_mem32
  • mvm/fw.c iwl_save_fw_paging
    • iwl_alloc_fw_paging_mem
    • iwl_fill_paging_mem
  • mvm/fw.c iwl_alloc_fw_paging_mem
    • calculations, then
    • get_order, alloc_pages (4K pages)
    • dma_map_page (check dma_mapping_error)
    • repeat for many blocks
  • mvm/fw.c iwl_fill_paging_mem
    • calculations, then
    • memcpy(page_address(…)) for first CSS block
    • Then repeat for other blocks
  • mvm/fw.c iwl_send_paging_cmd = iwl_mvm_send_cmd_pdu = iwl_mvm_send_cmd = iwl_trans_send_cmd = pcie/trans.c iwl_trans_pcie_send_hcmd
    • iwl_pcie_send_hcmd_asyc or
    • iwl_pcie_send_hcmd_sync
  • pcie/tx.c iwl_pcie_send_hcmd_async = iwl_pcie_enqueue_hcmd
    • lots of logic
    • if(iwl_queue_space(=logic)) < … no space iwl_op_mode_cmd_queue_full (=iwl_mvm_nic_restart)
    • lots of logic
    • iwl_pcie_txq_build_tfd (iwl_pcie_get_scratchbuf_dma (=logic))
    • dma_map_single check dma_mapping_error
    • iwl_pcie_txq_build_tfd
    • repeat above
    • mod_timer "start stuck timer if queue currently empty"
    • spin_lock around
    • iwl_pcie_set_cmd_in_flight
    • iwl_queue_inc_wrap (logic)
    • iwl_pcie_txq_inc_wr_ptr
  • pcie/tx.c iwl_pcie_txq_build_tfd
    • iwl_pcie_tfd_get_num_tbs (logic)
    • iwl_pcie_tfd_set_tb (logic and put_unaligned_le32)
  • pcie_tx.c iwl_pciw_set_cmd_in_flight
    • iwl_trans_pcie_ref (logic)
    • set_bit / poll_bit
  • pcie/tx.c iwl_pcie_txq_inc_wr_ptr
    • iwl_read32 / iwl_set_bit
    • iwl_write32
  • pcie/tx.c iwl_pcie_send_hcmd_sync
    • Same as _async (iwl_pcie_enqueue_hcmd) then:
    • wait_event_timeout (wait_command_queue)
    • lots of error-checking logic, RFKILL while waiting, etc.
  • mvm/coex.c iwl_send_bt_init_conf
    • fw_has_api (logic)
    • iwl_send_bt_init_conf_old (similar logic, 2 commands)
    • logic
    • iwl_mvm_send_cmd_pdu
  • mvm/nvm.c iwl_nvm_init
    • buffer = kmalloc eeprom_size
    • iwl_nvm_read_section to buffer
    • kmemdup to mvm->nvm_sections
    • free buffer
    • iwl_mvm_read_external_nvm (planning to not use)
    • iwl_parse_nvm_sections
  • mvm/nvm.c iwl_parse_nvm_sections = logic then iwl_parse_nvm_data
    • iwl_get_nvm_version (logic)
    • iwl_get_radio_cfg (logic)
    • iwl_set_radio_cfg (logic)
    • iwl_get_sku (logic)
    • iwl_get_n_hw_addrs (logic)
    • iwl_set_hw_address or iwl_set_hw_address_family_8000 (all logic)
    • iwl_init_sbands
  • iwl_nvm_parse.c iwl_init_sbands
    • iwl_init_channel_map
    • iwl_init_sband_channels (logic; iwl-eeprom-parse.c)
    • iwl_init_ht_hw_capab (logic; iwl-eeprom-parse.c)
    • same 2 for 5 GHz
    • iwl_init_vht_hw_capab (logic)
  • iwl_nvm_parse.c iwl_init_channel_map
    • ieee80211_channel_to_frequency (Linux)
    • iwl_get_channel_flags (logic)
  • mvm/mac80211.c iwl_mvm_mac_setup_register (mac80211 setup & register)
    • Lots of ieee80211_hw_set calls
    • Other ieee80211_hw config
    • iwl_mvm_is_lar_supported (logic)
    • iwl_mvm_reset_phy_ctxts (logic)
    • iwl_mvm_max_scan_ie_len (logic in some nested calls)
    • device_can_wakeup (Linux)
    • iwl_mvm_leds_init (mvm/led.c; ignore for now)
    • iwl_mvm_is_csum_supported (logic)
    • ieee80211_register_hw (Linux)
Clone this wiki locally