-
Notifications
You must be signed in to change notification settings - Fork 109
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
).
- 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)