162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2005-2014, 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_h__
862306a36Sopenharmony_ci#define __iwl_trans_h__
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/ieee80211.h>
1162306a36Sopenharmony_ci#include <linux/mm.h> /* for page_address */
1262306a36Sopenharmony_ci#include <linux/lockdep.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "iwl-debug.h"
1662306a36Sopenharmony_ci#include "iwl-config.h"
1762306a36Sopenharmony_ci#include "fw/img.h"
1862306a36Sopenharmony_ci#include "iwl-op-mode.h"
1962306a36Sopenharmony_ci#include <linux/firmware.h>
2062306a36Sopenharmony_ci#include "fw/api/cmdhdr.h"
2162306a36Sopenharmony_ci#include "fw/api/txq.h"
2262306a36Sopenharmony_ci#include "fw/api/dbg-tlv.h"
2362306a36Sopenharmony_ci#include "iwl-dbg-tlv.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/**
2662306a36Sopenharmony_ci * DOC: Transport layer - what is it ?
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * The transport layer is the layer that deals with the HW directly. It provides
2962306a36Sopenharmony_ci * an abstraction of the underlying HW to the upper layer. The transport layer
3062306a36Sopenharmony_ci * doesn't provide any policy, algorithm or anything of this kind, but only
3162306a36Sopenharmony_ci * mechanisms to make the HW do something. It is not completely stateless but
3262306a36Sopenharmony_ci * close to it.
3362306a36Sopenharmony_ci * We will have an implementation for each different supported bus.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/**
3762306a36Sopenharmony_ci * DOC: Life cycle of the transport layer
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * The transport layer has a very precise life cycle.
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci *	1) A helper function is called during the module initialization and
4262306a36Sopenharmony_ci *	   registers the bus driver's ops with the transport's alloc function.
4362306a36Sopenharmony_ci *	2) Bus's probe calls to the transport layer's allocation functions.
4462306a36Sopenharmony_ci *	   Of course this function is bus specific.
4562306a36Sopenharmony_ci *	3) This allocation functions will spawn the upper layer which will
4662306a36Sopenharmony_ci *	   register mac80211.
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci *	4) At some point (i.e. mac80211's start call), the op_mode will call
4962306a36Sopenharmony_ci *	   the following sequence:
5062306a36Sopenharmony_ci *	   start_hw
5162306a36Sopenharmony_ci *	   start_fw
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci *	5) Then when finished (or reset):
5462306a36Sopenharmony_ci *	   stop_device
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci *	6) Eventually, the free function will be called.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* default preset 0 (start from bit 16)*/
6062306a36Sopenharmony_ci#define IWL_FW_DBG_DOMAIN_POS	16
6162306a36Sopenharmony_ci#define IWL_FW_DBG_DOMAIN	BIT(IWL_FW_DBG_DOMAIN_POS)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define IWL_TRANS_FW_DBG_DOMAIN(trans)	IWL_FW_INI_DOMAIN_ALWAYS_ON
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define FH_RSCSR_FRAME_SIZE_MSK		0x00003FFF	/* bits 0-13 */
6662306a36Sopenharmony_ci#define FH_RSCSR_FRAME_INVALID		0x55550000
6762306a36Sopenharmony_ci#define FH_RSCSR_FRAME_ALIGN		0x40
6862306a36Sopenharmony_ci#define FH_RSCSR_RPA_EN			BIT(25)
6962306a36Sopenharmony_ci#define FH_RSCSR_RADA_EN		BIT(26)
7062306a36Sopenharmony_ci#define FH_RSCSR_RXQ_POS		16
7162306a36Sopenharmony_ci#define FH_RSCSR_RXQ_MASK		0x3F0000
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct iwl_rx_packet {
7462306a36Sopenharmony_ci	/*
7562306a36Sopenharmony_ci	 * The first 4 bytes of the RX frame header contain both the RX frame
7662306a36Sopenharmony_ci	 * size and some flags.
7762306a36Sopenharmony_ci	 * Bit fields:
7862306a36Sopenharmony_ci	 * 31:    flag flush RB request
7962306a36Sopenharmony_ci	 * 30:    flag ignore TC (terminal counter) request
8062306a36Sopenharmony_ci	 * 29:    flag fast IRQ request
8162306a36Sopenharmony_ci	 * 28-27: Reserved
8262306a36Sopenharmony_ci	 * 26:    RADA enabled
8362306a36Sopenharmony_ci	 * 25:    Offload enabled
8462306a36Sopenharmony_ci	 * 24:    RPF enabled
8562306a36Sopenharmony_ci	 * 23:    RSS enabled
8662306a36Sopenharmony_ci	 * 22:    Checksum enabled
8762306a36Sopenharmony_ci	 * 21-16: RX queue
8862306a36Sopenharmony_ci	 * 15-14: Reserved
8962306a36Sopenharmony_ci	 * 13-00: RX frame size
9062306a36Sopenharmony_ci	 */
9162306a36Sopenharmony_ci	__le32 len_n_flags;
9262306a36Sopenharmony_ci	struct iwl_cmd_header hdr;
9362306a36Sopenharmony_ci	u8 data[];
9462306a36Sopenharmony_ci} __packed;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic inline u32 iwl_rx_packet_len(const struct iwl_rx_packet *pkt)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	return iwl_rx_packet_len(pkt) - sizeof(pkt->hdr);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/**
10762306a36Sopenharmony_ci * enum CMD_MODE - how to send the host commands ?
10862306a36Sopenharmony_ci *
10962306a36Sopenharmony_ci * @CMD_ASYNC: Return right away and don't wait for the response
11062306a36Sopenharmony_ci * @CMD_WANT_SKB: Not valid with CMD_ASYNC. The caller needs the buffer of
11162306a36Sopenharmony_ci *	the response. The caller needs to call iwl_free_resp when done.
11262306a36Sopenharmony_ci * @CMD_WANT_ASYNC_CALLBACK: the op_mode's async callback function must be
11362306a36Sopenharmony_ci *	called after this command completes. Valid only with CMD_ASYNC.
11462306a36Sopenharmony_ci * @CMD_SEND_IN_D3: Allow the command to be sent in D3 mode, relevant to
11562306a36Sopenharmony_ci *	SUSPEND and RESUME commands. We are in D3 mode when we set
11662306a36Sopenharmony_ci *	trans->system_pm_mode to IWL_PLAT_PM_MODE_D3.
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_cienum CMD_MODE {
11962306a36Sopenharmony_ci	CMD_ASYNC		= BIT(0),
12062306a36Sopenharmony_ci	CMD_WANT_SKB		= BIT(1),
12162306a36Sopenharmony_ci	CMD_SEND_IN_RFKILL	= BIT(2),
12262306a36Sopenharmony_ci	CMD_WANT_ASYNC_CALLBACK	= BIT(3),
12362306a36Sopenharmony_ci	CMD_SEND_IN_D3          = BIT(4),
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#define DEF_CMD_PAYLOAD_SIZE 320
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/**
12962306a36Sopenharmony_ci * struct iwl_device_cmd
13062306a36Sopenharmony_ci *
13162306a36Sopenharmony_ci * For allocation of the command and tx queues, this establishes the overall
13262306a36Sopenharmony_ci * size of the largest command we send to uCode, except for commands that
13362306a36Sopenharmony_ci * aren't fully copied and use other TFD space.
13462306a36Sopenharmony_ci */
13562306a36Sopenharmony_cistruct iwl_device_cmd {
13662306a36Sopenharmony_ci	union {
13762306a36Sopenharmony_ci		struct {
13862306a36Sopenharmony_ci			struct iwl_cmd_header hdr;	/* uCode API */
13962306a36Sopenharmony_ci			u8 payload[DEF_CMD_PAYLOAD_SIZE];
14062306a36Sopenharmony_ci		};
14162306a36Sopenharmony_ci		struct {
14262306a36Sopenharmony_ci			struct iwl_cmd_header_wide hdr_wide;
14362306a36Sopenharmony_ci			u8 payload_wide[DEF_CMD_PAYLOAD_SIZE -
14462306a36Sopenharmony_ci					sizeof(struct iwl_cmd_header_wide) +
14562306a36Sopenharmony_ci					sizeof(struct iwl_cmd_header)];
14662306a36Sopenharmony_ci		};
14762306a36Sopenharmony_ci	};
14862306a36Sopenharmony_ci} __packed;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/**
15162306a36Sopenharmony_ci * struct iwl_device_tx_cmd - buffer for TX command
15262306a36Sopenharmony_ci * @hdr: the header
15362306a36Sopenharmony_ci * @payload: the payload placeholder
15462306a36Sopenharmony_ci *
15562306a36Sopenharmony_ci * The actual structure is sized dynamically according to need.
15662306a36Sopenharmony_ci */
15762306a36Sopenharmony_cistruct iwl_device_tx_cmd {
15862306a36Sopenharmony_ci	struct iwl_cmd_header hdr;
15962306a36Sopenharmony_ci	u8 payload[];
16062306a36Sopenharmony_ci} __packed;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/*
16562306a36Sopenharmony_ci * number of transfer buffers (fragments) per transmit frame descriptor;
16662306a36Sopenharmony_ci * this is just the driver's idea, the hardware supports 20
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_ci#define IWL_MAX_CMD_TBS_PER_TFD	2
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/* We need 2 entries for the TX command and header, and another one might
17162306a36Sopenharmony_ci * be needed for potential data in the SKB's head. The remaining ones can
17262306a36Sopenharmony_ci * be used for frags.
17362306a36Sopenharmony_ci */
17462306a36Sopenharmony_ci#define IWL_TRANS_MAX_FRAGS(trans) ((trans)->txqs.tfd.max_tbs - 3)
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/**
17762306a36Sopenharmony_ci * enum iwl_hcmd_dataflag - flag for each one of the chunks of the command
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * @IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's
18062306a36Sopenharmony_ci *	ring. The transport layer doesn't map the command's buffer to DMA, but
18162306a36Sopenharmony_ci *	rather copies it to a previously allocated DMA buffer. This flag tells
18262306a36Sopenharmony_ci *	the transport layer not to copy the command, but to map the existing
18362306a36Sopenharmony_ci *	buffer (that is passed in) instead. This saves the memcpy and allows
18462306a36Sopenharmony_ci *	commands that are bigger than the fixed buffer to be submitted.
18562306a36Sopenharmony_ci *	Note that a TFD entry after a NOCOPY one cannot be a normal copied one.
18662306a36Sopenharmony_ci * @IWL_HCMD_DFL_DUP: Only valid without NOCOPY, duplicate the memory for this
18762306a36Sopenharmony_ci *	chunk internally and free it again after the command completes. This
18862306a36Sopenharmony_ci *	can (currently) be used only once per command.
18962306a36Sopenharmony_ci *	Note that a TFD entry after a DUP one cannot be a normal copied one.
19062306a36Sopenharmony_ci */
19162306a36Sopenharmony_cienum iwl_hcmd_dataflag {
19262306a36Sopenharmony_ci	IWL_HCMD_DFL_NOCOPY	= BIT(0),
19362306a36Sopenharmony_ci	IWL_HCMD_DFL_DUP	= BIT(1),
19462306a36Sopenharmony_ci};
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cienum iwl_error_event_table_status {
19762306a36Sopenharmony_ci	IWL_ERROR_EVENT_TABLE_LMAC1 = BIT(0),
19862306a36Sopenharmony_ci	IWL_ERROR_EVENT_TABLE_LMAC2 = BIT(1),
19962306a36Sopenharmony_ci	IWL_ERROR_EVENT_TABLE_UMAC = BIT(2),
20062306a36Sopenharmony_ci	IWL_ERROR_EVENT_TABLE_TCM1 = BIT(3),
20162306a36Sopenharmony_ci	IWL_ERROR_EVENT_TABLE_TCM2 = BIT(4),
20262306a36Sopenharmony_ci	IWL_ERROR_EVENT_TABLE_RCM1 = BIT(5),
20362306a36Sopenharmony_ci	IWL_ERROR_EVENT_TABLE_RCM2 = BIT(6),
20462306a36Sopenharmony_ci};
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/**
20762306a36Sopenharmony_ci * struct iwl_host_cmd - Host command to the uCode
20862306a36Sopenharmony_ci *
20962306a36Sopenharmony_ci * @data: array of chunks that composes the data of the host command
21062306a36Sopenharmony_ci * @resp_pkt: response packet, if %CMD_WANT_SKB was set
21162306a36Sopenharmony_ci * @_rx_page_order: (internally used to free response packet)
21262306a36Sopenharmony_ci * @_rx_page_addr: (internally used to free response packet)
21362306a36Sopenharmony_ci * @flags: can be CMD_*
21462306a36Sopenharmony_ci * @len: array of the lengths of the chunks in data
21562306a36Sopenharmony_ci * @dataflags: IWL_HCMD_DFL_*
21662306a36Sopenharmony_ci * @id: command id of the host command, for wide commands encoding the
21762306a36Sopenharmony_ci *	version and group as well
21862306a36Sopenharmony_ci */
21962306a36Sopenharmony_cistruct iwl_host_cmd {
22062306a36Sopenharmony_ci	const void *data[IWL_MAX_CMD_TBS_PER_TFD];
22162306a36Sopenharmony_ci	struct iwl_rx_packet *resp_pkt;
22262306a36Sopenharmony_ci	unsigned long _rx_page_addr;
22362306a36Sopenharmony_ci	u32 _rx_page_order;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	u32 flags;
22662306a36Sopenharmony_ci	u32 id;
22762306a36Sopenharmony_ci	u16 len[IWL_MAX_CMD_TBS_PER_TFD];
22862306a36Sopenharmony_ci	u8 dataflags[IWL_MAX_CMD_TBS_PER_TFD];
22962306a36Sopenharmony_ci};
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic inline void iwl_free_resp(struct iwl_host_cmd *cmd)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	free_pages(cmd->_rx_page_addr, cmd->_rx_page_order);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistruct iwl_rx_cmd_buffer {
23762306a36Sopenharmony_ci	struct page *_page;
23862306a36Sopenharmony_ci	int _offset;
23962306a36Sopenharmony_ci	bool _page_stolen;
24062306a36Sopenharmony_ci	u32 _rx_page_order;
24162306a36Sopenharmony_ci	unsigned int truesize;
24262306a36Sopenharmony_ci};
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic inline void *rxb_addr(struct iwl_rx_cmd_buffer *r)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	return (void *)((unsigned long)page_address(r->_page) + r->_offset);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic inline int rxb_offset(struct iwl_rx_cmd_buffer *r)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	return r->_offset;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	r->_page_stolen = true;
25762306a36Sopenharmony_ci	get_page(r->_page);
25862306a36Sopenharmony_ci	return r->_page;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	__free_pages(r->_page, r->_rx_page_order);
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci#define MAX_NO_RECLAIM_CMDS	6
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/*
27162306a36Sopenharmony_ci * Maximum number of HW queues the transport layer
27262306a36Sopenharmony_ci * currently supports
27362306a36Sopenharmony_ci */
27462306a36Sopenharmony_ci#define IWL_MAX_HW_QUEUES		32
27562306a36Sopenharmony_ci#define IWL_MAX_TVQM_QUEUES		512
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci#define IWL_MAX_TID_COUNT	8
27862306a36Sopenharmony_ci#define IWL_MGMT_TID		15
27962306a36Sopenharmony_ci#define IWL_FRAME_LIMIT	64
28062306a36Sopenharmony_ci#define IWL_MAX_RX_HW_QUEUES	16
28162306a36Sopenharmony_ci#define IWL_9000_MAX_RX_HW_QUEUES	6
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/**
28462306a36Sopenharmony_ci * enum iwl_wowlan_status - WoWLAN image/device status
28562306a36Sopenharmony_ci * @IWL_D3_STATUS_ALIVE: firmware is still running after resume
28662306a36Sopenharmony_ci * @IWL_D3_STATUS_RESET: device was reset while suspended
28762306a36Sopenharmony_ci */
28862306a36Sopenharmony_cienum iwl_d3_status {
28962306a36Sopenharmony_ci	IWL_D3_STATUS_ALIVE,
29062306a36Sopenharmony_ci	IWL_D3_STATUS_RESET,
29162306a36Sopenharmony_ci};
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci/**
29462306a36Sopenharmony_ci * enum iwl_trans_status: transport status flags
29562306a36Sopenharmony_ci * @STATUS_SYNC_HCMD_ACTIVE: a SYNC command is being processed
29662306a36Sopenharmony_ci * @STATUS_DEVICE_ENABLED: APM is enabled
29762306a36Sopenharmony_ci * @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
29862306a36Sopenharmony_ci * @STATUS_INT_ENABLED: interrupts are enabled
29962306a36Sopenharmony_ci * @STATUS_RFKILL_HW: the actual HW state of the RF-kill switch
30062306a36Sopenharmony_ci * @STATUS_RFKILL_OPMODE: RF-kill state reported to opmode
30162306a36Sopenharmony_ci * @STATUS_FW_ERROR: the fw is in error state
30262306a36Sopenharmony_ci * @STATUS_TRANS_GOING_IDLE: shutting down the trans, only special commands
30362306a36Sopenharmony_ci *	are sent
30462306a36Sopenharmony_ci * @STATUS_TRANS_IDLE: the trans is idle - general commands are not to be sent
30562306a36Sopenharmony_ci * @STATUS_TRANS_DEAD: trans is dead - avoid any read/write operation
30662306a36Sopenharmony_ci * @STATUS_SUPPRESS_CMD_ERROR_ONCE: suppress "FW error in SYNC CMD" once,
30762306a36Sopenharmony_ci *	e.g. for testing
30862306a36Sopenharmony_ci */
30962306a36Sopenharmony_cienum iwl_trans_status {
31062306a36Sopenharmony_ci	STATUS_SYNC_HCMD_ACTIVE,
31162306a36Sopenharmony_ci	STATUS_DEVICE_ENABLED,
31262306a36Sopenharmony_ci	STATUS_TPOWER_PMI,
31362306a36Sopenharmony_ci	STATUS_INT_ENABLED,
31462306a36Sopenharmony_ci	STATUS_RFKILL_HW,
31562306a36Sopenharmony_ci	STATUS_RFKILL_OPMODE,
31662306a36Sopenharmony_ci	STATUS_FW_ERROR,
31762306a36Sopenharmony_ci	STATUS_TRANS_GOING_IDLE,
31862306a36Sopenharmony_ci	STATUS_TRANS_IDLE,
31962306a36Sopenharmony_ci	STATUS_TRANS_DEAD,
32062306a36Sopenharmony_ci	STATUS_SUPPRESS_CMD_ERROR_ONCE,
32162306a36Sopenharmony_ci};
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic inline int
32462306a36Sopenharmony_ciiwl_trans_get_rb_size_order(enum iwl_amsdu_size rb_size)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	switch (rb_size) {
32762306a36Sopenharmony_ci	case IWL_AMSDU_2K:
32862306a36Sopenharmony_ci		return get_order(2 * 1024);
32962306a36Sopenharmony_ci	case IWL_AMSDU_4K:
33062306a36Sopenharmony_ci		return get_order(4 * 1024);
33162306a36Sopenharmony_ci	case IWL_AMSDU_8K:
33262306a36Sopenharmony_ci		return get_order(8 * 1024);
33362306a36Sopenharmony_ci	case IWL_AMSDU_12K:
33462306a36Sopenharmony_ci		return get_order(16 * 1024);
33562306a36Sopenharmony_ci	default:
33662306a36Sopenharmony_ci		WARN_ON(1);
33762306a36Sopenharmony_ci		return -1;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic inline int
34262306a36Sopenharmony_ciiwl_trans_get_rb_size(enum iwl_amsdu_size rb_size)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	switch (rb_size) {
34562306a36Sopenharmony_ci	case IWL_AMSDU_2K:
34662306a36Sopenharmony_ci		return 2 * 1024;
34762306a36Sopenharmony_ci	case IWL_AMSDU_4K:
34862306a36Sopenharmony_ci		return 4 * 1024;
34962306a36Sopenharmony_ci	case IWL_AMSDU_8K:
35062306a36Sopenharmony_ci		return 8 * 1024;
35162306a36Sopenharmony_ci	case IWL_AMSDU_12K:
35262306a36Sopenharmony_ci		return 16 * 1024;
35362306a36Sopenharmony_ci	default:
35462306a36Sopenharmony_ci		WARN_ON(1);
35562306a36Sopenharmony_ci		return 0;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistruct iwl_hcmd_names {
36062306a36Sopenharmony_ci	u8 cmd_id;
36162306a36Sopenharmony_ci	const char *const cmd_name;
36262306a36Sopenharmony_ci};
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci#define HCMD_NAME(x)	\
36562306a36Sopenharmony_ci	{ .cmd_id = x, .cmd_name = #x }
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistruct iwl_hcmd_arr {
36862306a36Sopenharmony_ci	const struct iwl_hcmd_names *arr;
36962306a36Sopenharmony_ci	int size;
37062306a36Sopenharmony_ci};
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci#define HCMD_ARR(x)	\
37362306a36Sopenharmony_ci	{ .arr = x, .size = ARRAY_SIZE(x) }
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci/**
37662306a36Sopenharmony_ci * struct iwl_dump_sanitize_ops - dump sanitization operations
37762306a36Sopenharmony_ci * @frob_txf: Scrub the TX FIFO data
37862306a36Sopenharmony_ci * @frob_hcmd: Scrub a host command, the %hcmd pointer is to the header
37962306a36Sopenharmony_ci *	but that might be short or long (&struct iwl_cmd_header or
38062306a36Sopenharmony_ci *	&struct iwl_cmd_header_wide)
38162306a36Sopenharmony_ci * @frob_mem: Scrub memory data
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_cistruct iwl_dump_sanitize_ops {
38462306a36Sopenharmony_ci	void (*frob_txf)(void *ctx, void *buf, size_t buflen);
38562306a36Sopenharmony_ci	void (*frob_hcmd)(void *ctx, void *hcmd, size_t buflen);
38662306a36Sopenharmony_ci	void (*frob_mem)(void *ctx, u32 mem_addr, void *mem, size_t buflen);
38762306a36Sopenharmony_ci};
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/**
39062306a36Sopenharmony_ci * struct iwl_trans_config - transport configuration
39162306a36Sopenharmony_ci *
39262306a36Sopenharmony_ci * @op_mode: pointer to the upper layer.
39362306a36Sopenharmony_ci * @cmd_queue: the index of the command queue.
39462306a36Sopenharmony_ci *	Must be set before start_fw.
39562306a36Sopenharmony_ci * @cmd_fifo: the fifo for host commands
39662306a36Sopenharmony_ci * @cmd_q_wdg_timeout: the timeout of the watchdog timer for the command queue.
39762306a36Sopenharmony_ci * @no_reclaim_cmds: Some devices erroneously don't set the
39862306a36Sopenharmony_ci *	SEQ_RX_FRAME bit on some notifications, this is the
39962306a36Sopenharmony_ci *	list of such notifications to filter. Max length is
40062306a36Sopenharmony_ci *	%MAX_NO_RECLAIM_CMDS.
40162306a36Sopenharmony_ci * @n_no_reclaim_cmds: # of commands in list
40262306a36Sopenharmony_ci * @rx_buf_size: RX buffer size needed for A-MSDUs
40362306a36Sopenharmony_ci *	if unset 4k will be the RX buffer size
40462306a36Sopenharmony_ci * @bc_table_dword: set to true if the BC table expects the byte count to be
40562306a36Sopenharmony_ci *	in DWORD (as opposed to bytes)
40662306a36Sopenharmony_ci * @scd_set_active: should the transport configure the SCD for HCMD queue
40762306a36Sopenharmony_ci * @command_groups: array of command groups, each member is an array of the
40862306a36Sopenharmony_ci *	commands in the group; for debugging only
40962306a36Sopenharmony_ci * @command_groups_size: number of command groups, to avoid illegal access
41062306a36Sopenharmony_ci * @cb_data_offs: offset inside skb->cb to store transport data at, must have
41162306a36Sopenharmony_ci *	space for at least two pointers
41262306a36Sopenharmony_ci * @fw_reset_handshake: firmware supports reset flow handshake
41362306a36Sopenharmony_ci * @queue_alloc_cmd_ver: queue allocation command version, set to 0
41462306a36Sopenharmony_ci *	for using the older SCD_QUEUE_CFG, set to the version of
41562306a36Sopenharmony_ci *	SCD_QUEUE_CONFIG_CMD otherwise.
41662306a36Sopenharmony_ci */
41762306a36Sopenharmony_cistruct iwl_trans_config {
41862306a36Sopenharmony_ci	struct iwl_op_mode *op_mode;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	u8 cmd_queue;
42162306a36Sopenharmony_ci	u8 cmd_fifo;
42262306a36Sopenharmony_ci	unsigned int cmd_q_wdg_timeout;
42362306a36Sopenharmony_ci	const u8 *no_reclaim_cmds;
42462306a36Sopenharmony_ci	unsigned int n_no_reclaim_cmds;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	enum iwl_amsdu_size rx_buf_size;
42762306a36Sopenharmony_ci	bool bc_table_dword;
42862306a36Sopenharmony_ci	bool scd_set_active;
42962306a36Sopenharmony_ci	const struct iwl_hcmd_arr *command_groups;
43062306a36Sopenharmony_ci	int command_groups_size;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	u8 cb_data_offs;
43362306a36Sopenharmony_ci	bool fw_reset_handshake;
43462306a36Sopenharmony_ci	u8 queue_alloc_cmd_ver;
43562306a36Sopenharmony_ci};
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistruct iwl_trans_dump_data {
43862306a36Sopenharmony_ci	u32 len;
43962306a36Sopenharmony_ci	u8 data[];
44062306a36Sopenharmony_ci};
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistruct iwl_trans;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistruct iwl_trans_txq_scd_cfg {
44562306a36Sopenharmony_ci	u8 fifo;
44662306a36Sopenharmony_ci	u8 sta_id;
44762306a36Sopenharmony_ci	u8 tid;
44862306a36Sopenharmony_ci	bool aggregate;
44962306a36Sopenharmony_ci	int frame_limit;
45062306a36Sopenharmony_ci};
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci/**
45362306a36Sopenharmony_ci * struct iwl_trans_rxq_dma_data - RX queue DMA data
45462306a36Sopenharmony_ci * @fr_bd_cb: DMA address of free BD cyclic buffer
45562306a36Sopenharmony_ci * @fr_bd_wid: Initial write index of the free BD cyclic buffer
45662306a36Sopenharmony_ci * @urbd_stts_wrptr: DMA address of urbd_stts_wrptr
45762306a36Sopenharmony_ci * @ur_bd_cb: DMA address of used BD cyclic buffer
45862306a36Sopenharmony_ci */
45962306a36Sopenharmony_cistruct iwl_trans_rxq_dma_data {
46062306a36Sopenharmony_ci	u64 fr_bd_cb;
46162306a36Sopenharmony_ci	u32 fr_bd_wid;
46262306a36Sopenharmony_ci	u64 urbd_stts_wrptr;
46362306a36Sopenharmony_ci	u64 ur_bd_cb;
46462306a36Sopenharmony_ci};
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci/* maximal number of DRAM MAP entries supported by FW */
46762306a36Sopenharmony_ci#define IPC_DRAM_MAP_ENTRY_NUM_MAX 64
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci/**
47062306a36Sopenharmony_ci * struct iwl_pnvm_image - contains info about the parsed pnvm image
47162306a36Sopenharmony_ci * @chunks: array of pointers to pnvm payloads and their sizes
47262306a36Sopenharmony_ci * @n_chunks: the number of the pnvm payloads.
47362306a36Sopenharmony_ci * @version: the version of the loaded PNVM image
47462306a36Sopenharmony_ci */
47562306a36Sopenharmony_cistruct iwl_pnvm_image {
47662306a36Sopenharmony_ci	struct {
47762306a36Sopenharmony_ci		const void *data;
47862306a36Sopenharmony_ci		u32 len;
47962306a36Sopenharmony_ci	} chunks[IPC_DRAM_MAP_ENTRY_NUM_MAX];
48062306a36Sopenharmony_ci	u32 n_chunks;
48162306a36Sopenharmony_ci	u32 version;
48262306a36Sopenharmony_ci};
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci/**
48562306a36Sopenharmony_ci * struct iwl_trans_ops - transport specific operations
48662306a36Sopenharmony_ci *
48762306a36Sopenharmony_ci * All the handlers MUST be implemented
48862306a36Sopenharmony_ci *
48962306a36Sopenharmony_ci * @start_hw: starts the HW. From that point on, the HW can send interrupts.
49062306a36Sopenharmony_ci *	May sleep.
49162306a36Sopenharmony_ci * @op_mode_leave: Turn off the HW RF kill indication if on
49262306a36Sopenharmony_ci *	May sleep
49362306a36Sopenharmony_ci * @start_fw: allocates and inits all the resources for the transport
49462306a36Sopenharmony_ci *	layer. Also kick a fw image.
49562306a36Sopenharmony_ci *	May sleep
49662306a36Sopenharmony_ci * @fw_alive: called when the fw sends alive notification. If the fw provides
49762306a36Sopenharmony_ci *	the SCD base address in SRAM, then provide it here, or 0 otherwise.
49862306a36Sopenharmony_ci *	May sleep
49962306a36Sopenharmony_ci * @stop_device: stops the whole device (embedded CPU put to reset) and stops
50062306a36Sopenharmony_ci *	the HW. From that point on, the HW will be stopped but will still issue
50162306a36Sopenharmony_ci *	an interrupt if the HW RF kill switch is triggered.
50262306a36Sopenharmony_ci *	This callback must do the right thing and not crash even if %start_hw()
50362306a36Sopenharmony_ci *	was called but not &start_fw(). May sleep.
50462306a36Sopenharmony_ci * @d3_suspend: put the device into the correct mode for WoWLAN during
50562306a36Sopenharmony_ci *	suspend. This is optional, if not implemented WoWLAN will not be
50662306a36Sopenharmony_ci *	supported. This callback may sleep.
50762306a36Sopenharmony_ci * @d3_resume: resume the device after WoWLAN, enabling the opmode to
50862306a36Sopenharmony_ci *	talk to the WoWLAN image to get its status. This is optional, if not
50962306a36Sopenharmony_ci *	implemented WoWLAN will not be supported. This callback may sleep.
51062306a36Sopenharmony_ci * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted.
51162306a36Sopenharmony_ci *	If RFkill is asserted in the middle of a SYNC host command, it must
51262306a36Sopenharmony_ci *	return -ERFKILL straight away.
51362306a36Sopenharmony_ci *	May sleep only if CMD_ASYNC is not set
51462306a36Sopenharmony_ci * @tx: send an skb. The transport relies on the op_mode to zero the
51562306a36Sopenharmony_ci *	the ieee80211_tx_info->driver_data. If the MPDU is an A-MSDU, all
51662306a36Sopenharmony_ci *	the CSUM will be taken care of (TCP CSUM and IP header in case of
51762306a36Sopenharmony_ci *	IPv4). If the MPDU is a single MSDU, the op_mode must compute the IP
51862306a36Sopenharmony_ci *	header if it is IPv4.
51962306a36Sopenharmony_ci *	Must be atomic
52062306a36Sopenharmony_ci * @reclaim: free packet until ssn. Returns a list of freed packets.
52162306a36Sopenharmony_ci *	Must be atomic
52262306a36Sopenharmony_ci * @txq_enable: setup a queue. To setup an AC queue, use the
52362306a36Sopenharmony_ci *	iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before
52462306a36Sopenharmony_ci *	this one. The op_mode must not configure the HCMD queue. The scheduler
52562306a36Sopenharmony_ci *	configuration may be %NULL, in which case the hardware will not be
52662306a36Sopenharmony_ci *	configured. If true is returned, the operation mode needs to increment
52762306a36Sopenharmony_ci *	the sequence number of the packets routed to this queue because of a
52862306a36Sopenharmony_ci *	hardware scheduler bug. May sleep.
52962306a36Sopenharmony_ci * @txq_disable: de-configure a Tx queue to send AMPDUs
53062306a36Sopenharmony_ci *	Must be atomic
53162306a36Sopenharmony_ci * @txq_set_shared_mode: change Tx queue shared/unshared marking
53262306a36Sopenharmony_ci * @wait_tx_queues_empty: wait until tx queues are empty. May sleep.
53362306a36Sopenharmony_ci * @wait_txq_empty: wait until specific tx queue is empty. May sleep.
53462306a36Sopenharmony_ci * @freeze_txq_timer: prevents the timer of the queue from firing until the
53562306a36Sopenharmony_ci *	queue is set to awake. Must be atomic.
53662306a36Sopenharmony_ci * @block_txq_ptrs: stop updating the write pointers of the Tx queues. Note
53762306a36Sopenharmony_ci *	that the transport needs to refcount the calls since this function
53862306a36Sopenharmony_ci *	will be called several times with block = true, and then the queues
53962306a36Sopenharmony_ci *	need to be unblocked only after the same number of calls with
54062306a36Sopenharmony_ci *	block = false.
54162306a36Sopenharmony_ci * @write8: write a u8 to a register at offset ofs from the BAR
54262306a36Sopenharmony_ci * @write32: write a u32 to a register at offset ofs from the BAR
54362306a36Sopenharmony_ci * @read32: read a u32 register at offset ofs from the BAR
54462306a36Sopenharmony_ci * @read_prph: read a DWORD from a periphery register
54562306a36Sopenharmony_ci * @write_prph: write a DWORD to a periphery register
54662306a36Sopenharmony_ci * @read_mem: read device's SRAM in DWORD
54762306a36Sopenharmony_ci * @write_mem: write device's SRAM in DWORD. If %buf is %NULL, then the memory
54862306a36Sopenharmony_ci *	will be zeroed.
54962306a36Sopenharmony_ci * @read_config32: read a u32 value from the device's config space at
55062306a36Sopenharmony_ci *	the given offset.
55162306a36Sopenharmony_ci * @configure: configure parameters required by the transport layer from
55262306a36Sopenharmony_ci *	the op_mode. May be called several times before start_fw, can't be
55362306a36Sopenharmony_ci *	called after that.
55462306a36Sopenharmony_ci * @set_pmi: set the power pmi state
55562306a36Sopenharmony_ci * @grab_nic_access: wake the NIC to be able to access non-HBUS regs.
55662306a36Sopenharmony_ci *	Sleeping is not allowed between grab_nic_access and
55762306a36Sopenharmony_ci *	release_nic_access.
55862306a36Sopenharmony_ci * @release_nic_access: let the NIC go to sleep. The "flags" parameter
55962306a36Sopenharmony_ci *	must be the same one that was sent before to the grab_nic_access.
56062306a36Sopenharmony_ci * @set_bits_mask - set SRAM register according to value and mask.
56162306a36Sopenharmony_ci * @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last
56262306a36Sopenharmony_ci *	TX'ed commands and similar. The buffer will be vfree'd by the caller.
56362306a36Sopenharmony_ci *	Note that the transport must fill in the proper file headers.
56462306a36Sopenharmony_ci * @debugfs_cleanup: used in the driver unload flow to make a proper cleanup
56562306a36Sopenharmony_ci *	of the trans debugfs
56662306a36Sopenharmony_ci * @load_pnvm: save the pnvm data in DRAM
56762306a36Sopenharmony_ci * @set_pnvm: set the pnvm data in the prph scratch buffer, inside the
56862306a36Sopenharmony_ci *	context info.
56962306a36Sopenharmony_ci * @load_reduce_power: copy reduce power table to the corresponding DRAM memory
57062306a36Sopenharmony_ci * @set_reduce_power: set reduce power table addresses in the sratch buffer
57162306a36Sopenharmony_ci * @interrupts: disable/enable interrupts to transport
57262306a36Sopenharmony_ci */
57362306a36Sopenharmony_cistruct iwl_trans_ops {
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	int (*start_hw)(struct iwl_trans *iwl_trans);
57662306a36Sopenharmony_ci	void (*op_mode_leave)(struct iwl_trans *iwl_trans);
57762306a36Sopenharmony_ci	int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
57862306a36Sopenharmony_ci			bool run_in_rfkill);
57962306a36Sopenharmony_ci	void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
58062306a36Sopenharmony_ci	void (*stop_device)(struct iwl_trans *trans);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	int (*d3_suspend)(struct iwl_trans *trans, bool test, bool reset);
58362306a36Sopenharmony_ci	int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status,
58462306a36Sopenharmony_ci			 bool test, bool reset);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	int (*tx)(struct iwl_trans *trans, struct sk_buff *skb,
58962306a36Sopenharmony_ci		  struct iwl_device_tx_cmd *dev_cmd, int queue);
59062306a36Sopenharmony_ci	void (*reclaim)(struct iwl_trans *trans, int queue, int ssn,
59162306a36Sopenharmony_ci			struct sk_buff_head *skbs, bool is_flush);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	void (*set_q_ptrs)(struct iwl_trans *trans, int queue, int ptr);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	bool (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn,
59662306a36Sopenharmony_ci			   const struct iwl_trans_txq_scd_cfg *cfg,
59762306a36Sopenharmony_ci			   unsigned int queue_wdg_timeout);
59862306a36Sopenharmony_ci	void (*txq_disable)(struct iwl_trans *trans, int queue,
59962306a36Sopenharmony_ci			    bool configure_scd);
60062306a36Sopenharmony_ci	/* 22000 functions */
60162306a36Sopenharmony_ci	int (*txq_alloc)(struct iwl_trans *trans, u32 flags,
60262306a36Sopenharmony_ci			 u32 sta_mask, u8 tid,
60362306a36Sopenharmony_ci			 int size, unsigned int queue_wdg_timeout);
60462306a36Sopenharmony_ci	void (*txq_free)(struct iwl_trans *trans, int queue);
60562306a36Sopenharmony_ci	int (*rxq_dma_data)(struct iwl_trans *trans, int queue,
60662306a36Sopenharmony_ci			    struct iwl_trans_rxq_dma_data *data);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	void (*txq_set_shared_mode)(struct iwl_trans *trans, u32 txq_id,
60962306a36Sopenharmony_ci				    bool shared);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	int (*wait_tx_queues_empty)(struct iwl_trans *trans, u32 txq_bm);
61262306a36Sopenharmony_ci	int (*wait_txq_empty)(struct iwl_trans *trans, int queue);
61362306a36Sopenharmony_ci	void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs,
61462306a36Sopenharmony_ci				 bool freeze);
61562306a36Sopenharmony_ci	void (*block_txq_ptrs)(struct iwl_trans *trans, bool block);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val);
61862306a36Sopenharmony_ci	void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val);
61962306a36Sopenharmony_ci	u32 (*read32)(struct iwl_trans *trans, u32 ofs);
62062306a36Sopenharmony_ci	u32 (*read_prph)(struct iwl_trans *trans, u32 ofs);
62162306a36Sopenharmony_ci	void (*write_prph)(struct iwl_trans *trans, u32 ofs, u32 val);
62262306a36Sopenharmony_ci	int (*read_mem)(struct iwl_trans *trans, u32 addr,
62362306a36Sopenharmony_ci			void *buf, int dwords);
62462306a36Sopenharmony_ci	int (*write_mem)(struct iwl_trans *trans, u32 addr,
62562306a36Sopenharmony_ci			 const void *buf, int dwords);
62662306a36Sopenharmony_ci	int (*read_config32)(struct iwl_trans *trans, u32 ofs, u32 *val);
62762306a36Sopenharmony_ci	void (*configure)(struct iwl_trans *trans,
62862306a36Sopenharmony_ci			  const struct iwl_trans_config *trans_cfg);
62962306a36Sopenharmony_ci	void (*set_pmi)(struct iwl_trans *trans, bool state);
63062306a36Sopenharmony_ci	int (*sw_reset)(struct iwl_trans *trans, bool retake_ownership);
63162306a36Sopenharmony_ci	bool (*grab_nic_access)(struct iwl_trans *trans);
63262306a36Sopenharmony_ci	void (*release_nic_access)(struct iwl_trans *trans);
63362306a36Sopenharmony_ci	void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask,
63462306a36Sopenharmony_ci			      u32 value);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans,
63762306a36Sopenharmony_ci						 u32 dump_mask,
63862306a36Sopenharmony_ci						 const struct iwl_dump_sanitize_ops *sanitize_ops,
63962306a36Sopenharmony_ci						 void *sanitize_ctx);
64062306a36Sopenharmony_ci	void (*debugfs_cleanup)(struct iwl_trans *trans);
64162306a36Sopenharmony_ci	void (*sync_nmi)(struct iwl_trans *trans);
64262306a36Sopenharmony_ci	int (*load_pnvm)(struct iwl_trans *trans,
64362306a36Sopenharmony_ci			 const struct iwl_pnvm_image *pnvm_payloads,
64462306a36Sopenharmony_ci			 const struct iwl_ucode_capabilities *capa);
64562306a36Sopenharmony_ci	void (*set_pnvm)(struct iwl_trans *trans,
64662306a36Sopenharmony_ci			 const struct iwl_ucode_capabilities *capa);
64762306a36Sopenharmony_ci	int (*load_reduce_power)(struct iwl_trans *trans,
64862306a36Sopenharmony_ci				 const struct iwl_pnvm_image *payloads,
64962306a36Sopenharmony_ci				 const struct iwl_ucode_capabilities *capa);
65062306a36Sopenharmony_ci	void (*set_reduce_power)(struct iwl_trans *trans,
65162306a36Sopenharmony_ci				 const struct iwl_ucode_capabilities *capa);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	void (*interrupts)(struct iwl_trans *trans, bool enable);
65462306a36Sopenharmony_ci	int (*imr_dma_data)(struct iwl_trans *trans,
65562306a36Sopenharmony_ci			    u32 dst_addr, u64 src_addr,
65662306a36Sopenharmony_ci			    u32 byte_cnt);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci};
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci/**
66162306a36Sopenharmony_ci * enum iwl_trans_state - state of the transport layer
66262306a36Sopenharmony_ci *
66362306a36Sopenharmony_ci * @IWL_TRANS_NO_FW: firmware wasn't started yet, or crashed
66462306a36Sopenharmony_ci * @IWL_TRANS_FW_STARTED: FW was started, but not alive yet
66562306a36Sopenharmony_ci * @IWL_TRANS_FW_ALIVE: FW has sent an alive response
66662306a36Sopenharmony_ci */
66762306a36Sopenharmony_cienum iwl_trans_state {
66862306a36Sopenharmony_ci	IWL_TRANS_NO_FW,
66962306a36Sopenharmony_ci	IWL_TRANS_FW_STARTED,
67062306a36Sopenharmony_ci	IWL_TRANS_FW_ALIVE,
67162306a36Sopenharmony_ci};
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci/**
67462306a36Sopenharmony_ci * DOC: Platform power management
67562306a36Sopenharmony_ci *
67662306a36Sopenharmony_ci * In system-wide power management the entire platform goes into a low
67762306a36Sopenharmony_ci * power state (e.g. idle or suspend to RAM) at the same time and the
67862306a36Sopenharmony_ci * device is configured as a wakeup source for the entire platform.
67962306a36Sopenharmony_ci * This is usually triggered by userspace activity (e.g. the user
68062306a36Sopenharmony_ci * presses the suspend button or a power management daemon decides to
68162306a36Sopenharmony_ci * put the platform in low power mode).  The device's behavior in this
68262306a36Sopenharmony_ci * mode is dictated by the wake-on-WLAN configuration.
68362306a36Sopenharmony_ci *
68462306a36Sopenharmony_ci * The terms used for the device's behavior are as follows:
68562306a36Sopenharmony_ci *
68662306a36Sopenharmony_ci *	- D0: the device is fully powered and the host is awake;
68762306a36Sopenharmony_ci *	- D3: the device is in low power mode and only reacts to
68862306a36Sopenharmony_ci *		specific events (e.g. magic-packet received or scan
68962306a36Sopenharmony_ci *		results found);
69062306a36Sopenharmony_ci *
69162306a36Sopenharmony_ci * These terms reflect the power modes in the firmware and are not to
69262306a36Sopenharmony_ci * be confused with the physical device power state.
69362306a36Sopenharmony_ci */
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci/**
69662306a36Sopenharmony_ci * enum iwl_plat_pm_mode - platform power management mode
69762306a36Sopenharmony_ci *
69862306a36Sopenharmony_ci * This enumeration describes the device's platform power management
69962306a36Sopenharmony_ci * behavior when in system-wide suspend (i.e WoWLAN).
70062306a36Sopenharmony_ci *
70162306a36Sopenharmony_ci * @IWL_PLAT_PM_MODE_DISABLED: power management is disabled for this
70262306a36Sopenharmony_ci *	device.  In system-wide suspend mode, it means that the all
70362306a36Sopenharmony_ci *	connections will be closed automatically by mac80211 before
70462306a36Sopenharmony_ci *	the platform is suspended.
70562306a36Sopenharmony_ci * @IWL_PLAT_PM_MODE_D3: the device goes into D3 mode (i.e. WoWLAN).
70662306a36Sopenharmony_ci */
70762306a36Sopenharmony_cienum iwl_plat_pm_mode {
70862306a36Sopenharmony_ci	IWL_PLAT_PM_MODE_DISABLED,
70962306a36Sopenharmony_ci	IWL_PLAT_PM_MODE_D3,
71062306a36Sopenharmony_ci};
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci/**
71362306a36Sopenharmony_ci * enum iwl_ini_cfg_state
71462306a36Sopenharmony_ci * @IWL_INI_CFG_STATE_NOT_LOADED: no debug cfg was given
71562306a36Sopenharmony_ci * @IWL_INI_CFG_STATE_LOADED: debug cfg was found and loaded
71662306a36Sopenharmony_ci * @IWL_INI_CFG_STATE_CORRUPTED: debug cfg was found and some of the TLVs
71762306a36Sopenharmony_ci *	are corrupted. The rest of the debug TLVs will still be used
71862306a36Sopenharmony_ci */
71962306a36Sopenharmony_cienum iwl_ini_cfg_state {
72062306a36Sopenharmony_ci	IWL_INI_CFG_STATE_NOT_LOADED,
72162306a36Sopenharmony_ci	IWL_INI_CFG_STATE_LOADED,
72262306a36Sopenharmony_ci	IWL_INI_CFG_STATE_CORRUPTED,
72362306a36Sopenharmony_ci};
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci/* Max time to wait for nmi interrupt */
72662306a36Sopenharmony_ci#define IWL_TRANS_NMI_TIMEOUT (HZ / 4)
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci/**
72962306a36Sopenharmony_ci * struct iwl_dram_data
73062306a36Sopenharmony_ci * @physical: page phy pointer
73162306a36Sopenharmony_ci * @block: pointer to the allocated block/page
73262306a36Sopenharmony_ci * @size: size of the block/page
73362306a36Sopenharmony_ci */
73462306a36Sopenharmony_cistruct iwl_dram_data {
73562306a36Sopenharmony_ci	dma_addr_t physical;
73662306a36Sopenharmony_ci	void *block;
73762306a36Sopenharmony_ci	int size;
73862306a36Sopenharmony_ci};
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci/**
74162306a36Sopenharmony_ci * @drams: array of several DRAM areas that contains the pnvm and power
74262306a36Sopenharmony_ci *	reduction table payloads.
74362306a36Sopenharmony_ci * @n_regions: number of DRAM regions that were allocated
74462306a36Sopenharmony_ci * @prph_scratch_mem_desc: points to a structure allocated in dram,
74562306a36Sopenharmony_ci *	designed to show FW where all the payloads are.
74662306a36Sopenharmony_ci */
74762306a36Sopenharmony_cistruct iwl_dram_regions {
74862306a36Sopenharmony_ci	struct iwl_dram_data drams[IPC_DRAM_MAP_ENTRY_NUM_MAX];
74962306a36Sopenharmony_ci	struct iwl_dram_data prph_scratch_mem_desc;
75062306a36Sopenharmony_ci	u8 n_regions;
75162306a36Sopenharmony_ci};
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci/**
75462306a36Sopenharmony_ci * struct iwl_fw_mon - fw monitor per allocation id
75562306a36Sopenharmony_ci * @num_frags: number of fragments
75662306a36Sopenharmony_ci * @frags: an array of DRAM buffer fragments
75762306a36Sopenharmony_ci */
75862306a36Sopenharmony_cistruct iwl_fw_mon {
75962306a36Sopenharmony_ci	u32 num_frags;
76062306a36Sopenharmony_ci	struct iwl_dram_data *frags;
76162306a36Sopenharmony_ci};
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci/**
76462306a36Sopenharmony_ci * struct iwl_self_init_dram - dram data used by self init process
76562306a36Sopenharmony_ci * @fw: lmac and umac dram data
76662306a36Sopenharmony_ci * @fw_cnt: total number of items in array
76762306a36Sopenharmony_ci * @paging: paging dram data
76862306a36Sopenharmony_ci * @paging_cnt: total number of items in array
76962306a36Sopenharmony_ci */
77062306a36Sopenharmony_cistruct iwl_self_init_dram {
77162306a36Sopenharmony_ci	struct iwl_dram_data *fw;
77262306a36Sopenharmony_ci	int fw_cnt;
77362306a36Sopenharmony_ci	struct iwl_dram_data *paging;
77462306a36Sopenharmony_ci	int paging_cnt;
77562306a36Sopenharmony_ci};
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci/**
77862306a36Sopenharmony_ci * struct iwl_imr_data - imr dram data used during debug process
77962306a36Sopenharmony_ci * @imr_enable: imr enable status received from fw
78062306a36Sopenharmony_ci * @imr_size: imr dram size received from fw
78162306a36Sopenharmony_ci * @sram_addr: sram address from debug tlv
78262306a36Sopenharmony_ci * @sram_size: sram size from debug tlv
78362306a36Sopenharmony_ci * @imr2sram_remainbyte`: size remained after each dma transfer
78462306a36Sopenharmony_ci * @imr_curr_addr: current dst address used during dma transfer
78562306a36Sopenharmony_ci * @imr_base_addr: imr address received from fw
78662306a36Sopenharmony_ci */
78762306a36Sopenharmony_cistruct iwl_imr_data {
78862306a36Sopenharmony_ci	u32 imr_enable;
78962306a36Sopenharmony_ci	u32 imr_size;
79062306a36Sopenharmony_ci	u32 sram_addr;
79162306a36Sopenharmony_ci	u32 sram_size;
79262306a36Sopenharmony_ci	u32 imr2sram_remainbyte;
79362306a36Sopenharmony_ci	u64 imr_curr_addr;
79462306a36Sopenharmony_ci	__le64 imr_base_addr;
79562306a36Sopenharmony_ci};
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci#define IWL_TRANS_CURRENT_PC_NAME_MAX_BYTES      32
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci/**
80062306a36Sopenharmony_ci * struct iwl_pc_data - program counter details
80162306a36Sopenharmony_ci * @pc_name: cpu name
80262306a36Sopenharmony_ci * @pc_address: cpu program counter
80362306a36Sopenharmony_ci */
80462306a36Sopenharmony_cistruct iwl_pc_data {
80562306a36Sopenharmony_ci	u8  pc_name[IWL_TRANS_CURRENT_PC_NAME_MAX_BYTES];
80662306a36Sopenharmony_ci	u32 pc_address;
80762306a36Sopenharmony_ci};
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci/**
81062306a36Sopenharmony_ci * struct iwl_trans_debug - transport debug related data
81162306a36Sopenharmony_ci *
81262306a36Sopenharmony_ci * @n_dest_reg: num of reg_ops in %dbg_dest_tlv
81362306a36Sopenharmony_ci * @rec_on: true iff there is a fw debug recording currently active
81462306a36Sopenharmony_ci * @dest_tlv: points to the destination TLV for debug
81562306a36Sopenharmony_ci * @conf_tlv: array of pointers to configuration TLVs for debug
81662306a36Sopenharmony_ci * @trigger_tlv: array of pointers to triggers TLVs for debug
81762306a36Sopenharmony_ci * @lmac_error_event_table: addrs of lmacs error tables
81862306a36Sopenharmony_ci * @umac_error_event_table: addr of umac error table
81962306a36Sopenharmony_ci * @tcm_error_event_table: address(es) of TCM error table(s)
82062306a36Sopenharmony_ci * @rcm_error_event_table: address(es) of RCM error table(s)
82162306a36Sopenharmony_ci * @error_event_table_tlv_status: bitmap that indicates what error table
82262306a36Sopenharmony_ci *	pointers was recevied via TLV. uses enum &iwl_error_event_table_status
82362306a36Sopenharmony_ci * @internal_ini_cfg: internal debug cfg state. Uses &enum iwl_ini_cfg_state
82462306a36Sopenharmony_ci * @external_ini_cfg: external debug cfg state. Uses &enum iwl_ini_cfg_state
82562306a36Sopenharmony_ci * @fw_mon_cfg: debug buffer allocation configuration
82662306a36Sopenharmony_ci * @fw_mon_ini: DRAM buffer fragments per allocation id
82762306a36Sopenharmony_ci * @fw_mon: DRAM buffer for firmware monitor
82862306a36Sopenharmony_ci * @hw_error: equals true if hw error interrupt was received from the FW
82962306a36Sopenharmony_ci * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location
83062306a36Sopenharmony_ci * @active_regions: active regions
83162306a36Sopenharmony_ci * @debug_info_tlv_list: list of debug info TLVs
83262306a36Sopenharmony_ci * @time_point: array of debug time points
83362306a36Sopenharmony_ci * @periodic_trig_list: periodic triggers list
83462306a36Sopenharmony_ci * @domains_bitmap: bitmap of active domains other than &IWL_FW_INI_DOMAIN_ALWAYS_ON
83562306a36Sopenharmony_ci * @ucode_preset: preset based on ucode
83662306a36Sopenharmony_ci * @dump_file_name_ext: dump file name extension
83762306a36Sopenharmony_ci * @dump_file_name_ext_valid: dump file name extension if valid or not
83862306a36Sopenharmony_ci * @num_pc: number of program counter for cpu
83962306a36Sopenharmony_ci * @pc_data: details of the program counter
84062306a36Sopenharmony_ci */
84162306a36Sopenharmony_cistruct iwl_trans_debug {
84262306a36Sopenharmony_ci	u8 n_dest_reg;
84362306a36Sopenharmony_ci	bool rec_on;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	const struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv;
84662306a36Sopenharmony_ci	const struct iwl_fw_dbg_conf_tlv *conf_tlv[FW_DBG_CONF_MAX];
84762306a36Sopenharmony_ci	struct iwl_fw_dbg_trigger_tlv * const *trigger_tlv;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	u32 lmac_error_event_table[2];
85062306a36Sopenharmony_ci	u32 umac_error_event_table;
85162306a36Sopenharmony_ci	u32 tcm_error_event_table[2];
85262306a36Sopenharmony_ci	u32 rcm_error_event_table[2];
85362306a36Sopenharmony_ci	unsigned int error_event_table_tlv_status;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	enum iwl_ini_cfg_state internal_ini_cfg;
85662306a36Sopenharmony_ci	enum iwl_ini_cfg_state external_ini_cfg;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	struct iwl_fw_ini_allocation_tlv fw_mon_cfg[IWL_FW_INI_ALLOCATION_NUM];
85962306a36Sopenharmony_ci	struct iwl_fw_mon fw_mon_ini[IWL_FW_INI_ALLOCATION_NUM];
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	struct iwl_dram_data fw_mon;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	bool hw_error;
86462306a36Sopenharmony_ci	enum iwl_fw_ini_buffer_location ini_dest;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	u64 unsupported_region_msk;
86762306a36Sopenharmony_ci	struct iwl_ucode_tlv *active_regions[IWL_FW_INI_MAX_REGION_ID];
86862306a36Sopenharmony_ci	struct list_head debug_info_tlv_list;
86962306a36Sopenharmony_ci	struct iwl_dbg_tlv_time_point_data
87062306a36Sopenharmony_ci		time_point[IWL_FW_INI_TIME_POINT_NUM];
87162306a36Sopenharmony_ci	struct list_head periodic_trig_list;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	u32 domains_bitmap;
87462306a36Sopenharmony_ci	u32 ucode_preset;
87562306a36Sopenharmony_ci	bool restart_required;
87662306a36Sopenharmony_ci	u32 last_tp_resetfw;
87762306a36Sopenharmony_ci	struct iwl_imr_data imr_data;
87862306a36Sopenharmony_ci	u8 dump_file_name_ext[IWL_FW_INI_MAX_NAME];
87962306a36Sopenharmony_ci	bool dump_file_name_ext_valid;
88062306a36Sopenharmony_ci	u32 num_pc;
88162306a36Sopenharmony_ci	struct iwl_pc_data *pc_data;
88262306a36Sopenharmony_ci};
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cistruct iwl_dma_ptr {
88562306a36Sopenharmony_ci	dma_addr_t dma;
88662306a36Sopenharmony_ci	void *addr;
88762306a36Sopenharmony_ci	size_t size;
88862306a36Sopenharmony_ci};
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_cistruct iwl_cmd_meta {
89162306a36Sopenharmony_ci	/* only for SYNC commands, iff the reply skb is wanted */
89262306a36Sopenharmony_ci	struct iwl_host_cmd *source;
89362306a36Sopenharmony_ci	u32 flags;
89462306a36Sopenharmony_ci	u32 tbs;
89562306a36Sopenharmony_ci};
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci/*
89862306a36Sopenharmony_ci * The FH will write back to the first TB only, so we need to copy some data
89962306a36Sopenharmony_ci * into the buffer regardless of whether it should be mapped or not.
90062306a36Sopenharmony_ci * This indicates how big the first TB must be to include the scratch buffer
90162306a36Sopenharmony_ci * and the assigned PN.
90262306a36Sopenharmony_ci * Since PN location is 8 bytes at offset 12, it's 20 now.
90362306a36Sopenharmony_ci * If we make it bigger then allocations will be bigger and copy slower, so
90462306a36Sopenharmony_ci * that's probably not useful.
90562306a36Sopenharmony_ci */
90662306a36Sopenharmony_ci#define IWL_FIRST_TB_SIZE	20
90762306a36Sopenharmony_ci#define IWL_FIRST_TB_SIZE_ALIGN ALIGN(IWL_FIRST_TB_SIZE, 64)
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cistruct iwl_pcie_txq_entry {
91062306a36Sopenharmony_ci	void *cmd;
91162306a36Sopenharmony_ci	struct sk_buff *skb;
91262306a36Sopenharmony_ci	/* buffer to free after command completes */
91362306a36Sopenharmony_ci	const void *free_buf;
91462306a36Sopenharmony_ci	struct iwl_cmd_meta meta;
91562306a36Sopenharmony_ci};
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_cistruct iwl_pcie_first_tb_buf {
91862306a36Sopenharmony_ci	u8 buf[IWL_FIRST_TB_SIZE_ALIGN];
91962306a36Sopenharmony_ci};
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci/**
92262306a36Sopenharmony_ci * struct iwl_txq - Tx Queue for DMA
92362306a36Sopenharmony_ci * @q: generic Rx/Tx queue descriptor
92462306a36Sopenharmony_ci * @tfds: transmit frame descriptors (DMA memory)
92562306a36Sopenharmony_ci * @first_tb_bufs: start of command headers, including scratch buffers, for
92662306a36Sopenharmony_ci *	the writeback -- this is DMA memory and an array holding one buffer
92762306a36Sopenharmony_ci *	for each command on the queue
92862306a36Sopenharmony_ci * @first_tb_dma: DMA address for the first_tb_bufs start
92962306a36Sopenharmony_ci * @entries: transmit entries (driver state)
93062306a36Sopenharmony_ci * @lock: queue lock
93162306a36Sopenharmony_ci * @stuck_timer: timer that fires if queue gets stuck
93262306a36Sopenharmony_ci * @trans: pointer back to transport (for timer)
93362306a36Sopenharmony_ci * @need_update: indicates need to update read/write index
93462306a36Sopenharmony_ci * @ampdu: true if this queue is an ampdu queue for an specific RA/TID
93562306a36Sopenharmony_ci * @wd_timeout: queue watchdog timeout (jiffies) - per queue
93662306a36Sopenharmony_ci * @frozen: tx stuck queue timer is frozen
93762306a36Sopenharmony_ci * @frozen_expiry_remainder: remember how long until the timer fires
93862306a36Sopenharmony_ci * @bc_tbl: byte count table of the queue (relevant only for gen2 transport)
93962306a36Sopenharmony_ci * @write_ptr: 1-st empty entry (index) host_w
94062306a36Sopenharmony_ci * @read_ptr: last used entry (index) host_r
94162306a36Sopenharmony_ci * @dma_addr:  physical addr for BD's
94262306a36Sopenharmony_ci * @n_window: safe queue window
94362306a36Sopenharmony_ci * @id: queue id
94462306a36Sopenharmony_ci * @low_mark: low watermark, resume queue if free space more than this
94562306a36Sopenharmony_ci * @high_mark: high watermark, stop queue if free space less than this
94662306a36Sopenharmony_ci *
94762306a36Sopenharmony_ci * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
94862306a36Sopenharmony_ci * descriptors) and required locking structures.
94962306a36Sopenharmony_ci *
95062306a36Sopenharmony_ci * Note the difference between TFD_QUEUE_SIZE_MAX and n_window: the hardware
95162306a36Sopenharmony_ci * always assumes 256 descriptors, so TFD_QUEUE_SIZE_MAX is always 256 (unless
95262306a36Sopenharmony_ci * there might be HW changes in the future). For the normal TX
95362306a36Sopenharmony_ci * queues, n_window, which is the size of the software queue data
95462306a36Sopenharmony_ci * is also 256; however, for the command queue, n_window is only
95562306a36Sopenharmony_ci * 32 since we don't need so many commands pending. Since the HW
95662306a36Sopenharmony_ci * still uses 256 BDs for DMA though, TFD_QUEUE_SIZE_MAX stays 256.
95762306a36Sopenharmony_ci * This means that we end up with the following:
95862306a36Sopenharmony_ci *  HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
95962306a36Sopenharmony_ci *  SW entries:           | 0      | ... | 31          |
96062306a36Sopenharmony_ci * where N is a number between 0 and 7. This means that the SW
96162306a36Sopenharmony_ci * data is a window overlayed over the HW queue.
96262306a36Sopenharmony_ci */
96362306a36Sopenharmony_cistruct iwl_txq {
96462306a36Sopenharmony_ci	void *tfds;
96562306a36Sopenharmony_ci	struct iwl_pcie_first_tb_buf *first_tb_bufs;
96662306a36Sopenharmony_ci	dma_addr_t first_tb_dma;
96762306a36Sopenharmony_ci	struct iwl_pcie_txq_entry *entries;
96862306a36Sopenharmony_ci	/* lock for syncing changes on the queue */
96962306a36Sopenharmony_ci	spinlock_t lock;
97062306a36Sopenharmony_ci	unsigned long frozen_expiry_remainder;
97162306a36Sopenharmony_ci	struct timer_list stuck_timer;
97262306a36Sopenharmony_ci	struct iwl_trans *trans;
97362306a36Sopenharmony_ci	bool need_update;
97462306a36Sopenharmony_ci	bool frozen;
97562306a36Sopenharmony_ci	bool ampdu;
97662306a36Sopenharmony_ci	int block;
97762306a36Sopenharmony_ci	unsigned long wd_timeout;
97862306a36Sopenharmony_ci	struct sk_buff_head overflow_q;
97962306a36Sopenharmony_ci	struct iwl_dma_ptr bc_tbl;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	int write_ptr;
98262306a36Sopenharmony_ci	int read_ptr;
98362306a36Sopenharmony_ci	dma_addr_t dma_addr;
98462306a36Sopenharmony_ci	int n_window;
98562306a36Sopenharmony_ci	u32 id;
98662306a36Sopenharmony_ci	int low_mark;
98762306a36Sopenharmony_ci	int high_mark;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	bool overflow_tx;
99062306a36Sopenharmony_ci};
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci/**
99362306a36Sopenharmony_ci * struct iwl_trans_txqs - transport tx queues data
99462306a36Sopenharmony_ci *
99562306a36Sopenharmony_ci * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
99662306a36Sopenharmony_ci * @page_offs: offset from skb->cb to mac header page pointer
99762306a36Sopenharmony_ci * @dev_cmd_offs: offset from skb->cb to iwl_device_tx_cmd pointer
99862306a36Sopenharmony_ci * @queue_used - bit mask of used queues
99962306a36Sopenharmony_ci * @queue_stopped - bit mask of stopped queues
100062306a36Sopenharmony_ci * @scd_bc_tbls: gen1 pointer to the byte count table of the scheduler
100162306a36Sopenharmony_ci * @queue_alloc_cmd_ver: queue allocation command version
100262306a36Sopenharmony_ci */
100362306a36Sopenharmony_cistruct iwl_trans_txqs {
100462306a36Sopenharmony_ci	unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_TVQM_QUEUES)];
100562306a36Sopenharmony_ci	unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_TVQM_QUEUES)];
100662306a36Sopenharmony_ci	struct iwl_txq *txq[IWL_MAX_TVQM_QUEUES];
100762306a36Sopenharmony_ci	struct dma_pool *bc_pool;
100862306a36Sopenharmony_ci	size_t bc_tbl_size;
100962306a36Sopenharmony_ci	bool bc_table_dword;
101062306a36Sopenharmony_ci	u8 page_offs;
101162306a36Sopenharmony_ci	u8 dev_cmd_offs;
101262306a36Sopenharmony_ci	struct iwl_tso_hdr_page __percpu *tso_hdr_page;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	struct {
101562306a36Sopenharmony_ci		u8 fifo;
101662306a36Sopenharmony_ci		u8 q_id;
101762306a36Sopenharmony_ci		unsigned int wdg_timeout;
101862306a36Sopenharmony_ci	} cmd;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	struct {
102162306a36Sopenharmony_ci		u8 max_tbs;
102262306a36Sopenharmony_ci		u16 size;
102362306a36Sopenharmony_ci		u8 addr_size;
102462306a36Sopenharmony_ci	} tfd;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	struct iwl_dma_ptr scd_bc_tbls;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	u8 queue_alloc_cmd_ver;
102962306a36Sopenharmony_ci};
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci/**
103262306a36Sopenharmony_ci * struct iwl_trans - transport common data
103362306a36Sopenharmony_ci *
103462306a36Sopenharmony_ci * @csme_own - true if we couldn't get ownership on the device
103562306a36Sopenharmony_ci * @ops - pointer to iwl_trans_ops
103662306a36Sopenharmony_ci * @op_mode - pointer to the op_mode
103762306a36Sopenharmony_ci * @trans_cfg: the trans-specific configuration part
103862306a36Sopenharmony_ci * @cfg - pointer to the configuration
103962306a36Sopenharmony_ci * @drv - pointer to iwl_drv
104062306a36Sopenharmony_ci * @status: a bit-mask of transport status flags
104162306a36Sopenharmony_ci * @dev - pointer to struct device * that represents the device
104262306a36Sopenharmony_ci * @max_skb_frags: maximum number of fragments an SKB can have when transmitted.
104362306a36Sopenharmony_ci *	0 indicates that frag SKBs (NETIF_F_SG) aren't supported.
104462306a36Sopenharmony_ci * @hw_rf_id a u32 with the device RF ID
104562306a36Sopenharmony_ci * @hw_crf_id a u32 with the device CRF ID
104662306a36Sopenharmony_ci * @hw_wfpm_id a u32 with the device wfpm ID
104762306a36Sopenharmony_ci * @hw_id: a u32 with the ID of the device / sub-device.
104862306a36Sopenharmony_ci *	Set during transport allocation.
104962306a36Sopenharmony_ci * @hw_id_str: a string with info about HW ID. Set during transport allocation.
105062306a36Sopenharmony_ci * @hw_rev_step: The mac step of the HW
105162306a36Sopenharmony_ci * @pm_support: set to true in start_hw if link pm is supported
105262306a36Sopenharmony_ci * @ltr_enabled: set to true if the LTR is enabled
105362306a36Sopenharmony_ci * @fail_to_parse_pnvm_image: set to true if pnvm parsing failed
105462306a36Sopenharmony_ci * @failed_to_load_reduce_power_image: set to true if pnvm loading failed
105562306a36Sopenharmony_ci * @wide_cmd_header: true when ucode supports wide command header format
105662306a36Sopenharmony_ci * @wait_command_queue: wait queue for sync commands
105762306a36Sopenharmony_ci * @num_rx_queues: number of RX queues allocated by the transport;
105862306a36Sopenharmony_ci *	the transport must set this before calling iwl_drv_start()
105962306a36Sopenharmony_ci * @iml_len: the length of the image loader
106062306a36Sopenharmony_ci * @iml: a pointer to the image loader itself
106162306a36Sopenharmony_ci * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
106262306a36Sopenharmony_ci *	The user should use iwl_trans_{alloc,free}_tx_cmd.
106362306a36Sopenharmony_ci * @rx_mpdu_cmd: MPDU RX command ID, must be assigned by opmode before
106462306a36Sopenharmony_ci *	starting the firmware, used for tracing
106562306a36Sopenharmony_ci * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the
106662306a36Sopenharmony_ci *	start of the 802.11 header in the @rx_mpdu_cmd
106762306a36Sopenharmony_ci * @dflt_pwr_limit: default power limit fetched from the platform (ACPI)
106862306a36Sopenharmony_ci * @system_pm_mode: the system-wide power management mode in use.
106962306a36Sopenharmony_ci *	This mode is set dynamically, depending on the WoWLAN values
107062306a36Sopenharmony_ci *	configured from the userspace at runtime.
107162306a36Sopenharmony_ci * @iwl_trans_txqs: transport tx queues data.
107262306a36Sopenharmony_ci * @mbx_addr_0_step: step address data 0
107362306a36Sopenharmony_ci * @mbx_addr_1_step: step address data 1
107462306a36Sopenharmony_ci * @pcie_link_speed: current PCIe link speed (%PCI_EXP_LNKSTA_CLS_*),
107562306a36Sopenharmony_ci *	only valid for discrete (not integrated) NICs
107662306a36Sopenharmony_ci * @invalid_tx_cmd: invalid TX command buffer
107762306a36Sopenharmony_ci */
107862306a36Sopenharmony_cistruct iwl_trans {
107962306a36Sopenharmony_ci	bool csme_own;
108062306a36Sopenharmony_ci	const struct iwl_trans_ops *ops;
108162306a36Sopenharmony_ci	struct iwl_op_mode *op_mode;
108262306a36Sopenharmony_ci	const struct iwl_cfg_trans_params *trans_cfg;
108362306a36Sopenharmony_ci	const struct iwl_cfg *cfg;
108462306a36Sopenharmony_ci	struct iwl_drv *drv;
108562306a36Sopenharmony_ci	enum iwl_trans_state state;
108662306a36Sopenharmony_ci	unsigned long status;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	struct device *dev;
108962306a36Sopenharmony_ci	u32 max_skb_frags;
109062306a36Sopenharmony_ci	u32 hw_rev;
109162306a36Sopenharmony_ci	u32 hw_rev_step;
109262306a36Sopenharmony_ci	u32 hw_rf_id;
109362306a36Sopenharmony_ci	u32 hw_crf_id;
109462306a36Sopenharmony_ci	u32 hw_cnv_id;
109562306a36Sopenharmony_ci	u32 hw_wfpm_id;
109662306a36Sopenharmony_ci	u32 hw_id;
109762306a36Sopenharmony_ci	char hw_id_str[52];
109862306a36Sopenharmony_ci	u32 sku_id[3];
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size;
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	bool pm_support;
110362306a36Sopenharmony_ci	bool ltr_enabled;
110462306a36Sopenharmony_ci	u8 pnvm_loaded:1;
110562306a36Sopenharmony_ci	u8 fail_to_parse_pnvm_image:1;
110662306a36Sopenharmony_ci	u8 reduce_power_loaded:1;
110762306a36Sopenharmony_ci	u8 failed_to_load_reduce_power_image:1;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	const struct iwl_hcmd_arr *command_groups;
111062306a36Sopenharmony_ci	int command_groups_size;
111162306a36Sopenharmony_ci	bool wide_cmd_header;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	wait_queue_head_t wait_command_queue;
111462306a36Sopenharmony_ci	u8 num_rx_queues;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	size_t iml_len;
111762306a36Sopenharmony_ci	u8 *iml;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	/* The following fields are internal only */
112062306a36Sopenharmony_ci	struct kmem_cache *dev_cmd_pool;
112162306a36Sopenharmony_ci	char dev_cmd_pool_name[50];
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	struct dentry *dbgfs_dir;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci#ifdef CONFIG_LOCKDEP
112662306a36Sopenharmony_ci	struct lockdep_map sync_cmd_lockdep_map;
112762306a36Sopenharmony_ci#endif
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	struct iwl_trans_debug dbg;
113062306a36Sopenharmony_ci	struct iwl_self_init_dram init_dram;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	enum iwl_plat_pm_mode system_pm_mode;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	const char *name;
113562306a36Sopenharmony_ci	struct iwl_trans_txqs txqs;
113662306a36Sopenharmony_ci	u32 mbx_addr_0_step;
113762306a36Sopenharmony_ci	u32 mbx_addr_1_step;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	u8 pcie_link_speed;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	struct iwl_dma_ptr invalid_tx_cmd;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	/* pointer to trans specific struct */
114462306a36Sopenharmony_ci	/*Ensure that this pointer will always be aligned to sizeof pointer */
114562306a36Sopenharmony_ci	char trans_specific[] __aligned(sizeof(void *));
114662306a36Sopenharmony_ci};
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ciconst char *iwl_get_cmd_string(struct iwl_trans *trans, u32 id);
114962306a36Sopenharmony_ciint iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_cistatic inline void iwl_trans_configure(struct iwl_trans *trans,
115262306a36Sopenharmony_ci				       const struct iwl_trans_config *trans_cfg)
115362306a36Sopenharmony_ci{
115462306a36Sopenharmony_ci	trans->op_mode = trans_cfg->op_mode;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	trans->ops->configure(trans, trans_cfg);
115762306a36Sopenharmony_ci	WARN_ON(iwl_cmd_groups_verify_sorted(trans_cfg));
115862306a36Sopenharmony_ci}
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_cistatic inline int iwl_trans_start_hw(struct iwl_trans *trans)
116162306a36Sopenharmony_ci{
116262306a36Sopenharmony_ci	might_sleep();
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	return trans->ops->start_hw(trans);
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_cistatic inline void iwl_trans_op_mode_leave(struct iwl_trans *trans)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	might_sleep();
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	if (trans->ops->op_mode_leave)
117262306a36Sopenharmony_ci		trans->ops->op_mode_leave(trans);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	trans->op_mode = NULL;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	trans->state = IWL_TRANS_NO_FW;
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_cistatic inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	might_sleep();
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	trans->state = IWL_TRANS_FW_ALIVE;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	trans->ops->fw_alive(trans, scd_addr);
118662306a36Sopenharmony_ci}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_cistatic inline int iwl_trans_start_fw(struct iwl_trans *trans,
118962306a36Sopenharmony_ci				     const struct fw_img *fw,
119062306a36Sopenharmony_ci				     bool run_in_rfkill)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	int ret;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	might_sleep();
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	WARN_ON_ONCE(!trans->rx_mpdu_cmd);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	clear_bit(STATUS_FW_ERROR, &trans->status);
119962306a36Sopenharmony_ci	ret = trans->ops->start_fw(trans, fw, run_in_rfkill);
120062306a36Sopenharmony_ci	if (ret == 0)
120162306a36Sopenharmony_ci		trans->state = IWL_TRANS_FW_STARTED;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	return ret;
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistatic inline void iwl_trans_stop_device(struct iwl_trans *trans)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	might_sleep();
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	trans->ops->stop_device(trans);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	trans->state = IWL_TRANS_NO_FW;
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cistatic inline int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test,
121662306a36Sopenharmony_ci				       bool reset)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	might_sleep();
121962306a36Sopenharmony_ci	if (!trans->ops->d3_suspend)
122062306a36Sopenharmony_ci		return -EOPNOTSUPP;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	return trans->ops->d3_suspend(trans, test, reset);
122362306a36Sopenharmony_ci}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_cistatic inline int iwl_trans_d3_resume(struct iwl_trans *trans,
122662306a36Sopenharmony_ci				      enum iwl_d3_status *status,
122762306a36Sopenharmony_ci				      bool test, bool reset)
122862306a36Sopenharmony_ci{
122962306a36Sopenharmony_ci	might_sleep();
123062306a36Sopenharmony_ci	if (!trans->ops->d3_resume)
123162306a36Sopenharmony_ci		return -EOPNOTSUPP;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	return trans->ops->d3_resume(trans, status, test, reset);
123462306a36Sopenharmony_ci}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_cistatic inline struct iwl_trans_dump_data *
123762306a36Sopenharmony_ciiwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask,
123862306a36Sopenharmony_ci		    const struct iwl_dump_sanitize_ops *sanitize_ops,
123962306a36Sopenharmony_ci		    void *sanitize_ctx)
124062306a36Sopenharmony_ci{
124162306a36Sopenharmony_ci	if (!trans->ops->dump_data)
124262306a36Sopenharmony_ci		return NULL;
124362306a36Sopenharmony_ci	return trans->ops->dump_data(trans, dump_mask,
124462306a36Sopenharmony_ci				     sanitize_ops, sanitize_ctx);
124562306a36Sopenharmony_ci}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_cistatic inline struct iwl_device_tx_cmd *
124862306a36Sopenharmony_ciiwl_trans_alloc_tx_cmd(struct iwl_trans *trans)
124962306a36Sopenharmony_ci{
125062306a36Sopenharmony_ci	return kmem_cache_zalloc(trans->dev_cmd_pool, GFP_ATOMIC);
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ciint iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
125662306a36Sopenharmony_ci					 struct iwl_device_tx_cmd *dev_cmd)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	kmem_cache_free(trans->dev_cmd_pool, dev_cmd);
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cistatic inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
126262306a36Sopenharmony_ci			       struct iwl_device_tx_cmd *dev_cmd, int queue)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
126562306a36Sopenharmony_ci		return -EIO;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
126862306a36Sopenharmony_ci		IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
126962306a36Sopenharmony_ci		return -EIO;
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	return trans->ops->tx(trans, skb, dev_cmd, queue);
127362306a36Sopenharmony_ci}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_cistatic inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
127662306a36Sopenharmony_ci				     int ssn, struct sk_buff_head *skbs,
127762306a36Sopenharmony_ci				     bool is_flush)
127862306a36Sopenharmony_ci{
127962306a36Sopenharmony_ci	if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
128062306a36Sopenharmony_ci		IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
128162306a36Sopenharmony_ci		return;
128262306a36Sopenharmony_ci	}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	trans->ops->reclaim(trans, queue, ssn, skbs, is_flush);
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_cistatic inline void iwl_trans_set_q_ptrs(struct iwl_trans *trans, int queue,
128862306a36Sopenharmony_ci					int ptr)
128962306a36Sopenharmony_ci{
129062306a36Sopenharmony_ci	if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
129162306a36Sopenharmony_ci		IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
129262306a36Sopenharmony_ci		return;
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	trans->ops->set_q_ptrs(trans, queue, ptr);
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_cistatic inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue,
129962306a36Sopenharmony_ci					 bool configure_scd)
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	trans->ops->txq_disable(trans, queue, configure_scd);
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_cistatic inline bool
130562306a36Sopenharmony_ciiwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn,
130662306a36Sopenharmony_ci			 const struct iwl_trans_txq_scd_cfg *cfg,
130762306a36Sopenharmony_ci			 unsigned int queue_wdg_timeout)
130862306a36Sopenharmony_ci{
130962306a36Sopenharmony_ci	might_sleep();
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
131262306a36Sopenharmony_ci		IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
131362306a36Sopenharmony_ci		return false;
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	return trans->ops->txq_enable(trans, queue, ssn,
131762306a36Sopenharmony_ci				      cfg, queue_wdg_timeout);
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_cistatic inline int
132162306a36Sopenharmony_ciiwl_trans_get_rxq_dma_data(struct iwl_trans *trans, int queue,
132262306a36Sopenharmony_ci			   struct iwl_trans_rxq_dma_data *data)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	if (WARN_ON_ONCE(!trans->ops->rxq_dma_data))
132562306a36Sopenharmony_ci		return -ENOTSUPP;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	return trans->ops->rxq_dma_data(trans, queue, data);
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_cistatic inline void
133162306a36Sopenharmony_ciiwl_trans_txq_free(struct iwl_trans *trans, int queue)
133262306a36Sopenharmony_ci{
133362306a36Sopenharmony_ci	if (WARN_ON_ONCE(!trans->ops->txq_free))
133462306a36Sopenharmony_ci		return;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	trans->ops->txq_free(trans, queue);
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_cistatic inline int
134062306a36Sopenharmony_ciiwl_trans_txq_alloc(struct iwl_trans *trans,
134162306a36Sopenharmony_ci		    u32 flags, u32 sta_mask, u8 tid,
134262306a36Sopenharmony_ci		    int size, unsigned int wdg_timeout)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	might_sleep();
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	if (WARN_ON_ONCE(!trans->ops->txq_alloc))
134762306a36Sopenharmony_ci		return -ENOTSUPP;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
135062306a36Sopenharmony_ci		IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
135162306a36Sopenharmony_ci		return -EIO;
135262306a36Sopenharmony_ci	}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	return trans->ops->txq_alloc(trans, flags, sta_mask, tid,
135562306a36Sopenharmony_ci				     size, wdg_timeout);
135662306a36Sopenharmony_ci}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_cistatic inline void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans,
135962306a36Sopenharmony_ci						 int queue, bool shared_mode)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	if (trans->ops->txq_set_shared_mode)
136262306a36Sopenharmony_ci		trans->ops->txq_set_shared_mode(trans, queue, shared_mode);
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
136662306a36Sopenharmony_ci					int fifo, int sta_id, int tid,
136762306a36Sopenharmony_ci					int frame_limit, u16 ssn,
136862306a36Sopenharmony_ci					unsigned int queue_wdg_timeout)
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	struct iwl_trans_txq_scd_cfg cfg = {
137162306a36Sopenharmony_ci		.fifo = fifo,
137262306a36Sopenharmony_ci		.sta_id = sta_id,
137362306a36Sopenharmony_ci		.tid = tid,
137462306a36Sopenharmony_ci		.frame_limit = frame_limit,
137562306a36Sopenharmony_ci		.aggregate = sta_id >= 0,
137662306a36Sopenharmony_ci	};
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg, queue_wdg_timeout);
137962306a36Sopenharmony_ci}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_cistatic inline
138262306a36Sopenharmony_civoid iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo,
138362306a36Sopenharmony_ci			     unsigned int queue_wdg_timeout)
138462306a36Sopenharmony_ci{
138562306a36Sopenharmony_ci	struct iwl_trans_txq_scd_cfg cfg = {
138662306a36Sopenharmony_ci		.fifo = fifo,
138762306a36Sopenharmony_ci		.sta_id = -1,
138862306a36Sopenharmony_ci		.tid = IWL_MAX_TID_COUNT,
138962306a36Sopenharmony_ci		.frame_limit = IWL_FRAME_LIMIT,
139062306a36Sopenharmony_ci		.aggregate = false,
139162306a36Sopenharmony_ci	};
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout);
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cistatic inline void iwl_trans_freeze_txq_timer(struct iwl_trans *trans,
139762306a36Sopenharmony_ci					      unsigned long txqs,
139862306a36Sopenharmony_ci					      bool freeze)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
140162306a36Sopenharmony_ci		IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
140262306a36Sopenharmony_ci		return;
140362306a36Sopenharmony_ci	}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	if (trans->ops->freeze_txq_timer)
140662306a36Sopenharmony_ci		trans->ops->freeze_txq_timer(trans, txqs, freeze);
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_cistatic inline void iwl_trans_block_txq_ptrs(struct iwl_trans *trans,
141062306a36Sopenharmony_ci					    bool block)
141162306a36Sopenharmony_ci{
141262306a36Sopenharmony_ci	if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
141362306a36Sopenharmony_ci		IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
141462306a36Sopenharmony_ci		return;
141562306a36Sopenharmony_ci	}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	if (trans->ops->block_txq_ptrs)
141862306a36Sopenharmony_ci		trans->ops->block_txq_ptrs(trans, block);
141962306a36Sopenharmony_ci}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_cistatic inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans,
142262306a36Sopenharmony_ci						 u32 txqs)
142362306a36Sopenharmony_ci{
142462306a36Sopenharmony_ci	if (WARN_ON_ONCE(!trans->ops->wait_tx_queues_empty))
142562306a36Sopenharmony_ci		return -ENOTSUPP;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	/* No need to wait if the firmware is not alive */
142862306a36Sopenharmony_ci	if (trans->state != IWL_TRANS_FW_ALIVE) {
142962306a36Sopenharmony_ci		IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
143062306a36Sopenharmony_ci		return -EIO;
143162306a36Sopenharmony_ci	}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	return trans->ops->wait_tx_queues_empty(trans, txqs);
143462306a36Sopenharmony_ci}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_cistatic inline int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue)
143762306a36Sopenharmony_ci{
143862306a36Sopenharmony_ci	if (WARN_ON_ONCE(!trans->ops->wait_txq_empty))
143962306a36Sopenharmony_ci		return -ENOTSUPP;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
144262306a36Sopenharmony_ci		IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
144362306a36Sopenharmony_ci		return -EIO;
144462306a36Sopenharmony_ci	}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	return trans->ops->wait_txq_empty(trans, queue);
144762306a36Sopenharmony_ci}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_cistatic inline void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val)
145062306a36Sopenharmony_ci{
145162306a36Sopenharmony_ci	trans->ops->write8(trans, ofs, val);
145262306a36Sopenharmony_ci}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_cistatic inline void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val)
145562306a36Sopenharmony_ci{
145662306a36Sopenharmony_ci	trans->ops->write32(trans, ofs, val);
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_cistatic inline u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs)
146062306a36Sopenharmony_ci{
146162306a36Sopenharmony_ci	return trans->ops->read32(trans, ofs);
146262306a36Sopenharmony_ci}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_cistatic inline u32 iwl_trans_read_prph(struct iwl_trans *trans, u32 ofs)
146562306a36Sopenharmony_ci{
146662306a36Sopenharmony_ci	return trans->ops->read_prph(trans, ofs);
146762306a36Sopenharmony_ci}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_cistatic inline void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs,
147062306a36Sopenharmony_ci					u32 val)
147162306a36Sopenharmony_ci{
147262306a36Sopenharmony_ci	return trans->ops->write_prph(trans, ofs, val);
147362306a36Sopenharmony_ci}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_cistatic inline int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr,
147662306a36Sopenharmony_ci				     void *buf, int dwords)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci	return trans->ops->read_mem(trans, addr, buf, dwords);
147962306a36Sopenharmony_ci}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize)		      \
148262306a36Sopenharmony_ci	do {								      \
148362306a36Sopenharmony_ci		if (__builtin_constant_p(bufsize))			      \
148462306a36Sopenharmony_ci			BUILD_BUG_ON((bufsize) % sizeof(u32));		      \
148562306a36Sopenharmony_ci		iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\
148662306a36Sopenharmony_ci	} while (0)
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cistatic inline int iwl_trans_write_imr_mem(struct iwl_trans *trans,
148962306a36Sopenharmony_ci					  u32 dst_addr, u64 src_addr,
149062306a36Sopenharmony_ci					  u32 byte_cnt)
149162306a36Sopenharmony_ci{
149262306a36Sopenharmony_ci	if (trans->ops->imr_dma_data)
149362306a36Sopenharmony_ci		return trans->ops->imr_dma_data(trans, dst_addr, src_addr, byte_cnt);
149462306a36Sopenharmony_ci	return 0;
149562306a36Sopenharmony_ci}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_cistatic inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr)
149862306a36Sopenharmony_ci{
149962306a36Sopenharmony_ci	u32 value;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	if (iwl_trans_read_mem(trans, addr, &value, 1))
150262306a36Sopenharmony_ci		return 0xa5a5a5a5;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	return value;
150562306a36Sopenharmony_ci}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_cistatic inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr,
150862306a36Sopenharmony_ci				      const void *buf, int dwords)
150962306a36Sopenharmony_ci{
151062306a36Sopenharmony_ci	return trans->ops->write_mem(trans, addr, buf, dwords);
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_cistatic inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,
151462306a36Sopenharmony_ci					u32 val)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	return iwl_trans_write_mem(trans, addr, &val, 1);
151762306a36Sopenharmony_ci}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_cistatic inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
152062306a36Sopenharmony_ci{
152162306a36Sopenharmony_ci	if (trans->ops->set_pmi)
152262306a36Sopenharmony_ci		trans->ops->set_pmi(trans, state);
152362306a36Sopenharmony_ci}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_cistatic inline int iwl_trans_sw_reset(struct iwl_trans *trans,
152662306a36Sopenharmony_ci				     bool retake_ownership)
152762306a36Sopenharmony_ci{
152862306a36Sopenharmony_ci	if (trans->ops->sw_reset)
152962306a36Sopenharmony_ci		return trans->ops->sw_reset(trans, retake_ownership);
153062306a36Sopenharmony_ci	return 0;
153162306a36Sopenharmony_ci}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_cistatic inline void
153462306a36Sopenharmony_ciiwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
153562306a36Sopenharmony_ci{
153662306a36Sopenharmony_ci	trans->ops->set_bits_mask(trans, reg, mask, value);
153762306a36Sopenharmony_ci}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci#define iwl_trans_grab_nic_access(trans)		\
154062306a36Sopenharmony_ci	__cond_lock(nic_access,				\
154162306a36Sopenharmony_ci		    likely((trans)->ops->grab_nic_access(trans)))
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_cistatic inline void __releases(nic_access)
154462306a36Sopenharmony_ciiwl_trans_release_nic_access(struct iwl_trans *trans)
154562306a36Sopenharmony_ci{
154662306a36Sopenharmony_ci	trans->ops->release_nic_access(trans);
154762306a36Sopenharmony_ci	__release(nic_access);
154862306a36Sopenharmony_ci}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_cistatic inline void iwl_trans_fw_error(struct iwl_trans *trans, bool sync)
155162306a36Sopenharmony_ci{
155262306a36Sopenharmony_ci	if (WARN_ON_ONCE(!trans->op_mode))
155362306a36Sopenharmony_ci		return;
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	/* prevent double restarts due to the same erroneous FW */
155662306a36Sopenharmony_ci	if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status)) {
155762306a36Sopenharmony_ci		iwl_op_mode_nic_error(trans->op_mode, sync);
155862306a36Sopenharmony_ci		trans->state = IWL_TRANS_NO_FW;
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_cistatic inline bool iwl_trans_fw_running(struct iwl_trans *trans)
156362306a36Sopenharmony_ci{
156462306a36Sopenharmony_ci	return trans->state == IWL_TRANS_FW_ALIVE;
156562306a36Sopenharmony_ci}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_cistatic inline void iwl_trans_sync_nmi(struct iwl_trans *trans)
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	if (trans->ops->sync_nmi)
157062306a36Sopenharmony_ci		trans->ops->sync_nmi(trans);
157162306a36Sopenharmony_ci}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_civoid iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr,
157462306a36Sopenharmony_ci				  u32 sw_err_bit);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_cistatic inline int iwl_trans_load_pnvm(struct iwl_trans *trans,
157762306a36Sopenharmony_ci				      const struct iwl_pnvm_image *pnvm_data,
157862306a36Sopenharmony_ci				      const struct iwl_ucode_capabilities *capa)
157962306a36Sopenharmony_ci{
158062306a36Sopenharmony_ci	return trans->ops->load_pnvm(trans, pnvm_data, capa);
158162306a36Sopenharmony_ci}
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_cistatic inline void iwl_trans_set_pnvm(struct iwl_trans *trans,
158462306a36Sopenharmony_ci				      const struct iwl_ucode_capabilities *capa)
158562306a36Sopenharmony_ci{
158662306a36Sopenharmony_ci	if (trans->ops->set_pnvm)
158762306a36Sopenharmony_ci		trans->ops->set_pnvm(trans, capa);
158862306a36Sopenharmony_ci}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_cistatic inline int iwl_trans_load_reduce_power
159162306a36Sopenharmony_ci				(struct iwl_trans *trans,
159262306a36Sopenharmony_ci				 const struct iwl_pnvm_image *payloads,
159362306a36Sopenharmony_ci				 const struct iwl_ucode_capabilities *capa)
159462306a36Sopenharmony_ci{
159562306a36Sopenharmony_ci	return trans->ops->load_reduce_power(trans, payloads, capa);
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_cistatic inline void
159962306a36Sopenharmony_ciiwl_trans_set_reduce_power(struct iwl_trans *trans,
160062306a36Sopenharmony_ci			   const struct iwl_ucode_capabilities *capa)
160162306a36Sopenharmony_ci{
160262306a36Sopenharmony_ci	if (trans->ops->set_reduce_power)
160362306a36Sopenharmony_ci		trans->ops->set_reduce_power(trans, capa);
160462306a36Sopenharmony_ci}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_cistatic inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans)
160762306a36Sopenharmony_ci{
160862306a36Sopenharmony_ci	return trans->dbg.internal_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED ||
160962306a36Sopenharmony_ci		trans->dbg.external_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED;
161062306a36Sopenharmony_ci}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_cistatic inline void iwl_trans_interrupts(struct iwl_trans *trans, bool enable)
161362306a36Sopenharmony_ci{
161462306a36Sopenharmony_ci	if (trans->ops->interrupts)
161562306a36Sopenharmony_ci		trans->ops->interrupts(trans, enable);
161662306a36Sopenharmony_ci}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci/*****************************************************
161962306a36Sopenharmony_ci * transport helper functions
162062306a36Sopenharmony_ci *****************************************************/
162162306a36Sopenharmony_cistruct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
162262306a36Sopenharmony_ci			  struct device *dev,
162362306a36Sopenharmony_ci			  const struct iwl_trans_ops *ops,
162462306a36Sopenharmony_ci			  const struct iwl_cfg_trans_params *cfg_trans);
162562306a36Sopenharmony_ciint iwl_trans_init(struct iwl_trans *trans);
162662306a36Sopenharmony_civoid iwl_trans_free(struct iwl_trans *trans);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_cistatic inline bool iwl_trans_is_hw_error_value(u32 val)
162962306a36Sopenharmony_ci{
163062306a36Sopenharmony_ci	return ((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50);
163162306a36Sopenharmony_ci}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci/*****************************************************
163462306a36Sopenharmony_ci* driver (transport) register/unregister functions
163562306a36Sopenharmony_ci******************************************************/
163662306a36Sopenharmony_ciint __must_check iwl_pci_register_driver(void);
163762306a36Sopenharmony_civoid iwl_pci_unregister_driver(void);
163862306a36Sopenharmony_civoid iwl_trans_pcie_remove(struct iwl_trans *trans, bool rescan);
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci#endif /* __iwl_trans_h__ */
1641