162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2003-2015, 2018-2023 Intel Corporation 462306a36Sopenharmony_ci * Copyright (C) 2013-2015 Intel Mobile Communications GmbH 562306a36Sopenharmony_ci * Copyright (C) 2016-2017 Intel Deutschland GmbH 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#ifndef __iwl_trans_int_pcie_h__ 862306a36Sopenharmony_ci#define __iwl_trans_int_pcie_h__ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/spinlock.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/skbuff.h> 1362306a36Sopenharmony_ci#include <linux/wait.h> 1462306a36Sopenharmony_ci#include <linux/pci.h> 1562306a36Sopenharmony_ci#include <linux/timer.h> 1662306a36Sopenharmony_ci#include <linux/cpu.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "iwl-fh.h" 1962306a36Sopenharmony_ci#include "iwl-csr.h" 2062306a36Sopenharmony_ci#include "iwl-trans.h" 2162306a36Sopenharmony_ci#include "iwl-debug.h" 2262306a36Sopenharmony_ci#include "iwl-io.h" 2362306a36Sopenharmony_ci#include "iwl-op-mode.h" 2462306a36Sopenharmony_ci#include "iwl-drv.h" 2562306a36Sopenharmony_ci#include "queue/tx.h" 2662306a36Sopenharmony_ci#include "iwl-context-info.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * RX related structures and functions 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci#define RX_NUM_QUEUES 1 3262306a36Sopenharmony_ci#define RX_POST_REQ_ALLOC 2 3362306a36Sopenharmony_ci#define RX_CLAIM_REQ_ALLOC 8 3462306a36Sopenharmony_ci#define RX_PENDING_WATERMARK 16 3562306a36Sopenharmony_ci#define FIRST_RX_QUEUE 512 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct iwl_host_cmd; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/*This file includes the declaration that are internal to the 4062306a36Sopenharmony_ci * trans_pcie layer */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/** 4362306a36Sopenharmony_ci * struct iwl_rx_mem_buffer 4462306a36Sopenharmony_ci * @page_dma: bus address of rxb page 4562306a36Sopenharmony_ci * @page: driver's pointer to the rxb page 4662306a36Sopenharmony_ci * @list: list entry for the membuffer 4762306a36Sopenharmony_ci * @invalid: rxb is in driver ownership - not owned by HW 4862306a36Sopenharmony_ci * @vid: index of this rxb in the global table 4962306a36Sopenharmony_ci * @offset: indicates which offset of the page (in bytes) 5062306a36Sopenharmony_ci * this buffer uses (if multiple RBs fit into one page) 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_cistruct iwl_rx_mem_buffer { 5362306a36Sopenharmony_ci dma_addr_t page_dma; 5462306a36Sopenharmony_ci struct page *page; 5562306a36Sopenharmony_ci struct list_head list; 5662306a36Sopenharmony_ci u32 offset; 5762306a36Sopenharmony_ci u16 vid; 5862306a36Sopenharmony_ci bool invalid; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/** 6262306a36Sopenharmony_ci * struct isr_statistics - interrupt statistics 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_cistruct isr_statistics { 6662306a36Sopenharmony_ci u32 hw; 6762306a36Sopenharmony_ci u32 sw; 6862306a36Sopenharmony_ci u32 err_code; 6962306a36Sopenharmony_ci u32 sch; 7062306a36Sopenharmony_ci u32 alive; 7162306a36Sopenharmony_ci u32 rfkill; 7262306a36Sopenharmony_ci u32 ctkill; 7362306a36Sopenharmony_ci u32 wakeup; 7462306a36Sopenharmony_ci u32 rx; 7562306a36Sopenharmony_ci u32 tx; 7662306a36Sopenharmony_ci u32 unhandled; 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/** 8062306a36Sopenharmony_ci * struct iwl_rx_transfer_desc - transfer descriptor 8162306a36Sopenharmony_ci * @addr: ptr to free buffer start address 8262306a36Sopenharmony_ci * @rbid: unique tag of the buffer 8362306a36Sopenharmony_ci * @reserved: reserved 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_cistruct iwl_rx_transfer_desc { 8662306a36Sopenharmony_ci __le16 rbid; 8762306a36Sopenharmony_ci __le16 reserved[3]; 8862306a36Sopenharmony_ci __le64 addr; 8962306a36Sopenharmony_ci} __packed; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define IWL_RX_CD_FLAGS_FRAGMENTED BIT(0) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/** 9462306a36Sopenharmony_ci * struct iwl_rx_completion_desc - completion descriptor 9562306a36Sopenharmony_ci * @reserved1: reserved 9662306a36Sopenharmony_ci * @rbid: unique tag of the received buffer 9762306a36Sopenharmony_ci * @flags: flags (0: fragmented, all others: reserved) 9862306a36Sopenharmony_ci * @reserved2: reserved 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistruct iwl_rx_completion_desc { 10162306a36Sopenharmony_ci __le32 reserved1; 10262306a36Sopenharmony_ci __le16 rbid; 10362306a36Sopenharmony_ci u8 flags; 10462306a36Sopenharmony_ci u8 reserved2[25]; 10562306a36Sopenharmony_ci} __packed; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/** 10862306a36Sopenharmony_ci * struct iwl_rx_completion_desc_bz - Bz completion descriptor 10962306a36Sopenharmony_ci * @rbid: unique tag of the received buffer 11062306a36Sopenharmony_ci * @flags: flags (0: fragmented, all others: reserved) 11162306a36Sopenharmony_ci * @reserved: reserved 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistruct iwl_rx_completion_desc_bz { 11462306a36Sopenharmony_ci __le16 rbid; 11562306a36Sopenharmony_ci u8 flags; 11662306a36Sopenharmony_ci u8 reserved[1]; 11762306a36Sopenharmony_ci} __packed; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/** 12062306a36Sopenharmony_ci * struct iwl_rxq - Rx queue 12162306a36Sopenharmony_ci * @id: queue index 12262306a36Sopenharmony_ci * @bd: driver's pointer to buffer of receive buffer descriptors (rbd). 12362306a36Sopenharmony_ci * Address size is 32 bit in pre-9000 devices and 64 bit in 9000 devices. 12462306a36Sopenharmony_ci * In AX210 devices it is a pointer to a list of iwl_rx_transfer_desc's 12562306a36Sopenharmony_ci * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) 12662306a36Sopenharmony_ci * @used_bd: driver's pointer to buffer of used receive buffer descriptors (rbd) 12762306a36Sopenharmony_ci * @used_bd_dma: physical address of buffer of used receive buffer descriptors (rbd) 12862306a36Sopenharmony_ci * @read: Shared index to newest available Rx buffer 12962306a36Sopenharmony_ci * @write: Shared index to oldest written Rx packet 13062306a36Sopenharmony_ci * @free_count: Number of pre-allocated buffers in rx_free 13162306a36Sopenharmony_ci * @used_count: Number of RBDs handled to allocator to use for allocation 13262306a36Sopenharmony_ci * @write_actual: 13362306a36Sopenharmony_ci * @rx_free: list of RBDs with allocated RB ready for use 13462306a36Sopenharmony_ci * @rx_used: list of RBDs with no RB attached 13562306a36Sopenharmony_ci * @need_update: flag to indicate we need to update read/write index 13662306a36Sopenharmony_ci * @rb_stts: driver's pointer to receive buffer status 13762306a36Sopenharmony_ci * @rb_stts_dma: bus address of receive buffer status 13862306a36Sopenharmony_ci * @lock: 13962306a36Sopenharmony_ci * @queue: actual rx queue. Not used for multi-rx queue. 14062306a36Sopenharmony_ci * @next_rb_is_fragment: indicates that the previous RB that we handled set 14162306a36Sopenharmony_ci * the fragmented flag, so the next one is still another fragment 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_cistruct iwl_rxq { 14662306a36Sopenharmony_ci int id; 14762306a36Sopenharmony_ci void *bd; 14862306a36Sopenharmony_ci dma_addr_t bd_dma; 14962306a36Sopenharmony_ci void *used_bd; 15062306a36Sopenharmony_ci dma_addr_t used_bd_dma; 15162306a36Sopenharmony_ci u32 read; 15262306a36Sopenharmony_ci u32 write; 15362306a36Sopenharmony_ci u32 free_count; 15462306a36Sopenharmony_ci u32 used_count; 15562306a36Sopenharmony_ci u32 write_actual; 15662306a36Sopenharmony_ci u32 queue_size; 15762306a36Sopenharmony_ci struct list_head rx_free; 15862306a36Sopenharmony_ci struct list_head rx_used; 15962306a36Sopenharmony_ci bool need_update, next_rb_is_fragment; 16062306a36Sopenharmony_ci void *rb_stts; 16162306a36Sopenharmony_ci dma_addr_t rb_stts_dma; 16262306a36Sopenharmony_ci spinlock_t lock; 16362306a36Sopenharmony_ci struct napi_struct napi; 16462306a36Sopenharmony_ci struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; 16562306a36Sopenharmony_ci}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/** 16862306a36Sopenharmony_ci * struct iwl_rb_allocator - Rx allocator 16962306a36Sopenharmony_ci * @req_pending: number of requests the allcator had not processed yet 17062306a36Sopenharmony_ci * @req_ready: number of requests honored and ready for claiming 17162306a36Sopenharmony_ci * @rbd_allocated: RBDs with pages allocated and ready to be handled to 17262306a36Sopenharmony_ci * the queue. This is a list of &struct iwl_rx_mem_buffer 17362306a36Sopenharmony_ci * @rbd_empty: RBDs with no page attached for allocator use. This is a list 17462306a36Sopenharmony_ci * of &struct iwl_rx_mem_buffer 17562306a36Sopenharmony_ci * @lock: protects the rbd_allocated and rbd_empty lists 17662306a36Sopenharmony_ci * @alloc_wq: work queue for background calls 17762306a36Sopenharmony_ci * @rx_alloc: work struct for background calls 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistruct iwl_rb_allocator { 18062306a36Sopenharmony_ci atomic_t req_pending; 18162306a36Sopenharmony_ci atomic_t req_ready; 18262306a36Sopenharmony_ci struct list_head rbd_allocated; 18362306a36Sopenharmony_ci struct list_head rbd_empty; 18462306a36Sopenharmony_ci spinlock_t lock; 18562306a36Sopenharmony_ci struct workqueue_struct *alloc_wq; 18662306a36Sopenharmony_ci struct work_struct rx_alloc; 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/** 19062306a36Sopenharmony_ci * iwl_get_closed_rb_stts - get closed rb stts from different structs 19162306a36Sopenharmony_ci * @rxq - the rxq to get the rb stts from 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_cistatic inline __le16 iwl_get_closed_rb_stts(struct iwl_trans *trans, 19462306a36Sopenharmony_ci struct iwl_rxq *rxq) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { 19762306a36Sopenharmony_ci __le16 *rb_stts = rxq->rb_stts; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return READ_ONCE(*rb_stts); 20062306a36Sopenharmony_ci } else { 20162306a36Sopenharmony_ci struct iwl_rb_status *rb_stts = rxq->rb_stts; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return READ_ONCE(rb_stts->closed_rb_num); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 20862306a36Sopenharmony_ci/** 20962306a36Sopenharmony_ci * enum iwl_fw_mon_dbgfs_state - the different states of the monitor_data 21062306a36Sopenharmony_ci * debugfs file 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * @IWL_FW_MON_DBGFS_STATE_CLOSED: the file is closed. 21362306a36Sopenharmony_ci * @IWL_FW_MON_DBGFS_STATE_OPEN: the file is open. 21462306a36Sopenharmony_ci * @IWL_FW_MON_DBGFS_STATE_DISABLED: the file is disabled, once this state is 21562306a36Sopenharmony_ci * set the file can no longer be used. 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_cienum iwl_fw_mon_dbgfs_state { 21862306a36Sopenharmony_ci IWL_FW_MON_DBGFS_STATE_CLOSED, 21962306a36Sopenharmony_ci IWL_FW_MON_DBGFS_STATE_OPEN, 22062306a36Sopenharmony_ci IWL_FW_MON_DBGFS_STATE_DISABLED, 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci#endif 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/** 22562306a36Sopenharmony_ci * enum iwl_shared_irq_flags - level of sharing for irq 22662306a36Sopenharmony_ci * @IWL_SHARED_IRQ_NON_RX: interrupt vector serves non rx causes. 22762306a36Sopenharmony_ci * @IWL_SHARED_IRQ_FIRST_RSS: interrupt vector serves first RSS queue. 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_cienum iwl_shared_irq_flags { 23062306a36Sopenharmony_ci IWL_SHARED_IRQ_NON_RX = BIT(0), 23162306a36Sopenharmony_ci IWL_SHARED_IRQ_FIRST_RSS = BIT(1), 23262306a36Sopenharmony_ci}; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/** 23562306a36Sopenharmony_ci * enum iwl_image_response_code - image response values 23662306a36Sopenharmony_ci * @IWL_IMAGE_RESP_DEF: the default value of the register 23762306a36Sopenharmony_ci * @IWL_IMAGE_RESP_SUCCESS: iml was read successfully 23862306a36Sopenharmony_ci * @IWL_IMAGE_RESP_FAIL: iml reading failed 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_cienum iwl_image_response_code { 24162306a36Sopenharmony_ci IWL_IMAGE_RESP_DEF = 0, 24262306a36Sopenharmony_ci IWL_IMAGE_RESP_SUCCESS = 1, 24362306a36Sopenharmony_ci IWL_IMAGE_RESP_FAIL = 2, 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/** 24762306a36Sopenharmony_ci * struct cont_rec: continuous recording data structure 24862306a36Sopenharmony_ci * @prev_wr_ptr: the last address that was read in monitor_data 24962306a36Sopenharmony_ci * debugfs file 25062306a36Sopenharmony_ci * @prev_wrap_cnt: the wrap count that was used during the last read in 25162306a36Sopenharmony_ci * monitor_data debugfs file 25262306a36Sopenharmony_ci * @state: the state of monitor_data debugfs file as described 25362306a36Sopenharmony_ci * in &iwl_fw_mon_dbgfs_state enum 25462306a36Sopenharmony_ci * @mutex: locked while reading from monitor_data debugfs file 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 25762306a36Sopenharmony_cistruct cont_rec { 25862306a36Sopenharmony_ci u32 prev_wr_ptr; 25962306a36Sopenharmony_ci u32 prev_wrap_cnt; 26062306a36Sopenharmony_ci u8 state; 26162306a36Sopenharmony_ci /* Used to sync monitor_data debugfs file with driver unload flow */ 26262306a36Sopenharmony_ci struct mutex mutex; 26362306a36Sopenharmony_ci}; 26462306a36Sopenharmony_ci#endif 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cienum iwl_pcie_fw_reset_state { 26762306a36Sopenharmony_ci FW_RESET_IDLE, 26862306a36Sopenharmony_ci FW_RESET_REQUESTED, 26962306a36Sopenharmony_ci FW_RESET_OK, 27062306a36Sopenharmony_ci FW_RESET_ERROR, 27162306a36Sopenharmony_ci}; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/** 27462306a36Sopenharmony_ci * enum wl_pcie_imr_status - imr dma transfer state 27562306a36Sopenharmony_ci * @IMR_D2S_IDLE: default value of the dma transfer 27662306a36Sopenharmony_ci * @IMR_D2S_REQUESTED: dma transfer requested 27762306a36Sopenharmony_ci * @IMR_D2S_COMPLETED: dma transfer completed 27862306a36Sopenharmony_ci * @IMR_D2S_ERROR: dma transfer error 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_cienum iwl_pcie_imr_status { 28162306a36Sopenharmony_ci IMR_D2S_IDLE, 28262306a36Sopenharmony_ci IMR_D2S_REQUESTED, 28362306a36Sopenharmony_ci IMR_D2S_COMPLETED, 28462306a36Sopenharmony_ci IMR_D2S_ERROR, 28562306a36Sopenharmony_ci}; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/** 28862306a36Sopenharmony_ci * struct iwl_trans_pcie - PCIe transport specific data 28962306a36Sopenharmony_ci * @rxq: all the RX queue data 29062306a36Sopenharmony_ci * @rx_pool: initial pool of iwl_rx_mem_buffer for all the queues 29162306a36Sopenharmony_ci * @global_table: table mapping received VID from hw to rxb 29262306a36Sopenharmony_ci * @rba: allocator for RX replenishing 29362306a36Sopenharmony_ci * @ctxt_info: context information for FW self init 29462306a36Sopenharmony_ci * @ctxt_info_gen3: context information for gen3 devices 29562306a36Sopenharmony_ci * @prph_info: prph info for self init 29662306a36Sopenharmony_ci * @prph_scratch: prph scratch for self init 29762306a36Sopenharmony_ci * @ctxt_info_dma_addr: dma addr of context information 29862306a36Sopenharmony_ci * @prph_info_dma_addr: dma addr of prph info 29962306a36Sopenharmony_ci * @prph_scratch_dma_addr: dma addr of prph scratch 30062306a36Sopenharmony_ci * @ctxt_info_dma_addr: dma addr of context information 30162306a36Sopenharmony_ci * @init_dram: DRAM data of firmware image (including paging). 30262306a36Sopenharmony_ci * Context information addresses will be taken from here. 30362306a36Sopenharmony_ci * This is driver's local copy for keeping track of size and 30462306a36Sopenharmony_ci * count for allocating and freeing the memory. 30562306a36Sopenharmony_ci * @iml: image loader image virtual address 30662306a36Sopenharmony_ci * @iml_dma_addr: image loader image DMA address 30762306a36Sopenharmony_ci * @trans: pointer to the generic transport area 30862306a36Sopenharmony_ci * @scd_base_addr: scheduler sram base address in SRAM 30962306a36Sopenharmony_ci * @kw: keep warm address 31062306a36Sopenharmony_ci * @pnvm_data: holds info about pnvm payloads allocated in DRAM 31162306a36Sopenharmony_ci * @reduced_tables_data: holds info about power reduced tablse 31262306a36Sopenharmony_ci * payloads allocated in DRAM 31362306a36Sopenharmony_ci * @pci_dev: basic pci-network driver stuff 31462306a36Sopenharmony_ci * @hw_base: pci hardware address support 31562306a36Sopenharmony_ci * @ucode_write_complete: indicates that the ucode has been copied. 31662306a36Sopenharmony_ci * @ucode_write_waitq: wait queue for uCode load 31762306a36Sopenharmony_ci * @cmd_queue - command queue number 31862306a36Sopenharmony_ci * @rx_buf_size: Rx buffer size 31962306a36Sopenharmony_ci * @scd_set_active: should the transport configure the SCD for HCMD queue 32062306a36Sopenharmony_ci * @rx_page_order: page order for receive buffer size 32162306a36Sopenharmony_ci * @rx_buf_bytes: RX buffer (RB) size in bytes 32262306a36Sopenharmony_ci * @reg_lock: protect hw register access 32362306a36Sopenharmony_ci * @mutex: to protect stop_device / start_fw / start_hw 32462306a36Sopenharmony_ci * @cmd_in_flight: true when we have a host command in flight 32562306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 32662306a36Sopenharmony_ci * @fw_mon_data: fw continuous recording data 32762306a36Sopenharmony_ci#endif 32862306a36Sopenharmony_ci * @msix_entries: array of MSI-X entries 32962306a36Sopenharmony_ci * @msix_enabled: true if managed to enable MSI-X 33062306a36Sopenharmony_ci * @shared_vec_mask: the type of causes the shared vector handles 33162306a36Sopenharmony_ci * (see iwl_shared_irq_flags). 33262306a36Sopenharmony_ci * @alloc_vecs: the number of interrupt vectors allocated by the OS 33362306a36Sopenharmony_ci * @def_irq: default irq for non rx causes 33462306a36Sopenharmony_ci * @fh_init_mask: initial unmasked fh causes 33562306a36Sopenharmony_ci * @hw_init_mask: initial unmasked hw causes 33662306a36Sopenharmony_ci * @fh_mask: current unmasked fh causes 33762306a36Sopenharmony_ci * @hw_mask: current unmasked hw causes 33862306a36Sopenharmony_ci * @in_rescan: true if we have triggered a device rescan 33962306a36Sopenharmony_ci * @base_rb_stts: base virtual address of receive buffer status for all queues 34062306a36Sopenharmony_ci * @base_rb_stts_dma: base physical address of receive buffer status 34162306a36Sopenharmony_ci * @supported_dma_mask: DMA mask to validate the actual address against, 34262306a36Sopenharmony_ci * will be DMA_BIT_MASK(11) or DMA_BIT_MASK(12) depending on the device 34362306a36Sopenharmony_ci * @alloc_page_lock: spinlock for the page allocator 34462306a36Sopenharmony_ci * @alloc_page: allocated page to still use parts of 34562306a36Sopenharmony_ci * @alloc_page_used: how much of the allocated page was already used (bytes) 34662306a36Sopenharmony_ci * @imr_status: imr dma state machine 34762306a36Sopenharmony_ci * @wait_queue_head_t: imr wait queue for dma completion 34862306a36Sopenharmony_ci * @rf_name: name/version of the CRF, if any 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_cistruct iwl_trans_pcie { 35162306a36Sopenharmony_ci struct iwl_rxq *rxq; 35262306a36Sopenharmony_ci struct iwl_rx_mem_buffer *rx_pool; 35362306a36Sopenharmony_ci struct iwl_rx_mem_buffer **global_table; 35462306a36Sopenharmony_ci struct iwl_rb_allocator rba; 35562306a36Sopenharmony_ci union { 35662306a36Sopenharmony_ci struct iwl_context_info *ctxt_info; 35762306a36Sopenharmony_ci struct iwl_context_info_gen3 *ctxt_info_gen3; 35862306a36Sopenharmony_ci }; 35962306a36Sopenharmony_ci struct iwl_prph_info *prph_info; 36062306a36Sopenharmony_ci struct iwl_prph_scratch *prph_scratch; 36162306a36Sopenharmony_ci void *iml; 36262306a36Sopenharmony_ci dma_addr_t ctxt_info_dma_addr; 36362306a36Sopenharmony_ci dma_addr_t prph_info_dma_addr; 36462306a36Sopenharmony_ci dma_addr_t prph_scratch_dma_addr; 36562306a36Sopenharmony_ci dma_addr_t iml_dma_addr; 36662306a36Sopenharmony_ci struct iwl_trans *trans; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci struct net_device napi_dev; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* INT ICT Table */ 37162306a36Sopenharmony_ci __le32 *ict_tbl; 37262306a36Sopenharmony_ci dma_addr_t ict_tbl_dma; 37362306a36Sopenharmony_ci int ict_index; 37462306a36Sopenharmony_ci bool use_ict; 37562306a36Sopenharmony_ci bool is_down, opmode_down; 37662306a36Sopenharmony_ci s8 debug_rfkill; 37762306a36Sopenharmony_ci struct isr_statistics isr_stats; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci spinlock_t irq_lock; 38062306a36Sopenharmony_ci struct mutex mutex; 38162306a36Sopenharmony_ci u32 inta_mask; 38262306a36Sopenharmony_ci u32 scd_base_addr; 38362306a36Sopenharmony_ci struct iwl_dma_ptr kw; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* pnvm data */ 38662306a36Sopenharmony_ci struct iwl_dram_regions pnvm_data; 38762306a36Sopenharmony_ci struct iwl_dram_regions reduced_tables_data; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci struct iwl_txq *txq_memory; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* PCI bus related data */ 39262306a36Sopenharmony_ci struct pci_dev *pci_dev; 39362306a36Sopenharmony_ci u8 __iomem *hw_base; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci bool ucode_write_complete; 39662306a36Sopenharmony_ci bool sx_complete; 39762306a36Sopenharmony_ci wait_queue_head_t ucode_write_waitq; 39862306a36Sopenharmony_ci wait_queue_head_t sx_waitq; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci u8 n_no_reclaim_cmds; 40162306a36Sopenharmony_ci u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; 40262306a36Sopenharmony_ci u16 num_rx_bufs; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci enum iwl_amsdu_size rx_buf_size; 40562306a36Sopenharmony_ci bool scd_set_active; 40662306a36Sopenharmony_ci bool pcie_dbg_dumped_once; 40762306a36Sopenharmony_ci u32 rx_page_order; 40862306a36Sopenharmony_ci u32 rx_buf_bytes; 40962306a36Sopenharmony_ci u32 supported_dma_mask; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* allocator lock for the two values below */ 41262306a36Sopenharmony_ci spinlock_t alloc_page_lock; 41362306a36Sopenharmony_ci struct page *alloc_page; 41462306a36Sopenharmony_ci u32 alloc_page_used; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /*protect hw register */ 41762306a36Sopenharmony_ci spinlock_t reg_lock; 41862306a36Sopenharmony_ci bool cmd_hold_nic_awake; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 42162306a36Sopenharmony_ci struct cont_rec fw_mon_data; 42262306a36Sopenharmony_ci#endif 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci struct msix_entry msix_entries[IWL_MAX_RX_HW_QUEUES]; 42562306a36Sopenharmony_ci bool msix_enabled; 42662306a36Sopenharmony_ci u8 shared_vec_mask; 42762306a36Sopenharmony_ci u32 alloc_vecs; 42862306a36Sopenharmony_ci u32 def_irq; 42962306a36Sopenharmony_ci u32 fh_init_mask; 43062306a36Sopenharmony_ci u32 hw_init_mask; 43162306a36Sopenharmony_ci u32 fh_mask; 43262306a36Sopenharmony_ci u32 hw_mask; 43362306a36Sopenharmony_ci cpumask_t affinity_mask[IWL_MAX_RX_HW_QUEUES]; 43462306a36Sopenharmony_ci u16 tx_cmd_queue_size; 43562306a36Sopenharmony_ci bool in_rescan; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci void *base_rb_stts; 43862306a36Sopenharmony_ci dma_addr_t base_rb_stts_dma; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci bool fw_reset_handshake; 44162306a36Sopenharmony_ci enum iwl_pcie_fw_reset_state fw_reset_state; 44262306a36Sopenharmony_ci wait_queue_head_t fw_reset_waitq; 44362306a36Sopenharmony_ci enum iwl_pcie_imr_status imr_status; 44462306a36Sopenharmony_ci wait_queue_head_t imr_waitq; 44562306a36Sopenharmony_ci char rf_name[32]; 44662306a36Sopenharmony_ci}; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic inline struct iwl_trans_pcie * 44962306a36Sopenharmony_ciIWL_TRANS_GET_PCIE_TRANS(struct iwl_trans *trans) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci return (void *)trans->trans_specific; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic inline void iwl_pcie_clear_irq(struct iwl_trans *trans, int queue) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci /* 45762306a36Sopenharmony_ci * Before sending the interrupt the HW disables it to prevent 45862306a36Sopenharmony_ci * a nested interrupt. This is done by writing 1 to the corresponding 45962306a36Sopenharmony_ci * bit in the mask register. After handling the interrupt, it should be 46062306a36Sopenharmony_ci * re-enabled by clearing this bit. This register is defined as 46162306a36Sopenharmony_ci * write 1 clear (W1C) register, meaning that it's being clear 46262306a36Sopenharmony_ci * by writing 1 to the bit. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci iwl_write32(trans, CSR_MSIX_AUTOMASK_ST_AD, BIT(queue)); 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic inline struct iwl_trans * 46862306a36Sopenharmony_ciiwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci return container_of((void *)trans_pcie, struct iwl_trans, 47162306a36Sopenharmony_ci trans_specific); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/* 47562306a36Sopenharmony_ci * Convention: trans API functions: iwl_trans_pcie_XXX 47662306a36Sopenharmony_ci * Other functions: iwl_pcie_XXX 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_cistruct iwl_trans 47962306a36Sopenharmony_ci*iwl_trans_pcie_alloc(struct pci_dev *pdev, 48062306a36Sopenharmony_ci const struct pci_device_id *ent, 48162306a36Sopenharmony_ci const struct iwl_cfg_trans_params *cfg_trans); 48262306a36Sopenharmony_civoid iwl_trans_pcie_free(struct iwl_trans *trans); 48362306a36Sopenharmony_civoid iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_regions, 48462306a36Sopenharmony_ci struct device *dev); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cibool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans); 48762306a36Sopenharmony_ci#define _iwl_trans_pcie_grab_nic_access(trans) \ 48862306a36Sopenharmony_ci __cond_lock(nic_access_nobh, \ 48962306a36Sopenharmony_ci likely(__iwl_trans_pcie_grab_nic_access(trans))) 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci/***************************************************** 49262306a36Sopenharmony_ci* RX 49362306a36Sopenharmony_ci******************************************************/ 49462306a36Sopenharmony_ciint iwl_pcie_rx_init(struct iwl_trans *trans); 49562306a36Sopenharmony_ciint iwl_pcie_gen2_rx_init(struct iwl_trans *trans); 49662306a36Sopenharmony_ciirqreturn_t iwl_pcie_msix_isr(int irq, void *data); 49762306a36Sopenharmony_ciirqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id); 49862306a36Sopenharmony_ciirqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id); 49962306a36Sopenharmony_ciirqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id); 50062306a36Sopenharmony_ciint iwl_pcie_rx_stop(struct iwl_trans *trans); 50162306a36Sopenharmony_civoid iwl_pcie_rx_free(struct iwl_trans *trans); 50262306a36Sopenharmony_civoid iwl_pcie_free_rbs_pool(struct iwl_trans *trans); 50362306a36Sopenharmony_civoid iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq); 50462306a36Sopenharmony_civoid iwl_pcie_rx_napi_sync(struct iwl_trans *trans); 50562306a36Sopenharmony_civoid iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority, 50662306a36Sopenharmony_ci struct iwl_rxq *rxq); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci/***************************************************** 50962306a36Sopenharmony_ci* ICT - interrupt handling 51062306a36Sopenharmony_ci******************************************************/ 51162306a36Sopenharmony_ciirqreturn_t iwl_pcie_isr(int irq, void *data); 51262306a36Sopenharmony_ciint iwl_pcie_alloc_ict(struct iwl_trans *trans); 51362306a36Sopenharmony_civoid iwl_pcie_free_ict(struct iwl_trans *trans); 51462306a36Sopenharmony_civoid iwl_pcie_reset_ict(struct iwl_trans *trans); 51562306a36Sopenharmony_civoid iwl_pcie_disable_ict(struct iwl_trans *trans); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci/***************************************************** 51862306a36Sopenharmony_ci* TX / HCMD 51962306a36Sopenharmony_ci******************************************************/ 52062306a36Sopenharmony_ciint iwl_pcie_tx_init(struct iwl_trans *trans); 52162306a36Sopenharmony_civoid iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); 52262306a36Sopenharmony_ciint iwl_pcie_tx_stop(struct iwl_trans *trans); 52362306a36Sopenharmony_civoid iwl_pcie_tx_free(struct iwl_trans *trans); 52462306a36Sopenharmony_cibool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, 52562306a36Sopenharmony_ci const struct iwl_trans_txq_scd_cfg *cfg, 52662306a36Sopenharmony_ci unsigned int wdg_timeout); 52762306a36Sopenharmony_civoid iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, 52862306a36Sopenharmony_ci bool configure_scd); 52962306a36Sopenharmony_civoid iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id, 53062306a36Sopenharmony_ci bool shared_mode); 53162306a36Sopenharmony_ciint iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, 53262306a36Sopenharmony_ci struct iwl_device_tx_cmd *dev_cmd, int txq_id); 53362306a36Sopenharmony_civoid iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans); 53462306a36Sopenharmony_ciint iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); 53562306a36Sopenharmony_civoid iwl_pcie_hcmd_complete(struct iwl_trans *trans, 53662306a36Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb); 53762306a36Sopenharmony_civoid iwl_trans_pcie_tx_reset(struct iwl_trans *trans); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci/***************************************************** 54062306a36Sopenharmony_ci* Error handling 54162306a36Sopenharmony_ci******************************************************/ 54262306a36Sopenharmony_civoid iwl_pcie_dump_csr(struct iwl_trans *trans); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci/***************************************************** 54562306a36Sopenharmony_ci* Helpers 54662306a36Sopenharmony_ci******************************************************/ 54762306a36Sopenharmony_cistatic inline void _iwl_disable_interrupts(struct iwl_trans *trans) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci clear_bit(STATUS_INT_ENABLED, &trans->status); 55262306a36Sopenharmony_ci if (!trans_pcie->msix_enabled) { 55362306a36Sopenharmony_ci /* disable interrupts from uCode/NIC to host */ 55462306a36Sopenharmony_ci iwl_write32(trans, CSR_INT_MASK, 0x00000000); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* acknowledge/clear/reset any interrupts still pending 55762306a36Sopenharmony_ci * from uCode or flow handler (Rx/Tx DMA) */ 55862306a36Sopenharmony_ci iwl_write32(trans, CSR_INT, 0xffffffff); 55962306a36Sopenharmony_ci iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff); 56062306a36Sopenharmony_ci } else { 56162306a36Sopenharmony_ci /* disable all the interrupt we might use */ 56262306a36Sopenharmony_ci iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, 56362306a36Sopenharmony_ci trans_pcie->fh_init_mask); 56462306a36Sopenharmony_ci iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, 56562306a36Sopenharmony_ci trans_pcie->hw_init_mask); 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic inline int iwl_pcie_get_num_sections(const struct fw_img *fw, 57162306a36Sopenharmony_ci int start) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci int i = 0; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci while (start < fw->num_sec && 57662306a36Sopenharmony_ci fw->sec[start].offset != CPU1_CPU2_SEPARATOR_SECTION && 57762306a36Sopenharmony_ci fw->sec[start].offset != PAGING_SEPARATOR_SECTION) { 57862306a36Sopenharmony_ci start++; 57962306a36Sopenharmony_ci i++; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return i; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic inline void iwl_pcie_ctxt_info_free_fw_img(struct iwl_trans *trans) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci struct iwl_self_init_dram *dram = &trans->init_dram; 58862306a36Sopenharmony_ci int i; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (!dram->fw) { 59162306a36Sopenharmony_ci WARN_ON(dram->fw_cnt); 59262306a36Sopenharmony_ci return; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci for (i = 0; i < dram->fw_cnt; i++) 59662306a36Sopenharmony_ci dma_free_coherent(trans->dev, dram->fw[i].size, 59762306a36Sopenharmony_ci dram->fw[i].block, dram->fw[i].physical); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci kfree(dram->fw); 60062306a36Sopenharmony_ci dram->fw_cnt = 0; 60162306a36Sopenharmony_ci dram->fw = NULL; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic inline void iwl_disable_interrupts(struct iwl_trans *trans) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci spin_lock_bh(&trans_pcie->irq_lock); 60962306a36Sopenharmony_ci _iwl_disable_interrupts(trans); 61062306a36Sopenharmony_ci spin_unlock_bh(&trans_pcie->irq_lock); 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic inline void _iwl_enable_interrupts(struct iwl_trans *trans) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci IWL_DEBUG_ISR(trans, "Enabling interrupts\n"); 61862306a36Sopenharmony_ci set_bit(STATUS_INT_ENABLED, &trans->status); 61962306a36Sopenharmony_ci if (!trans_pcie->msix_enabled) { 62062306a36Sopenharmony_ci trans_pcie->inta_mask = CSR_INI_SET_MASK; 62162306a36Sopenharmony_ci iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); 62262306a36Sopenharmony_ci } else { 62362306a36Sopenharmony_ci /* 62462306a36Sopenharmony_ci * fh/hw_mask keeps all the unmasked causes. 62562306a36Sopenharmony_ci * Unlike msi, in msix cause is enabled when it is unset. 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_ci trans_pcie->hw_mask = trans_pcie->hw_init_mask; 62862306a36Sopenharmony_ci trans_pcie->fh_mask = trans_pcie->fh_init_mask; 62962306a36Sopenharmony_ci iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, 63062306a36Sopenharmony_ci ~trans_pcie->fh_mask); 63162306a36Sopenharmony_ci iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, 63262306a36Sopenharmony_ci ~trans_pcie->hw_mask); 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic inline void iwl_enable_interrupts(struct iwl_trans *trans) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci spin_lock_bh(&trans_pcie->irq_lock); 64162306a36Sopenharmony_ci _iwl_enable_interrupts(trans); 64262306a36Sopenharmony_ci spin_unlock_bh(&trans_pcie->irq_lock); 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_cistatic inline void iwl_enable_hw_int_msk_msix(struct iwl_trans *trans, u32 msk) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, ~msk); 64962306a36Sopenharmony_ci trans_pcie->hw_mask = msk; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic inline void iwl_enable_fh_int_msk_msix(struct iwl_trans *trans, u32 msk) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, ~msk); 65762306a36Sopenharmony_ci trans_pcie->fh_mask = msk; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic inline void iwl_enable_fw_load_int(struct iwl_trans *trans) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci IWL_DEBUG_ISR(trans, "Enabling FW load interrupt\n"); 66562306a36Sopenharmony_ci if (!trans_pcie->msix_enabled) { 66662306a36Sopenharmony_ci trans_pcie->inta_mask = CSR_INT_BIT_FH_TX; 66762306a36Sopenharmony_ci iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); 66862306a36Sopenharmony_ci } else { 66962306a36Sopenharmony_ci iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, 67062306a36Sopenharmony_ci trans_pcie->hw_init_mask); 67162306a36Sopenharmony_ci iwl_enable_fh_int_msk_msix(trans, 67262306a36Sopenharmony_ci MSIX_FH_INT_CAUSES_D2S_CH0_NUM); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic inline void iwl_enable_fw_load_int_ctx_info(struct iwl_trans *trans) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci IWL_DEBUG_ISR(trans, "Enabling ALIVE interrupt only\n"); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (!trans_pcie->msix_enabled) { 68362306a36Sopenharmony_ci /* 68462306a36Sopenharmony_ci * When we'll receive the ALIVE interrupt, the ISR will call 68562306a36Sopenharmony_ci * iwl_enable_fw_load_int_ctx_info again to set the ALIVE 68662306a36Sopenharmony_ci * interrupt (which is not really needed anymore) but also the 68762306a36Sopenharmony_ci * RX interrupt which will allow us to receive the ALIVE 68862306a36Sopenharmony_ci * notification (which is Rx) and continue the flow. 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_ci trans_pcie->inta_mask = CSR_INT_BIT_ALIVE | CSR_INT_BIT_FH_RX; 69162306a36Sopenharmony_ci iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); 69262306a36Sopenharmony_ci } else { 69362306a36Sopenharmony_ci iwl_enable_hw_int_msk_msix(trans, 69462306a36Sopenharmony_ci MSIX_HW_INT_CAUSES_REG_ALIVE); 69562306a36Sopenharmony_ci /* 69662306a36Sopenharmony_ci * Leave all the FH causes enabled to get the ALIVE 69762306a36Sopenharmony_ci * notification. 69862306a36Sopenharmony_ci */ 69962306a36Sopenharmony_ci iwl_enable_fh_int_msk_msix(trans, trans_pcie->fh_init_mask); 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic inline const char *queue_name(struct device *dev, 70462306a36Sopenharmony_ci struct iwl_trans_pcie *trans_p, int i) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci if (trans_p->shared_vec_mask) { 70762306a36Sopenharmony_ci int vec = trans_p->shared_vec_mask & 70862306a36Sopenharmony_ci IWL_SHARED_IRQ_FIRST_RSS ? 1 : 0; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (i == 0) 71162306a36Sopenharmony_ci return DRV_NAME ":shared_IRQ"; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci return devm_kasprintf(dev, GFP_KERNEL, 71462306a36Sopenharmony_ci DRV_NAME ":queue_%d", i + vec); 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci if (i == 0) 71762306a36Sopenharmony_ci return DRV_NAME ":default_queue"; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (i == trans_p->alloc_vecs - 1) 72062306a36Sopenharmony_ci return DRV_NAME ":exception"; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return devm_kasprintf(dev, GFP_KERNEL, 72362306a36Sopenharmony_ci DRV_NAME ":queue_%d", i); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic inline void iwl_enable_rfkill_int(struct iwl_trans *trans) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n"); 73162306a36Sopenharmony_ci if (!trans_pcie->msix_enabled) { 73262306a36Sopenharmony_ci trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL; 73362306a36Sopenharmony_ci iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); 73462306a36Sopenharmony_ci } else { 73562306a36Sopenharmony_ci iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, 73662306a36Sopenharmony_ci trans_pcie->fh_init_mask); 73762306a36Sopenharmony_ci iwl_enable_hw_int_msk_msix(trans, 73862306a36Sopenharmony_ci MSIX_HW_INT_CAUSES_REG_RF_KILL); 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_9000) { 74262306a36Sopenharmony_ci /* 74362306a36Sopenharmony_ci * On 9000-series devices this bit isn't enabled by default, so 74462306a36Sopenharmony_ci * when we power down the device we need set the bit to allow it 74562306a36Sopenharmony_ci * to wake up the PCI-E bus for RF-kill interrupts. 74662306a36Sopenharmony_ci */ 74762306a36Sopenharmony_ci iwl_set_bit(trans, CSR_GP_CNTRL, 74862306a36Sopenharmony_ci CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN); 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_civoid iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans, bool from_irq); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic inline bool iwl_is_rfkill_set(struct iwl_trans *trans) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci lockdep_assert_held(&trans_pcie->mutex); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (trans_pcie->debug_rfkill == 1) 76162306a36Sopenharmony_ci return true; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci return !(iwl_read32(trans, CSR_GP_CNTRL) & 76462306a36Sopenharmony_ci CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic inline void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, 76862306a36Sopenharmony_ci u32 reg, u32 mask, u32 value) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci u32 v; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUG 77362306a36Sopenharmony_ci WARN_ON_ONCE(value & ~mask); 77462306a36Sopenharmony_ci#endif 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci v = iwl_read32(trans, reg); 77762306a36Sopenharmony_ci v &= ~mask; 77862306a36Sopenharmony_ci v |= value; 77962306a36Sopenharmony_ci iwl_write32(trans, reg, v); 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans, 78362306a36Sopenharmony_ci u32 reg, u32 mask) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0); 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, 78962306a36Sopenharmony_ci u32 reg, u32 mask) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic inline bool iwl_pcie_dbg_on(struct iwl_trans *trans) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci return (trans->dbg.dest_tlv || iwl_trans_dbg_ini_valid(trans)); 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_civoid iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state, bool from_irq); 80062306a36Sopenharmony_civoid iwl_trans_pcie_dump_regs(struct iwl_trans *trans); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 80362306a36Sopenharmony_civoid iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans); 80462306a36Sopenharmony_ci#else 80562306a36Sopenharmony_cistatic inline void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) { } 80662306a36Sopenharmony_ci#endif 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_civoid iwl_pcie_rx_allocator_work(struct work_struct *data); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci/* common functions that are used by gen2 transport */ 81162306a36Sopenharmony_ciint iwl_pcie_gen2_apm_init(struct iwl_trans *trans); 81262306a36Sopenharmony_civoid iwl_pcie_apm_config(struct iwl_trans *trans); 81362306a36Sopenharmony_ciint iwl_pcie_prepare_card_hw(struct iwl_trans *trans); 81462306a36Sopenharmony_civoid iwl_pcie_synchronize_irqs(struct iwl_trans *trans); 81562306a36Sopenharmony_cibool iwl_pcie_check_hw_rf_kill(struct iwl_trans *trans); 81662306a36Sopenharmony_civoid iwl_trans_pcie_handle_stop_rfkill(struct iwl_trans *trans, 81762306a36Sopenharmony_ci bool was_in_rfkill); 81862306a36Sopenharmony_civoid iwl_pcie_apm_stop_master(struct iwl_trans *trans); 81962306a36Sopenharmony_civoid iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie); 82062306a36Sopenharmony_ciint iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, 82162306a36Sopenharmony_ci struct iwl_dma_ptr *ptr, size_t size); 82262306a36Sopenharmony_civoid iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr); 82362306a36Sopenharmony_civoid iwl_pcie_apply_destination(struct iwl_trans *trans); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci/* common functions that are used by gen3 transport */ 82662306a36Sopenharmony_civoid iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci/* transport gen 2 exported functions */ 82962306a36Sopenharmony_ciint iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, 83062306a36Sopenharmony_ci const struct fw_img *fw, bool run_in_rfkill); 83162306a36Sopenharmony_civoid iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr); 83262306a36Sopenharmony_ciint iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans, 83362306a36Sopenharmony_ci struct iwl_host_cmd *cmd); 83462306a36Sopenharmony_civoid iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans); 83562306a36Sopenharmony_civoid _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans); 83662306a36Sopenharmony_civoid iwl_pcie_d3_complete_suspend(struct iwl_trans *trans, 83762306a36Sopenharmony_ci bool test, bool reset); 83862306a36Sopenharmony_ciint iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, 83962306a36Sopenharmony_ci struct iwl_host_cmd *cmd); 84062306a36Sopenharmony_ciint iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, 84162306a36Sopenharmony_ci struct iwl_host_cmd *cmd); 84262306a36Sopenharmony_civoid iwl_trans_pcie_copy_imr_fh(struct iwl_trans *trans, 84362306a36Sopenharmony_ci u32 dst_addr, u64 src_addr, u32 byte_cnt); 84462306a36Sopenharmony_ciint iwl_trans_pcie_copy_imr(struct iwl_trans *trans, 84562306a36Sopenharmony_ci u32 dst_addr, u64 src_addr, u32 byte_cnt); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci#endif /* __iwl_trans_int_pcie_h__ */ 848