Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
0d770a82
Commit
0d770a82
authored
May 08, 2014
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-john' of
git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
parents
d294d028
017a6416
Changes
30
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
507 additions
and
291 deletions
+507
-291
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Kconfig
+8
-4
drivers/net/wireless/iwlwifi/dvm/Makefile
drivers/net/wireless/iwlwifi/dvm/Makefile
+2
-1
drivers/net/wireless/iwlwifi/dvm/dev.h
drivers/net/wireless/iwlwifi/dvm/dev.h
+2
-0
drivers/net/wireless/iwlwifi/dvm/led.h
drivers/net/wireless/iwlwifi/dvm/led.h
+12
-0
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-7000.c
+1
-1
drivers/net/wireless/iwlwifi/iwl-8000.c
drivers/net/wireless/iwlwifi/iwl-8000.c
+1
-1
drivers/net/wireless/iwlwifi/iwl-agn-hw.h
drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+1
-3
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-config.h
+6
-0
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+26
-0
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-fw.h
+2
-0
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+38
-8
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/iwl-trans.h
+19
-0
drivers/net/wireless/iwlwifi/mvm/Makefile
drivers/net/wireless/iwlwifi/mvm/Makefile
+2
-1
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex.c
+3
-3
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
+1
-1
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+4
-4
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/fw.c
+1
-1
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+12
-0
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
+87
-4
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/mvm.h
+15
-1
drivers/net/wireless/iwlwifi/mvm/nvm.c
drivers/net/wireless/iwlwifi/mvm/nvm.c
+20
-10
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/ops.c
+28
-8
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+3
-6
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.c
+58
-115
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/scan.c
+12
-41
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/mvm/utils.c
+2
-0
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/internal.h
+14
-10
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/rx.c
+1
-1
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/trans.c
+62
-2
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/iwlwifi/pcie/tx.c
+64
-65
No files found.
drivers/net/wireless/iwlwifi/Kconfig
View file @
0d770a82
...
...
@@ -2,10 +2,6 @@ config IWLWIFI
tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) "
depends on PCI && MAC80211 && HAS_IOMEM
select FW_LOADER
select NEW_LEDS
select LEDS_CLASS
select LEDS_TRIGGERS
select MAC80211_LEDS
---help---
Select to build the driver supporting the:
...
...
@@ -43,6 +39,14 @@ config IWLWIFI
say M here and read <file:Documentation/kbuild/modules.txt>. The
module will be called iwlwifi.
config IWLWIFI_LEDS
bool
depends on IWLWIFI
depends on LEDS_CLASS
select LEDS_TRIGGERS
select MAC80211_LEDS
default y
config IWLDVM
tristate "Intel Wireless WiFi DVM Firmware support"
depends on IWLWIFI
...
...
drivers/net/wireless/iwlwifi/dvm/Makefile
View file @
0d770a82
...
...
@@ -4,9 +4,10 @@ iwldvm-objs += main.o rs.o mac80211.o ucode.o tx.o
iwldvm-objs
+=
lib.o calib.o tt.o sta.o rx.o
iwldvm-objs
+=
power.o
iwldvm-objs
+=
scan.o
led.o
iwldvm-objs
+=
scan.o
iwldvm-objs
+=
rxon.o devices.o
iwldvm-$(CONFIG_IWLWIFI_LEDS)
+=
led.o
iwldvm-$(CONFIG_IWLWIFI_DEBUGFS)
+=
debugfs.o
ccflags-y
+=
-D__CHECK_ENDIAN__
-I
$(src)
/../
drivers/net/wireless/iwlwifi/dvm/dev.h
View file @
0d770a82
...
...
@@ -888,9 +888,11 @@ struct iwl_priv {
struct
iwl_event_log
event_log
;
#ifdef CONFIG_IWLWIFI_LEDS
struct
led_classdev
led
;
unsigned
long
blink_on
,
blink_off
;
bool
led_registered
;
#endif
/* WoWLAN GTK rekey data */
u8
kck
[
NL80211_KCK_LEN
],
kek
[
NL80211_KEK_LEN
];
...
...
drivers/net/wireless/iwlwifi/dvm/led.h
View file @
0d770a82
...
...
@@ -36,8 +36,20 @@ struct iwl_priv;
#define IWL_LED_ACTIVITY (0<<1)
#define IWL_LED_LINK (1<<1)
#ifdef CONFIG_IWLWIFI_LEDS
void
iwlagn_led_enable
(
struct
iwl_priv
*
priv
);
void
iwl_leds_init
(
struct
iwl_priv
*
priv
);
void
iwl_leds_exit
(
struct
iwl_priv
*
priv
);
#else
static
inline
void
iwlagn_led_enable
(
struct
iwl_priv
*
priv
)
{
}
static
inline
void
iwl_leds_init
(
struct
iwl_priv
*
priv
)
{
}
static
inline
void
iwl_leds_exit
(
struct
iwl_priv
*
priv
)
{
}
#endif
#endif
/* __iwl_leds_h__ */
drivers/net/wireless/iwlwifi/iwl-7000.c
View file @
0d770a82
...
...
@@ -98,7 +98,7 @@
#define NVM_HW_SECTION_NUM_FAMILY_7000 0
static
const
struct
iwl_base_params
iwl7000_base_params
=
{
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
,
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
_FAMILY_7000
,
.
num_of_queues
=
IWLAGN_NUM_QUEUES
,
.
pll_cfg_val
=
0
,
.
shadow_ram_support
=
true
,
...
...
drivers/net/wireless/iwlwifi/iwl-8000.c
View file @
0d770a82
...
...
@@ -85,7 +85,7 @@
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
static
const
struct
iwl_base_params
iwl8000_base_params
=
{
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
,
.
eeprom_size
=
OTP_LOW_IMAGE_SIZE
_FAMILY_8000
,
.
num_of_queues
=
IWLAGN_NUM_QUEUES
,
.
pll_cfg_val
=
0
,
.
shadow_ram_support
=
true
,
...
...
drivers/net/wireless/iwlwifi/iwl-agn-hw.h
View file @
0d770a82
...
...
@@ -102,9 +102,7 @@
/* EEPROM */
#define IWLAGN_EEPROM_IMG_SIZE 2048
/* OTP */
/* lower blocks contain EEPROM image and calibration data */
#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16))
/* 2 KB */
/* high blocks contain PAPD data */
#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16))
/* 6 KB */
#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16))
/* 1024 bytes */
...
...
drivers/net/wireless/iwlwifi/iwl-config.h
View file @
0d770a82
...
...
@@ -193,6 +193,11 @@ struct iwl_ht_params {
#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS 0x80
#define EEPROM_REGULATORY_BAND_NO_HT40 0
/* lower blocks contain EEPROM image and calibration data */
#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16))
/* 2 KB */
#define OTP_LOW_IMAGE_SIZE_FAMILY_7000 (4 * 512 * sizeof(u16))
/* 4 KB */
#define OTP_LOW_IMAGE_SIZE_FAMILY_8000 (32 * 512 * sizeof(u16))
/* 32 KB */
struct
iwl_eeprom_params
{
const
u8
regulatory_bands
[
7
];
bool
enhanced_txpower
;
...
...
@@ -269,6 +274,7 @@ struct iwl_cfg {
u8
nvm_hw_section_num
;
bool
lp_xtal_workaround
;
const
struct
iwl_pwr_tx_backoff
*
pwr_tx_backoffs
;
bool
no_power_up_nic_in_init
;
};
/*
...
...
drivers/net/wireless/iwlwifi/
mvm/
fw-error-dump.h
→
drivers/net/wireless/iwlwifi/
iwl-
fw-error-dump.h
View file @
0d770a82
...
...
@@ -72,11 +72,14 @@
* @IWL_FW_ERROR_DUMP_SRAM:
* @IWL_FW_ERROR_DUMP_REG:
* @IWL_FW_ERROR_DUMP_RXF:
* @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as
* &struct iwl_fw_error_dump_txcmd packets
*/
enum
iwl_fw_error_dump_type
{
IWL_FW_ERROR_DUMP_SRAM
=
0
,
IWL_FW_ERROR_DUMP_REG
=
1
,
IWL_FW_ERROR_DUMP_RXF
=
2
,
IWL_FW_ERROR_DUMP_TXCMD
=
3
,
IWL_FW_ERROR_DUMP_MAX
,
};
...
...
@@ -105,4 +108,27 @@ struct iwl_fw_error_dump_file {
u8
data
[
0
];
}
__packed
;
/**
* struct iwl_fw_error_dump_txcmd - TX command data
* @cmdlen: original length of command
* @caplen: captured length of command (may be less)
* @data: captured command data, @caplen bytes
*/
struct
iwl_fw_error_dump_txcmd
{
__le32
cmdlen
;
__le32
caplen
;
u8
data
[];
}
__packed
;
/**
* iwl_mvm_fw_error_next_data - advance fw error dump data pointer
* @data: previous data block
* Returns: next data block
*/
static
inline
struct
iwl_fw_error_dump_data
*
iwl_mvm_fw_error_next_data
(
struct
iwl_fw_error_dump_data
*
data
)
{
return
(
void
*
)(
data
->
data
+
le32_to_cpu
(
data
->
len
));
}
#endif
/* __fw_error_dump_h__ */
drivers/net/wireless/iwlwifi/iwl-fw.h
View file @
0d770a82
...
...
@@ -116,9 +116,11 @@ enum iwl_ucode_tlv_flag {
/**
* enum iwl_ucode_tlv_api - ucode api
* @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field.
* @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA.
*/
enum
iwl_ucode_tlv_api
{
IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID
=
BIT
(
0
),
IWL_UCODE_TLV_API_CSA_FLOW
=
BIT
(
4
),
};
/**
...
...
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
View file @
0d770a82
...
...
@@ -62,6 +62,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/etherdevice.h>
#include "iwl-drv.h"
#include "iwl-modparams.h"
#include "iwl-nvm-parse.h"
...
...
@@ -450,13 +451,7 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg,
struct
iwl_nvm_data
*
data
,
const
__le16
*
nvm_sec
)
{
u8
hw_addr
[
ETH_ALEN
];
if
(
cfg
->
device_family
!=
IWL_DEVICE_FAMILY_8000
)
memcpy
(
hw_addr
,
nvm_sec
+
HW_ADDR
,
ETH_ALEN
);
else
memcpy
(
hw_addr
,
nvm_sec
+
MAC_ADDRESS_OVERRIDE_FAMILY_8000
,
ETH_ALEN
);
const
u8
*
hw_addr
=
(
const
u8
*
)(
nvm_sec
+
HW_ADDR
);
/* The byte order is little endian 16 bit, meaning 214365 */
data
->
hw_addr
[
0
]
=
hw_addr
[
1
];
...
...
@@ -467,6 +462,41 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg,
data
->
hw_addr
[
5
]
=
hw_addr
[
4
];
}
static
void
iwl_set_hw_address_family_8000
(
const
struct
iwl_cfg
*
cfg
,
struct
iwl_nvm_data
*
data
,
const
__le16
*
mac_override
,
const
__le16
*
nvm_hw
)
{
const
u8
*
hw_addr
;
if
(
mac_override
)
{
hw_addr
=
(
const
u8
*
)(
mac_override
+
MAC_ADDRESS_OVERRIDE_FAMILY_8000
);
/* The byte order is little endian 16 bit, meaning 214365 */
data
->
hw_addr
[
0
]
=
hw_addr
[
1
];
data
->
hw_addr
[
1
]
=
hw_addr
[
0
];
data
->
hw_addr
[
2
]
=
hw_addr
[
3
];
data
->
hw_addr
[
3
]
=
hw_addr
[
2
];
data
->
hw_addr
[
4
]
=
hw_addr
[
5
];
data
->
hw_addr
[
5
]
=
hw_addr
[
4
];
if
(
is_valid_ether_addr
(
hw_addr
))
return
;
}
/* take the MAC address from the OTP */
hw_addr
=
(
const
u8
*
)(
nvm_hw
+
HW_ADDR0_FAMILY_8000
);
data
->
hw_addr
[
0
]
=
hw_addr
[
3
];
data
->
hw_addr
[
1
]
=
hw_addr
[
2
];
data
->
hw_addr
[
2
]
=
hw_addr
[
1
];
data
->
hw_addr
[
3
]
=
hw_addr
[
0
];
hw_addr
=
(
const
u8
*
)(
nvm_hw
+
HW_ADDR1_FAMILY_8000
);
data
->
hw_addr
[
4
]
=
hw_addr
[
1
];
data
->
hw_addr
[
5
]
=
hw_addr
[
0
];
}
struct
iwl_nvm_data
*
iwl_parse_nvm_data
(
struct
device
*
dev
,
const
struct
iwl_cfg
*
cfg
,
const
__le16
*
nvm_hw
,
const
__le16
*
nvm_sw
,
...
...
@@ -526,7 +556,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
rx_chains
);
}
else
{
/* MAC address in family 8000 */
iwl_set_hw_address
(
cfg
,
data
,
mac_override
);
iwl_set_hw_address
_family_8000
(
cfg
,
data
,
mac_override
,
nvm_hw
);
iwl_init_sbands
(
dev
,
cfg
,
data
,
regulatory
,
sku
&
NVM_SKU_CAP_11AC_ENABLE
,
tx_chains
,
...
...
drivers/net/wireless/iwlwifi/iwl-trans.h
View file @
0d770a82
...
...
@@ -463,6 +463,11 @@ struct iwl_trans;
* @unref: release a reference previously taken with @ref. Note that
* initially the reference count is 1, making an initial @unref
* necessary to allow low power states.
* @dump_data: fill a data dump with debug data, maybe containing last
* TX'ed commands and similar. When called with a NULL buffer and
* zero buffer length, provide only the (estimated) required buffer
* length. Return the used buffer length.
* Note that the transport must fill in the proper file headers.
*/
struct
iwl_trans_ops
{
...
...
@@ -511,6 +516,10 @@ struct iwl_trans_ops {
u32
value
);
void
(
*
ref
)(
struct
iwl_trans
*
trans
);
void
(
*
unref
)(
struct
iwl_trans
*
trans
);
#ifdef CONFIG_IWLWIFI_DEBUGFS
u32
(
*
dump_data
)(
struct
iwl_trans
*
trans
,
void
*
buf
,
u32
buflen
);
#endif
};
/**
...
...
@@ -664,6 +673,16 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
trans
->
ops
->
unref
(
trans
);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
static
inline
u32
iwl_trans_dump_data
(
struct
iwl_trans
*
trans
,
void
*
buf
,
u32
buflen
)
{
if
(
!
trans
->
ops
->
dump_data
)
return
0
;
return
trans
->
ops
->
dump_data
(
trans
,
buf
,
buflen
);
}
#endif
static
inline
int
iwl_trans_send_cmd
(
struct
iwl_trans
*
trans
,
struct
iwl_host_cmd
*
cmd
)
{
...
...
drivers/net/wireless/iwlwifi/mvm/Makefile
View file @
0d770a82
...
...
@@ -3,8 +3,9 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y
+=
utils.o rx.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y
+=
scan.o time-event.o rs.o
iwlmvm-y
+=
power.o coex.o
iwlmvm-y
+=
led.o
tt.o offloading.o
iwlmvm-y
+=
tt.o offloading.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS)
+=
debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_IWLWIFI_LEDS)
+=
led.o
iwlmvm-$(CONFIG_PM_SLEEP)
+=
d3.o
ccflags-y
+=
-D__CHECK_ENDIAN__
-I
$(src)
/../
drivers/net/wireless/iwlwifi/mvm/coex.c
View file @
0d770a82
...
...
@@ -611,14 +611,14 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
bt_cmd
->
flags
|=
cpu_to_le32
(
BT_COEX_SYNC2SCO
);
if
(
IWL_MVM_BT_COEX_CORUNNING
)
{
bt_cmd
->
valid_bit_msk
=
cpu_to_le32
(
BT_VALID_CORUN_LUT_20
|
BT_VALID_CORUN_LUT_40
);
bt_cmd
->
valid_bit_msk
|
=
cpu_to_le32
(
BT_VALID_CORUN_LUT_20
|
BT_VALID_CORUN_LUT_40
);
bt_cmd
->
flags
|=
cpu_to_le32
(
BT_COEX_CORUNNING
);
}
if
(
IWL_MVM_BT_COEX_MPLUT
)
{
bt_cmd
->
flags
|=
cpu_to_le32
(
BT_COEX_MPLUT
);
bt_cmd
->
valid_bit_msk
=
cpu_to_le32
(
BT_VALID_MULTI_PRIO_LUT
);
bt_cmd
->
valid_bit_msk
|
=
cpu_to_le32
(
BT_VALID_MULTI_PRIO_LUT
);
}
if
(
mvm
->
cfg
->
bt_shared_single_ant
)
...
...
drivers/net/wireless/iwlwifi/mvm/debugfs.c
View file @
0d770a82
...
...
@@ -67,7 +67,7 @@
#include "iwl-io.h"
#include "iwl-prph.h"
#include "debugfs.h"
#include "fw-error-dump.h"
#include "
iwl-
fw-error-dump.h"
static
ssize_t
iwl_dbgfs_tx_flush_write
(
struct
iwl_mvm
*
mvm
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
...
...
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
View file @
0d770a82
...
...
@@ -187,9 +187,9 @@ enum iwl_scan_type {
* this number of packets were received (typically 1)
* @passive2active: is auto switching from passive to active during scan allowed
* @rxchain_sel_flags: RXON_RX_CHAIN_*
* @max_out_time: in
usec
s, max out of serving channel time
* @max_out_time: in
TU
s, max out of serving channel time
* @suspend_time: how long to pause scan when returning to service channel:
* bits 0-19: beacon interal in
usec
s (suspend before executing)
* bits 0-19: beacon interal in
TU
s (suspend before executing)
* bits 20-23: reserved
* bits 24-31: number of beacons (suspend between channels)
* @rxon_flags: RXON_FLG_*
...
...
@@ -387,8 +387,8 @@ enum scan_framework_client {
* @quiet_plcp_th: quiet channel num of packets threshold
* @good_CRC_th: passive to active promotion threshold
* @rx_chain: RXON rx chain.
* @max_out_time: max
uSec
to be out of assoceated channel
* @suspend_time: pause scan this
long
when returning to service channel
* @max_out_time: max
TUs
to be out of assoceated channel
* @suspend_time: pause scan this
TUs
when returning to service channel
* @flags: RXON flags
* @filter_flags: RXONfilter
* @tx_cmd: tx command for active scan; for 2GHz and for 5GHz.
...
...
drivers/net/wireless/iwlwifi/mvm/fw.c
View file @
0d770a82
...
...
@@ -295,7 +295,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
/* Read the NVM only at driver load time, no need to do this twice */
if
(
read_nvm
)
{
/* Read nvm */
ret
=
iwl_nvm_init
(
mvm
);
ret
=
iwl_nvm_init
(
mvm
,
true
);
if
(
ret
)
{
IWL_ERR
(
mvm
,
"Failed to read NVM: %d
\n
"
,
ret
);
goto
error
;
...
...
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
View file @
0d770a82
...
...
@@ -1237,11 +1237,23 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
u32
rate
__maybe_unused
=
le32_to_cpu
(
beacon
->
beacon_notify_hdr
.
initial_rate
);
lockdep_assert_held
(
&
mvm
->
mutex
);
IWL_DEBUG_RX
(
mvm
,
"beacon status %#x retries:%d tsf:0x%16llX rate:%d
\n
"
,
status
&
TX_STATUS_MSK
,
beacon
->
beacon_notify_hdr
.
failure_frame
,
le64_to_cpu
(
beacon
->
tsf
),
rate
);
if
(
unlikely
(
mvm
->
csa_vif
&&
mvm
->
csa_vif
->
csa_active
))
{
if
(
!
ieee80211_csa_is_complete
(
mvm
->
csa_vif
))
{
iwl_mvm_mac_ctxt_beacon_changed
(
mvm
,
mvm
->
csa_vif
);
}
else
{
ieee80211_csa_finish
(
mvm
->
csa_vif
);
mvm
->
csa_vif
=
NULL
;
}
}
return
0
;
}
...
...
drivers/net/wireless/iwlwifi/mvm/mac80211.c
View file @
0d770a82
...
...
@@ -320,6 +320,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if
(
mvm
->
fw
->
ucode_capa
.
flags
&
IWL_UCODE_TLV_FLAGS_GO_UAPSD
)
hw
->
wiphy
->
flags
|=
WIPHY_FLAG_AP_UAPSD
;
if
(
mvm
->
fw
->
ucode_capa
.
api
[
0
]
&
IWL_UCODE_TLV_API_CSA_FLOW
)
hw
->
wiphy
->
flags
|=
WIPHY_FLAG_HAS_CHANNEL_SWITCH
;
hw
->
wiphy
->
iface_combinations
=
iwl_mvm_iface_combinations
;
hw
->
wiphy
->
n_iface_combinations
=
ARRAY_SIZE
(
iwl_mvm_iface_combinations
);
...
...
@@ -539,13 +542,22 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
return
-
EACCES
;
/* return from D0i3 before starting a new Tx aggregation */
if
(
action
==
IEEE80211_AMPDU_TX_START
)
{
switch
(
action
)
{
case
IEEE80211_AMPDU_TX_START
:
case
IEEE80211_AMPDU_TX_STOP_CONT
:
case
IEEE80211_AMPDU_TX_STOP_FLUSH
:
case
IEEE80211_AMPDU_TX_STOP_FLUSH_CONT
:
case
IEEE80211_AMPDU_TX_OPERATIONAL
:
iwl_mvm_ref
(
mvm
,
IWL_MVM_REF_TX_AGG
);
tx_agg_ref
=
true
;
/*
* wait synchronously until D0i3 exit to get the correct
* sequence number for the tid
* for tx start, wait synchronously until D0i3 exit to
* get the correct sequence number for the tid.
* additionally, some other ampdu actions use direct
* target access, which is not handled automatically
* by the trans layer (unlike commands), so wait for
* d0i3 exit in these cases as well.
*/
if
(
!
wait_event_timeout
(
mvm
->
d0i3_exit_waitq
,
!
test_bit
(
IWL_MVM_STATUS_IN_D0I3
,
&
mvm
->
status
),
HZ
))
{
...
...
@@ -553,6 +565,9 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
iwl_mvm_unref
(
mvm
,
IWL_MVM_REF_TX_AGG
);
return
-
EIO
;
}
break
;
default:
break
;
}
mutex_lock
(
&
mvm
->
mutex
);
...
...
@@ -2186,6 +2201,11 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
switch
(
vif
->
type
)
{
case
NL80211_IFTYPE_AP
:
/* Unless it's a CSA flow we have nothing to do here */
if
(
vif
->
csa_active
)
{
mvmvif
->
ap_ibss_active
=
true
;
break
;
}
case
NL80211_IFTYPE_ADHOC
:
/*
* The AP binding flow is handled as part of the start_ap flow
...
...
@@ -2222,6 +2242,12 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
goto
out_remove_binding
;
}
/* Handle binding during CSA */
if
(
vif
->
type
==
NL80211_IFTYPE_AP
)
{
iwl_mvm_update_quotas
(
mvm
,
vif
);
iwl_mvm_mac_ctxt_changed
(
mvm
,
vif
);
}
goto
out_unlock
;
out_remove_binding:
...
...
@@ -2246,13 +2272,20 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
iwl_mvm_remove_time_event
(
mvm
,
mvmvif
,
&
mvmvif
->
time_event_data
);
switch
(
vif
->
type
)
{
case
NL80211_IFTYPE_AP
:
case
NL80211_IFTYPE_ADHOC
:
goto
out_unlock
;
case
NL80211_IFTYPE_MONITOR
:
mvmvif
->
monitor_active
=
false
;
iwl_mvm_update_quotas
(
mvm
,
NULL
);
break
;
case
NL80211_IFTYPE_AP
:
/* This part is triggered only during CSA */
if
(
!
vif
->
csa_active
||
!
mvmvif
->
ap_ibss_active
)
goto
out_unlock
;
mvmvif
->
ap_ibss_active
=
false
;
iwl_mvm_update_quotas
(
mvm
,
NULL
);
/*TODO: bt_coex notification here? */
default:
break
;
}
...
...
@@ -2348,6 +2381,53 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw,
}
#endif
static
void
iwl_mvm_channel_switch_beacon
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
cfg80211_chan_def
*
chandef
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
mutex_lock
(
&
mvm
->
mutex
);
if
(
WARN
(
mvm
->
csa_vif
&&
mvm
->
csa_vif
->
csa_active
,
"Another CSA is already in progress"
))
goto
out_unlock
;
IWL_DEBUG_MAC80211
(
mvm
,
"CSA started to freq %d
\n
"
,
chandef
->
center_freq1
);
mvm
->
csa_vif
=
vif
;
out_unlock:
mutex_unlock
(
&
mvm
->
mutex
);
}
static
void
iwl_mvm_mac_flush
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
u32
queues
,
bool
drop
)
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
struct
iwl_mvm_vif
*
mvmvif
;
struct
iwl_mvm_sta
*
mvmsta
;
if
(
!
vif
||
vif
->
type
!=
NL80211_IFTYPE_STATION
)
return
;
mutex_lock
(
&
mvm
->
mutex
);
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
mvmsta
=
iwl_mvm_sta_from_staid_protected
(
mvm
,
mvmvif
->
ap_sta_id
);
if
(
WARN_ON_ONCE
(
!
mvmsta
))
goto
done
;
if
(
drop
)
{
if
(
iwl_mvm_flush_tx_path
(
mvm
,
mvmsta
->
tfd_queue_msk
,
true
))
IWL_ERR
(
mvm
,
"flush request fail
\n
"
);
}
else
{
iwl_trans_wait_tx_queue_empty
(
mvm
->
trans
,
mvmsta
->
tfd_queue_msk
);
}
done:
mutex_unlock
(
&
mvm
->
mutex
);
}
const
struct
ieee80211_ops
iwl_mvm_hw_ops
=
{
.
tx
=
iwl_mvm_mac_tx
,
.
ampdu_action
=
iwl_mvm_mac_ampdu_action
,
...
...
@@ -2371,6 +2451,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.
sta_rc_update
=
iwl_mvm_sta_rc_update
,
.
conf_tx
=
iwl_mvm_mac_conf_tx
,
.
mgd_prepare_tx
=
iwl_mvm_mac_mgd_prepare_tx
,
.
flush
=
iwl_mvm_mac_flush
,
.
sched_scan_start
=
iwl_mvm_mac_sched_scan_start
,
.
sched_scan_stop
=
iwl_mvm_mac_sched_scan_stop
,
.
set_key
=
iwl_mvm_mac_set_key
,
...
...
@@ -2390,6 +2471,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.
set_tim
=
iwl_mvm_set_tim
,
.
channel_switch_beacon
=
iwl_mvm_channel_switch_beacon
,
CFG80211_TESTMODE_CMD
(
iwl_mvm_mac_testmode_cmd
)
#ifdef CONFIG_PM_SLEEP
...
...
drivers/net/wireless/iwlwifi/mvm/mvm.h
View file @
0d770a82
...
...
@@ -589,7 +589,9 @@ struct iwl_mvm {
u32
*
fw_error_rxf
;
u32
fw_error_rxf_len
;
#ifdef CONFIG_IWLWIFI_LEDS
struct
led_classdev
led
;
#endif
struct
ieee80211_vif
*
p2p_device_vif
;
...
...
@@ -642,6 +644,8 @@ struct iwl_mvm {
/* Indicate if device power save is allowed */
bool
ps_disabled
;
struct
ieee80211_vif
*
csa_vif
;
};
/* Extract MVM priv from op_mode and _hw */
...
...
@@ -757,7 +761,7 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
struct
iwl_device_cmd
*
cmd
);
/* NVM */
int
iwl_nvm_init
(
struct
iwl_mvm
*
mvm
);
int
iwl_nvm_init
(
struct
iwl_mvm
*
mvm
,
bool
read_nvm_from_nic
);
int
iwl_mvm_load_nvm_to_nic
(
struct
iwl_mvm
*
mvm
);
int
iwl_mvm_up
(
struct
iwl_mvm
*
mvm
);
...
...
@@ -896,8 +900,18 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
struct
iwl_rx_cmd_buffer
*
rxb
,
struct
iwl_device_cmd
*
cmd
);
#ifdef CONFIG_IWLWIFI_LEDS
int
iwl_mvm_leds_init
(
struct
iwl_mvm
*
mvm
);
void
iwl_mvm_leds_exit
(
struct
iwl_mvm
*
mvm
);
#else
static
inline
int
iwl_mvm_leds_init
(
struct
iwl_mvm
*
mvm
)
{
return
0
;
}
static
inline
void
iwl_mvm_leds_exit
(
struct
iwl_mvm
*
mvm
)
{
}
#endif
/* D3 (WoWLAN, NetDetect) */
int
iwl_mvm_suspend
(
struct
ieee80211_hw
*
hw
,
struct
cfg80211_wowlan
*
wowlan
);
...
...
drivers/net/wireless/iwlwifi/mvm/nvm.c
View file @
0d770a82
...
...
@@ -238,13 +238,20 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
return
NULL
;
}
}
else
{
/* SW and REGULATORY sections are mandatory */
if
(
!
mvm
->
nvm_sections
[
NVM_SECTION_TYPE_SW
].
data
||
!
mvm
->
nvm_sections
[
NVM_SECTION_TYPE_MAC_OVERRIDE
].
data
||
!
mvm
->
nvm_sections
[
NVM_SECTION_TYPE_REGULATORY
].
data
)
{
IWL_ERR
(
mvm
,
"Can't parse empty family 8000 NVM sections
\n
"
);
return
NULL
;
}
/* MAC_OVERRIDE or at least HW section must exist */
if
(
!
mvm
->
nvm_sections
[
mvm
->
cfg
->
nvm_hw_section_num
].
data
&&
!
mvm
->
nvm_sections
[
NVM_SECTION_TYPE_MAC_OVERRIDE
].
data
)
{
IWL_ERR
(
mvm
,
"Can't parse mac_address, empty sections
\n
"
);
return
NULL
;
}
}
if
(
WARN_ON
(
!
mvm
->
cfg
))
...
...
@@ -427,7 +434,7 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm)
return
ret
;
}
int
iwl_nvm_init
(
struct
iwl_mvm
*
mvm
)
int
iwl_nvm_init
(
struct
iwl_mvm
*
mvm
,
bool
read_nvm_from_nic
)
{
int
ret
,
i
,
section
;
u8
*
nvm_buffer
,
*
temp
;
...
...
@@ -437,13 +444,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
if
(
WARN_ON_ONCE
(
mvm
->
cfg
->
nvm_hw_section_num
>=
NVM_MAX_NUM_SECTIONS
))
return
-
EINVAL
;
/* load external NVM if configured */
if
(
iwlwifi_mod_params
.
nvm_file
)
{
/* move to External NVM flow */
ret
=
iwl_mvm_read_external_nvm
(
mvm
);
if
(
ret
)
return
ret
;
}
else
{
/* load NVM values from nic */
if
(
read_nvm_from_nic
)
{
/* list of NVM sections we are allowed/need to read */
if
(
mvm
->
trans
->
cfg
->
device_family
!=
IWL_DEVICE_FAMILY_8000
)
{
nvm_to_read
[
0
]
=
mvm
->
cfg
->
nvm_hw_section_num
;
...
...
@@ -463,7 +465,6 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
/* Read From FW NVM */
IWL_DEBUG_EEPROM
(
mvm
->
trans
->
dev
,
"Read from NVM
\n
"
);
/* TODO: find correct NVM max size for a section */
nvm_buffer
=
kmalloc
(
mvm
->
cfg
->
base_params
->
eeprom_size
,
GFP_KERNEL
);
if
(
!
nvm_buffer
)
...
...
@@ -511,6 +512,15 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
return
ret
;
}
/* load external NVM if configured */
if
(
iwlwifi_mod_params
.
nvm_file
)
{
/* move to External NVM flow */
ret
=
iwl_mvm_read_external_nvm
(
mvm
);
if
(
ret
)
return
ret
;
}
/* parse the relevant nvm sections */
mvm
->
nvm_data
=
iwl_parse_nvm_sections
(
mvm
);
if
(
!
mvm
->
nvm_data
)
return
-
ENODATA
;
...
...
drivers/net/wireless/iwlwifi/mvm/ops.c
View file @
0d770a82
...
...
@@ -79,8 +79,8 @@
#include "iwl-prph.h"
#include "rs.h"
#include "fw-api-scan.h"
#include "fw-error-dump.h"
#include "time-event.h"
#include "iwl-fw-error-dump.h"
/*
* module name, copyright, version, etc.
...
...
@@ -220,7 +220,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER
(
BA_NOTIF
,
iwl_mvm_rx_ba_notif
,
false
),
RX_HANDLER
(
BT_PROFILE_NOTIFICATION
,
iwl_mvm_rx_bt_coex_notif
,
true
),
RX_HANDLER
(
BEACON_NOTIFICATION
,
iwl_mvm_rx_beacon_notif
,
fals
e
),
RX_HANDLER
(
BEACON_NOTIFICATION
,
iwl_mvm_rx_beacon_notif
,
tru
e
),
RX_HANDLER
(
STATISTICS_NOTIFICATION
,
iwl_mvm_rx_statistics
,
true
),
RX_HANDLER
(
ANTENNA_COUPLING_NOTIFICATION
,
iwl_mvm_rx_ant_coupling_notif
,
true
),
...
...
@@ -467,12 +467,18 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
min_backoff
=
calc_min_backoff
(
trans
,
cfg
);
iwl_mvm_tt_initialize
(
mvm
,
min_backoff
);
if
(
WARN
(
cfg
->
no_power_up_nic_in_init
&&
!
iwlwifi_mod_params
.
nvm_file
,
"not allowing power-up and not having nvm_file
\n
"
))
goto
out_free
;
/*
* If the NVM exists in an external file,
* there is no need to unnecessarily power up the NIC at driver load
* Even if nvm exists in the nvm_file driver should read agin the nvm
* from the nic because there might be entries that exist in the OTP
* and not in the file.
* for nics with no_power_up_nic_in_init: rely completley on nvm_file
*/
if
(
iwlwifi_mod_params
.
nvm_file
)
{
err
=
iwl_nvm_init
(
mvm
);
if
(
cfg
->
no_power_up_nic_in_init
&&
iwlwifi_mod_params
.
nvm_file
)
{
err
=
iwl_nvm_init
(
mvm
,
false
);
if
(
err
)
goto
out_free
;
}
else
{
...
...
@@ -519,7 +525,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
out_free:
iwl_phy_db_free
(
mvm
->
phy_db
);
kfree
(
mvm
->
scan_cmd
);
if
(
!
iwlwifi_mod_params
.
nvm_file
)
if
(
!
cfg
->
no_power_up_nic_in_init
||
!
iwlwifi_mod_params
.
nvm_file
)
iwl_trans_op_mode_leave
(
trans
);
ieee80211_free_hw
(
mvm
->
hw
);
return
NULL
;
...
...
@@ -816,6 +822,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
struct
iwl_fw_error_dump_file
*
dump_file
;
struct
iwl_fw_error_dump_data
*
dump_data
;
u32
file_len
;
u32
trans_len
;
lockdep_assert_held
(
&
mvm
->
mutex
);
...
...
@@ -827,6 +834,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
sizeof
(
*
dump_file
)
+
sizeof
(
*
dump_data
)
*
2
;
trans_len
=
iwl_trans_dump_data
(
mvm
->
trans
,
NULL
,
0
);
if
(
trans_len
)
file_len
+=
trans_len
;
dump_file
=
vmalloc
(
file_len
);
if
(
!
dump_file
)
return
;
...
...
@@ -840,7 +851,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_data
->
len
=
cpu_to_le32
(
mvm
->
fw_error_rxf_len
);
memcpy
(
dump_data
->
data
,
mvm
->
fw_error_rxf
,
mvm
->
fw_error_rxf_len
);
dump_data
=
(
void
*
)((
u8
*
)
dump_data
->
data
+
mvm
->
fw_error_rxf_len
);
dump_data
=
iwl_mvm_fw_error_next_data
(
dump_data
);
dump_data
->
type
=
cpu_to_le32
(
IWL_FW_ERROR_DUMP_SRAM
);
dump_data
->
len
=
cpu_to_le32
(
mvm
->
fw_error_sram_len
);
...
...
@@ -858,6 +869,15 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
kfree
(
mvm
->
fw_error_sram
);
mvm
->
fw_error_sram
=
NULL
;
mvm
->
fw_error_sram_len
=
0
;
if
(
trans_len
)
{
void
*
buf
=
iwl_mvm_fw_error_next_data
(
dump_data
);
u32
real_trans_len
=
iwl_trans_dump_data
(
mvm
->
trans
,
buf
,
trans_len
);
dump_data
=
(
void
*
)((
u8
*
)
buf
+
real_trans_len
);
dump_file
->
file_len
=
cpu_to_le32
(
file_len
-
trans_len
+
real_trans_len
);
}
}
#endif
...
...
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
View file @
0d770a82
...
...
@@ -202,18 +202,15 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
struct
cfg80211_chan_def
*
chandef
,
u8
chains_static
,
u8
chains_dynamic
)
{
int
ret
;
WARN_ON
(
!
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
)
&&
ctxt
->
ref
);
lockdep_assert_held
(
&
mvm
->
mutex
);
ctxt
->
channel
=
chandef
->
chan
;
ret
=
iwl_mvm_phy_ctxt_apply
(
mvm
,
ctxt
,
chandef
,
chains_static
,
chains_dynamic
,
FW_CTXT_ACTION_ADD
,
0
);
return
ret
;
return
iwl_mvm_phy_ctxt_apply
(
mvm
,
ctxt
,
chandef
,
chains_static
,
chains_dynamic
,
FW_CTXT_ACTION_ADD
,
0
);
}
/*
...
...
drivers/net/wireless/iwlwifi/mvm/rs.c
View file @
0d770a82
...
...
@@ -211,7 +211,7 @@ static const struct rs_tx_column rs_tx_columns[] = {
.
next_columns
=
{
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_
SISO_ANT_B
,
RS_COLUMN_
MIMO2
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
...
...
@@ -223,8 +223,8 @@ static const struct rs_tx_column rs_tx_columns[] = {
.
ant
=
ANT_B
,
.
next_columns
=
{
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_MIMO2
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
...
...
@@ -238,10 +238,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_MIMO2
,
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
...
...
@@ -254,10 +254,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_MIMO2
,
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
...
...
@@ -271,10 +271,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_MIMO2
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
...
...
@@ -289,10 +289,10 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_MIMO2
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_siso_allow
,
...
...
@@ -304,12 +304,12 @@ static const struct rs_tx_column rs_tx_columns[] = {
.
ant
=
ANT_AB
,
.
next_columns
=
{
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_MIMO2_SGI
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_mimo_allow
,
...
...
@@ -321,12 +321,12 @@ static const struct rs_tx_column rs_tx_columns[] = {
.
sgi
=
true
,
.
next_columns
=
{
RS_COLUMN_SISO_ANT_A_SGI
,
RS_COLUMN_SISO_ANT_B_SGI
,
RS_COLUMN_SISO_ANT_A
,
RS_COLUMN_SISO_ANT_B
,
RS_COLUMN_MIMO2
,
RS_COLUMN_LEGACY_ANT_A
,
RS_COLUMN_LEGACY_ANT_B
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
RS_COLUMN_INVALID
,
},
.
checks
=
{
rs_mimo_allow
,
...
...
@@ -1031,7 +1031,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
return
;
}
#ifdef C
PTCF
G_MAC80211_DEBUGFS
#ifdef C
ONFI
G_MAC80211_DEBUGFS
/* Disable last tx check if we are debugging with fixed rate */
if
(
lq_sta
->
dbg_fixed_rate
)
{
IWL_DEBUG_RATE
(
mvm
,
"Fixed rate. avoid rate scaling
\n
"
);
...
...
@@ -1335,105 +1335,50 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
tbl
->
expected_tpt
=
rs_get_expected_tpt_table
(
lq_sta
,
column
,
rate
->
bw
);
}
/*
* Find starting rate for new "search" high-throughput mode of modulation.
* Goal is to find lowest expected rate (under perfect conditions) that is
* above the current measured throughput of "active" mode, to give new mode
* a fair chance to prove itself without too many challenges.
*
* This gets called when transitioning to more aggressive modulation
* (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
* (i.e. MIMO to SISO). When moving to MIMO, bit rate will typically need
* to decrease to match "active" throughput. When moving from MIMO to SISO,
* bit rate will typically need to increase, but not if performance was bad.
*/
static
s32
rs_get_best_rate
(
struct
iwl_mvm
*
mvm
,
struct
iwl_lq_sta
*
lq_sta
,
struct
iwl_scale_tbl_info
*
tbl
,
/* "search" */
u
16
rate_mask
,
s8
index
)
u
nsigned
long
rate_mask
,
s8
index
)
{
/* "active" values */
struct
iwl_scale_tbl_info
*
active_tbl
=
&
(
lq_sta
->
lq_info
[
lq_sta
->
active_tbl
]);
s32
active_sr
=
active_tbl
->
win
[
index
].
success_ratio
;
s32
active_tpt
=
active_tbl
->
expected_tpt
[
index
];
/* expected "search" throughput */
s32
success_ratio
=
active_tbl
->
win
[
index
].
success_ratio
;
u16
expected_current_tpt
=
active_tbl
->
expected_tpt
[
index
];
const
u16
*
tpt_tbl
=
tbl
->
expected_tpt
;
s32
new_rate
,
high
,
low
,
start_hi
;
u16
high_low
;
s8
rate
=
index
;
new_rate
=
high
=
low
=
start_hi
=
IWL_RATE_INVALID
;
while
(
1
)
{
high_low
=
rs_get_adjacent_rate
(
mvm
,
rate
,
rate_mask
,
tbl
->
rate
.
type
);
low
=
high_low
&
0xff
;
high
=
(
high_low
>>
8
)
&
0xff
;
u32
target_tpt
;
int
rate_idx
;
/*
* Lower the "search" bit rate, to give new "search" mode
* approximately the same throughput as "active" if:
*
* 1) "Active" mode has been working modestly well (but not
* great), and expected "search" throughput (under perfect
* conditions) at candidate rate is above the actual
* measured "active" throughput (but less than expected
* "active" throughput under perfect conditions).
* OR
* 2) "Active" mode has been working perfectly or very well
* and expected "search" throughput (under perfect
* conditions) at candidate rate is above expected
* "active" throughput (under perfect conditions).
*/
if
((((
100
*
tpt_tbl
[
rate
])
>
lq_sta
->
last_tpt
)
&&
((
active_sr
>
RS_SR_FORCE_DECREASE
)
&&
(
active_sr
<=
IWL_RATE_HIGH_TH
)
&&
(
tpt_tbl
[
rate
]
<=
active_tpt
)))
||
((
active_sr
>=
IWL_RATE_SCALE_SWITCH
)
&&
(
tpt_tbl
[
rate
]
>
active_tpt
)))
{
/* (2nd or later pass)
* If we've already tried to raise the rate, and are
* now trying to lower it, use the higher rate. */
if
(
start_hi
!=
IWL_RATE_INVALID
)
{
new_rate
=
start_hi
;
break
;
}
new_rate
=
rate
;
/* Loop again with lower rate */
if
(
low
!=
IWL_RATE_INVALID
)
rate
=
low
;
if
(
success_ratio
>
RS_SR_NO_DECREASE
)
{
target_tpt
=
100
*
expected_current_tpt
;
IWL_DEBUG_RATE
(
mvm
,
"SR %d high. Find rate exceeding EXPECTED_CURRENT %d
\n
"
,
success_ratio
,
target_tpt
);
}
else
{
target_tpt
=
lq_sta
->
last_tpt
;
IWL_DEBUG_RATE
(
mvm
,
"SR %d not thag good. Find rate exceeding ACTUAL_TPT %d
\n
"
,
success_ratio
,
target_tpt
);
}
/* Lower rate not available, use the original */
else
break
;
rate_idx
=
find_first_bit
(
&
rate_mask
,
BITS_PER_LONG
);
/* Else try to raise the "search" rate to match "active" */
}
else
{
/* (2nd or later pass)
* If we've already tried to lower the rate, and are
* now trying to raise it, use the lower rate. */
if
(
new_rate
!=
IWL_RATE_INVALID
)
break
;
while
(
rate_idx
!=
IWL_RATE_INVALID
)
{
if
(
target_tpt
<
(
100
*
tpt_tbl
[
rate_idx
]))
break
;
/* Loop again with higher rate */
else
if
(
high
!=
IWL_RATE_INVALID
)
{
start_hi
=
high
;
rate
=
high
;
high_low
=
rs_get_adjacent_rate
(
mvm
,
rate_idx
,
rate_mask
,
tbl
->
rate
.
type
);
/* Higher rate not available, use the original */
}
else
{
new_rate
=
rate
;
break
;
}
}
rate_idx
=
(
high_low
>>
8
)
&
0xff
;
}
return
new_rate
;
IWL_DEBUG_RATE
(
mvm
,
"Best rate found %d target_tp %d expected_new %d
\n
"
,
rate_idx
,
target_tpt
,
rate_idx
!=
IWL_RATE_INVALID
?
100
*
tpt_tbl
[
rate_idx
]
:
IWL_INVALID_VALUE
);
return
rate_idx
;
}
static
u32
rs_bw_from_sta_bw
(
struct
ieee80211_sta
*
sta
)
...
...
@@ -1608,7 +1553,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
tpt
=
lq_sta
->
last_tpt
/
100
;
expected_tpt_tbl
=
rs_get_expected_tpt_table
(
lq_sta
,
next_col
,
tbl
->
rate
.
bw
);
rs_bw_from_sta_bw
(
sta
)
);
if
(
WARN_ON_ONCE
(
!
expected_tpt_tbl
))
continue
;
...
...
@@ -1649,7 +1594,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
const
struct
rs_tx_column
*
curr_column
=
&
rs_tx_columns
[
tbl
->
column
];
u32
sz
=
(
sizeof
(
struct
iwl_scale_tbl_info
)
-
(
sizeof
(
struct
iwl_rate_scale_data
)
*
IWL_RATE_COUNT
));
u
16
rate_mask
=
0
;
u
nsigned
long
rate_mask
=
0
;
u32
rate_idx
=
0
;
memcpy
(
search_tbl
,
tbl
,
sz
);
...
...
@@ -1691,7 +1636,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
!
(
BIT
(
rate_idx
)
&
rate_mask
))
{
IWL_DEBUG_RATE
(
mvm
,
"can not switch with index %d"
" rate mask %x
\n
"
,
" rate mask %
l
x
\n
"
,
rate_idx
,
rate_mask
);
goto
err
;
...
...
@@ -1805,16 +1750,21 @@ static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
*
stronger
=
TPC_INVALID
;
}
static
bool
rs_tpc_allowed
(
struct
iwl_mvm
*
mvm
,
struct
rs_rate
*
rate
,
enum
ieee80211_band
band
)
static
bool
rs_tpc_allowed
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
rs_rate
*
rate
,
enum
ieee80211_band
band
)
{
int
index
=
rate
->
index
;
bool
cam
=
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
);
bool
sta_ps_disabled
=
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
!
vif
->
bss_conf
.
ps
);
IWL_DEBUG_RATE
(
mvm
,
"cam: %d sta_ps_disabled %d
\n
"
,
cam
,
sta_ps_disabled
);
/*
* allow tpc only if power management is enabled, or bt coex
* activity grade allows it and we are on 2.4Ghz.
*/
if
(
iwlmvm_mod_params
.
power_scheme
==
IWL_POWER_SCHEME_CAM
&&
if
(
(
cam
||
sta_ps_disabled
)
&&
!
iwl_mvm_bt_coex_is_tpc_allowed
(
mvm
,
band
))
return
false
;
...
...
@@ -1931,7 +1881,7 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm,
band
=
chanctx_conf
->
def
.
chan
->
band
;
rcu_read_unlock
();
if
(
!
rs_tpc_allowed
(
mvm
,
rate
,
band
))
{
if
(
!
rs_tpc_allowed
(
mvm
,
vif
,
rate
,
band
))
{
IWL_DEBUG_RATE
(
mvm
,
"tpc is not allowed. remove txp restrictions"
);
lq_sta
->
lq
.
reduced_tpc
=
TPC_NO_REDUCTION
;
...
...
@@ -2235,7 +2185,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
break
;
case
RS_ACTION_STAY
:
/* No change */
update_lq
=
rs_tpc_perform
(
mvm
,
sta
,
lq_sta
,
tbl
);
if
(
lq_sta
->
rs_state
==
RS_STATE_STAY_IN_COLUMN
)
update_lq
=
rs_tpc_perform
(
mvm
,
sta
,
lq_sta
,
tbl
);
break
;
default:
break
;
...
...
@@ -2489,10 +2440,6 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
/* Disable MCS9 as a workaround */
if
(
i
==
IWL_RATE_MCS_9_INDEX
)
continue
;
/* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
if
(
i
==
IWL_RATE_MCS_9_INDEX
&&
sta
->
bandwidth
==
IEEE80211_STA_RX_BW_20
)
...
...
@@ -2511,10 +2458,6 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
if
(
i
==
IWL_RATE_9M_INDEX
)
continue
;
/* Disable MCS9 as a workaround */
if
(
i
==
IWL_RATE_MCS_9_INDEX
)
continue
;
/* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
if
(
i
==
IWL_RATE_MCS_9_INDEX
&&
sta
->
bandwidth
==
IEEE80211_STA_RX_BW_20
)
...
...
drivers/net/wireless/iwlwifi/mvm/scan.c
View file @
0d770a82
...
...
@@ -277,51 +277,22 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
IEEE80211_IFACE_ITER_NORMAL
,
iwl_mvm_scan_condition_iterator
,
&
global_bound
);
/*
* Under low latency traffic passive scan is fragmented meaning
* that dwell on a particular channel will be fragmented. Each fragment
* dwell time is 20ms and fragments period is 105ms. Skipping to next
* channel will be delayed by the same period - 105ms. So suspend_time
* parameter describing both fragments and channels skipping periods is
* set to 105ms. This value is chosen so that overall passive scan
* duration will not be too long. Max_out_time in this case is set to
* 70ms, so for active scanning operating channel will be left for 70ms
* while for passive still for 20ms (fragment dwell).
*/
if
(
global_bound
)
{
if
(
!
iwl_mvm_low_latency
(
mvm
))
{
params
->
suspend_time
=
ieee80211_tu_to_usec
(
100
);
params
->
max_out_time
=
ieee80211_tu_to_usec
(
600
);
}
else
{
params
->
suspend_time
=
ieee80211_tu_to_usec
(
105
);
/* P2P doesn't support fragmented passive scan, so
* configure max_out_time to be at least longest dwell
* time for passive scan.
*/
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
!
vif
->
p2p
)
{
params
->
max_out_time
=
ieee80211_tu_to_usec
(
70
);
params
->
passive_fragmented
=
true
;
}
else
{
u32
passive_dwell
;
/*
* Use band G so that passive channel dwell time
* will be assigned with maximum value.
*/
band
=
IEEE80211_BAND_2GHZ
;
passive_dwell
=
iwl_mvm_get_passive_dwell
(
band
);
params
->
max_out_time
=
ieee80211_tu_to_usec
(
passive_dwell
);
}
}
if
(
!
global_bound
)
goto
not_bound
;
params
->
suspend_time
=
100
;
params
->
max_out_time
=
600
;
if
(
iwl_mvm_low_latency
(
mvm
))
{
params
->
suspend_time
=
250
;
params
->
max_out_time
=
250
;
}
not_bound:
for
(
band
=
IEEE80211_BAND_2GHZ
;
band
<
IEEE80211_NUM_BANDS
;
band
++
)
{
if
(
params
->
passive_fragmented
)
params
->
dwell
[
band
].
passive
=
20
;
else
params
->
dwell
[
band
].
passive
=
iwl_mvm_get_passive_dwell
(
band
);
params
->
dwell
[
band
].
passive
=
iwl_mvm_get_passive_dwell
(
band
);
params
->
dwell
[
band
].
active
=
iwl_mvm_get_active_dwell
(
band
,
n_ssids
);
}
...
...
drivers/net/wireless/iwlwifi/mvm/utils.c
View file @
0d770a82
...
...
@@ -519,6 +519,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
iwl_mvm_dump_umac_error_log
(
mvm
);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
void
iwl_mvm_fw_error_sram_dump
(
struct
iwl_mvm
*
mvm
)
{
const
struct
fw_img
*
img
;
...
...
@@ -581,6 +582,7 @@ void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm)
}
iwl_trans_release_nic_access
(
mvm
->
trans
,
&
flags
);
}
#endif
/**
* iwl_mvm_send_lq_cmd() - Send link quality command
...
...
drivers/net/wireless/iwlwifi/pcie/internal.h
View file @
0d770a82
...
...
@@ -117,21 +117,19 @@ struct iwl_dma_ptr {
/**
* iwl_queue_inc_wrap - increment queue index, wrap back to beginning
* @index -- current index
* @n_bd -- total number of entries in queue (must be power of 2)
*/
static
inline
int
iwl_queue_inc_wrap
(
int
index
,
int
n_bd
)
static
inline
int
iwl_queue_inc_wrap
(
int
index
)
{
return
++
index
&
(
n_bd
-
1
);
return
++
index
&
(
TFD_QUEUE_SIZE_MAX
-
1
);
}
/**
* iwl_queue_dec_wrap - decrement queue index, wrap back to end
* @index -- current index
* @n_bd -- total number of entries in queue (must be power of 2)
*/
static
inline
int
iwl_queue_dec_wrap
(
int
index
,
int
n_bd
)
static
inline
int
iwl_queue_dec_wrap
(
int
index
)
{
return
--
index
&
(
n_bd
-
1
);
return
--
index
&
(
TFD_QUEUE_SIZE_MAX
-
1
);
}
struct
iwl_cmd_meta
{
...
...
@@ -145,13 +143,13 @@ struct iwl_cmd_meta {
*
* Contains common data for Rx and Tx queues.
*
* Note the difference between
n_bd
and n_window: the hardware
* always assumes 256 descriptors, so
n_bd
is always 256 (unless
* Note the difference between
TFD_QUEUE_SIZE_MAX
and n_window: the hardware
* always assumes 256 descriptors, so
TFD_QUEUE_SIZE_MAX
is always 256 (unless
* there might be HW changes in the future). For the normal TX
* queues, n_window, which is the size of the software queue data
* is also 256; however, for the command queue, n_window is only
* 32 since we don't need so many commands pending. Since the HW
* still uses 256 BDs for DMA though,
n_bd
stays 256. As a result,
* still uses 256 BDs for DMA though,
TFD_QUEUE_SIZE_MAX
stays 256. As a result,
* the software buffers (in the variables @meta, @txb in struct
* iwl_txq) only have 32 entries, while the HW buffers (@tfds in
* the same struct) have 256.
...
...
@@ -162,7 +160,6 @@ struct iwl_cmd_meta {
* data is a window overlayed over the HW queue.
*/
struct
iwl_queue
{
int
n_bd
;
/* number of BDs in this queue */
int
write_ptr
;
/* 1-st empty entry (index) host_w*/
int
read_ptr
;
/* last used entry (index) host_r*/
/* use for monitoring and recovering the stuck queue */
...
...
@@ -373,6 +370,13 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
struct
sk_buff_head
*
skbs
);
void
iwl_trans_pcie_tx_reset
(
struct
iwl_trans
*
trans
);
static
inline
u16
iwl_pcie_tfd_tb_get_len
(
struct
iwl_tfd
*
tfd
,
u8
idx
)
{
struct
iwl_tfd_tb
*
tb
=
&
tfd
->
tbs
[
idx
];
return
le16_to_cpu
(
tb
->
hi_n_len
)
>>
4
;
}
/*****************************************************
* Error handling
******************************************************/
...
...
drivers/net/wireless/iwlwifi/pcie/rx.c
View file @
0d770a82
...
...
@@ -850,7 +850,7 @@ static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans)
trans_pcie
->
ict_index
,
read
);
trans_pcie
->
ict_tbl
[
trans_pcie
->
ict_index
]
=
0
;
trans_pcie
->
ict_index
=
iwl_queue_inc_wrap
(
trans_pcie
->
ict_index
,
ICT_COUNT
);
((
trans_pcie
->
ict_index
+
1
)
&
(
ICT_COUNT
-
1
)
);
read
=
le32_to_cpu
(
trans_pcie
->
ict_tbl
[
trans_pcie
->
ict_index
]);
trace_iwlwifi_dev_ict_read
(
trans
->
dev
,
trans_pcie
->
ict_index
,
...
...
drivers/net/wireless/iwlwifi/pcie/trans.c
View file @
0d770a82
...
...
@@ -73,6 +73,7 @@
#include "iwl-csr.h"
#include "iwl-prph.h"
#include "iwl-agn-hw.h"
#include "iwl-fw-error-dump.h"
#include "internal.h"
static
u32
iwl_trans_pcie_read_shr
(
struct
iwl_trans
*
trans
,
u32
reg
)
...
...
@@ -1337,8 +1338,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
IWL_ERR
(
trans
,
"Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]
\n
"
,
cnt
,
active
?
""
:
"in"
,
fifo
,
tbl_dw
,
iwl_read_prph
(
trans
,
SCD_QUEUE_RDPTR
(
cnt
))
&
(
txq
->
q
.
n_bd
-
1
),
iwl_read_prph
(
trans
,
SCD_QUEUE_RDPTR
(
cnt
))
&
(
TFD_QUEUE_SIZE_MAX
-
1
),
iwl_read_prph
(
trans
,
SCD_QUEUE_WRPTR
(
cnt
)));
}
...
...
@@ -1669,6 +1670,61 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
IWL_ERR
(
trans
,
"failed to create the trans debugfs entry
\n
"
);
return
-
ENOMEM
;
}
static
u32
iwl_trans_pcie_get_cmdlen
(
struct
iwl_tfd
*
tfd
)
{
u32
cmdlen
=
0
;
int
i
;
for
(
i
=
0
;
i
<
IWL_NUM_OF_TBS
;
i
++
)
cmdlen
+=
iwl_pcie_tfd_tb_get_len
(
tfd
,
i
);
return
cmdlen
;
}
static
u32
iwl_trans_pcie_dump_data
(
struct
iwl_trans
*
trans
,
void
*
buf
,
u32
buflen
)
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
struct
iwl_fw_error_dump_data
*
data
;
struct
iwl_txq
*
cmdq
=
&
trans_pcie
->
txq
[
trans_pcie
->
cmd_queue
];
struct
iwl_fw_error_dump_txcmd
*
txcmd
;
u32
len
;
int
i
,
ptr
;
if
(
!
buf
)
return
sizeof
(
*
data
)
+
cmdq
->
q
.
n_window
*
(
sizeof
(
*
txcmd
)
+
TFD_MAX_PAYLOAD_SIZE
);
len
=
0
;
data
=
buf
;
data
->
type
=
cpu_to_le32
(
IWL_FW_ERROR_DUMP_TXCMD
);
txcmd
=
(
void
*
)
data
->
data
;
spin_lock_bh
(
&
cmdq
->
lock
);
ptr
=
cmdq
->
q
.
write_ptr
;
for
(
i
=
0
;
i
<
cmdq
->
q
.
n_window
;
i
++
)
{
u8
idx
=
get_cmd_index
(
&
cmdq
->
q
,
ptr
);
u32
caplen
,
cmdlen
;
cmdlen
=
iwl_trans_pcie_get_cmdlen
(
&
cmdq
->
tfds
[
ptr
]);
caplen
=
min_t
(
u32
,
TFD_MAX_PAYLOAD_SIZE
,
cmdlen
);
if
(
cmdlen
)
{
len
+=
sizeof
(
*
txcmd
)
+
caplen
;
txcmd
->
cmdlen
=
cpu_to_le32
(
cmdlen
);
txcmd
->
caplen
=
cpu_to_le32
(
caplen
);
memcpy
(
txcmd
->
data
,
cmdq
->
entries
[
idx
].
cmd
,
caplen
);
txcmd
=
(
void
*
)((
u8
*
)
txcmd
->
data
+
caplen
);
}
ptr
=
iwl_queue_dec_wrap
(
ptr
);
}
spin_unlock_bh
(
&
cmdq
->
lock
);
data
->
len
=
cpu_to_le32
(
len
);
return
sizeof
(
*
data
)
+
len
;
}
#else
static
int
iwl_trans_pcie_dbgfs_register
(
struct
iwl_trans
*
trans
,
struct
dentry
*
dir
)
...
...
@@ -1711,6 +1767,10 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.
grab_nic_access
=
iwl_trans_pcie_grab_nic_access
,
.
release_nic_access
=
iwl_trans_pcie_release_nic_access
,
.
set_bits_mask
=
iwl_trans_pcie_set_bits_mask
,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.
dump_data
=
iwl_trans_pcie_dump_data
,
#endif
};
struct
iwl_trans
*
iwl_trans_pcie_alloc
(
struct
pci_dev
*
pdev
,
...
...
drivers/net/wireless/iwlwifi/pcie/tx.c
View file @
0d770a82
...
...
@@ -70,20 +70,20 @@ static int iwl_queue_space(const struct iwl_queue *q)
/*
* To avoid ambiguity between empty and completely full queues, there
* should always be less than
q->n_bd
elements in the queue.
* If q->n_window is smaller than
q->n_bd, there is no need to reserve
* any queue entries for this purpose.
* should always be less than
TFD_QUEUE_SIZE_MAX
elements in the queue.
* If q->n_window is smaller than
TFD_QUEUE_SIZE_MAX, there is no need
*
to reserve
any queue entries for this purpose.
*/
if
(
q
->
n_window
<
q
->
n_bd
)
if
(
q
->
n_window
<
TFD_QUEUE_SIZE_MAX
)
max
=
q
->
n_window
;
else
max
=
q
->
n_bd
-
1
;
max
=
TFD_QUEUE_SIZE_MAX
-
1
;
/*
*
q->n_bd is a power of 2, so the following is equivalent to modulo by
*
q->n_bd and is well defined for negative dividends
.
*
TFD_QUEUE_SIZE_MAX is a power of 2, so the following is equivalent to
*
modulo by TFD_QUEUE_SIZE_MAX and is well defined
.
*/
used
=
(
q
->
write_ptr
-
q
->
read_ptr
)
&
(
q
->
n_bd
-
1
);
used
=
(
q
->
write_ptr
-
q
->
read_ptr
)
&
(
TFD_QUEUE_SIZE_MAX
-
1
);
if
(
WARN_ON
(
used
>
max
))
return
0
;
...
...
@@ -94,17 +94,11 @@ static int iwl_queue_space(const struct iwl_queue *q)
/*
* iwl_queue_init - Initialize queue's high/low-water and read/write indexes
*/
static
int
iwl_queue_init
(
struct
iwl_queue
*
q
,
int
count
,
int
slots_num
,
u32
id
)
static
int
iwl_queue_init
(
struct
iwl_queue
*
q
,
int
slots_num
,
u32
id
)
{
q
->
n_bd
=
count
;
q
->
n_window
=
slots_num
;
q
->
id
=
id
;
/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
* and iwl_queue_dec_wrap are broken. */
if
(
WARN_ON
(
!
is_power_of_2
(
count
)))
return
-
EINVAL
;
/* slots_num must be power-of-two size, otherwise
* get_cmd_index is broken. */
if
(
WARN_ON
(
!
is_power_of_2
(
slots_num
)))
...
...
@@ -197,13 +191,13 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
IWL_ERR
(
trans
,
"Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]
\n
"
,
i
,
active
?
""
:
"in"
,
fifo
,
tbl_dw
,
iwl_read_prph
(
trans
,
SCD_QUEUE_RDPTR
(
i
))
&
(
txq
->
q
.
n_bd
-
1
),
iwl_read_prph
(
trans
,
SCD_QUEUE_RDPTR
(
i
))
&
(
TFD_QUEUE_SIZE_MAX
-
1
),
iwl_read_prph
(
trans
,
SCD_QUEUE_WRPTR
(
i
)));
}
for
(
i
=
q
->
read_ptr
;
i
!=
q
->
write_ptr
;
i
=
iwl_queue_inc_wrap
(
i
,
q
->
n_bd
))
i
=
iwl_queue_inc_wrap
(
i
))
IWL_ERR
(
trans
,
"scratch %d = 0x%08x
\n
"
,
i
,
le32_to_cpu
(
txq
->
scratchbufs
[
i
].
scratch
));
...
...
@@ -359,13 +353,6 @@ static inline dma_addr_t iwl_pcie_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
return
addr
;
}
static
inline
u16
iwl_pcie_tfd_tb_get_len
(
struct
iwl_tfd
*
tfd
,
u8
idx
)
{
struct
iwl_tfd_tb
*
tb
=
&
tfd
->
tbs
[
idx
];
return
le16_to_cpu
(
tb
->
hi_n_len
)
>>
4
;
}
static
inline
void
iwl_pcie_tfd_set_tb
(
struct
iwl_tfd
*
tfd
,
u8
idx
,
dma_addr_t
addr
,
u16
len
)
{
...
...
@@ -425,13 +412,17 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)
{
struct
iwl_tfd
*
tfd_tmp
=
txq
->
tfds
;
/* rd_ptr is bounded by n_bd and idx is bounded by n_window */
/* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and
* idx is bounded by n_window
*/
int
rd_ptr
=
txq
->
q
.
read_ptr
;
int
idx
=
get_cmd_index
(
&
txq
->
q
,
rd_ptr
);
lockdep_assert_held
(
&
txq
->
lock
);
/* We have only q->n_window txq->entries, but we use q->n_bd tfds */
/* We have only q->n_window txq->entries, but we use
* TFD_QUEUE_SIZE_MAX tfds
*/
iwl_pcie_tfd_unmap
(
trans
,
&
txq
->
entries
[
idx
].
meta
,
&
tfd_tmp
[
rd_ptr
]);
/* free SKB */
...
...
@@ -452,7 +443,7 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)
}
static
int
iwl_pcie_txq_build_tfd
(
struct
iwl_trans
*
trans
,
struct
iwl_txq
*
txq
,
dma_addr_t
addr
,
u16
len
,
u8
reset
)
dma_addr_t
addr
,
u16
len
,
bool
reset
)
{
struct
iwl_queue
*
q
;
struct
iwl_tfd
*
tfd
,
*
tfd_tmp
;
...
...
@@ -565,8 +556,7 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
BUILD_BUG_ON
(
TFD_QUEUE_SIZE_MAX
&
(
TFD_QUEUE_SIZE_MAX
-
1
));
/* Initialize queue's high/low-water marks, and head/tail indexes */
ret
=
iwl_queue_init
(
&
txq
->
q
,
TFD_QUEUE_SIZE_MAX
,
slots_num
,
txq_id
);
ret
=
iwl_queue_init
(
&
txq
->
q
,
slots_num
,
txq_id
);
if
(
ret
)
return
ret
;
...
...
@@ -591,15 +581,12 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
struct
iwl_txq
*
txq
=
&
trans_pcie
->
txq
[
txq_id
];
struct
iwl_queue
*
q
=
&
txq
->
q
;
if
(
!
q
->
n_bd
)
return
;
spin_lock_bh
(
&
txq
->
lock
);
while
(
q
->
write_ptr
!=
q
->
read_ptr
)
{
IWL_DEBUG_TX_REPLY
(
trans
,
"Q %d Free %d
\n
"
,
txq_id
,
q
->
read_ptr
);
iwl_pcie_txq_free_tfd
(
trans
,
txq
);
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
,
q
->
n_bd
);
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
);
}
txq
->
active
=
false
;
spin_unlock_bh
(
&
txq
->
lock
);
...
...
@@ -636,10 +623,12 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
}
/* De-alloc circular buffer of TFDs */
if
(
txq
->
q
.
n_bd
)
{
dma_free_coherent
(
dev
,
sizeof
(
struct
iwl_tfd
)
*
txq
->
q
.
n_bd
,
txq
->
tfds
,
txq
->
q
.
dma_addr
);
if
(
txq
->
tfds
)
{
dma_free_coherent
(
dev
,
sizeof
(
struct
iwl_tfd
)
*
TFD_QUEUE_SIZE_MAX
,
txq
->
tfds
,
txq
->
q
.
dma_addr
);
txq
->
q
.
dma_addr
=
0
;
txq
->
tfds
=
NULL
;
dma_free_coherent
(
dev
,
sizeof
(
*
txq
->
scratchbufs
)
*
txq
->
q
.
n_window
,
...
...
@@ -948,8 +937,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
{
struct
iwl_trans_pcie
*
trans_pcie
=
IWL_TRANS_GET_PCIE_TRANS
(
trans
);
struct
iwl_txq
*
txq
=
&
trans_pcie
->
txq
[
txq_id
];
/* n_bd is usually 256 => n_bd - 1 = 0xff */
int
tfd_num
=
ssn
&
(
txq
->
q
.
n_bd
-
1
);
int
tfd_num
=
ssn
&
(
TFD_QUEUE_SIZE_MAX
-
1
);
struct
iwl_queue
*
q
=
&
txq
->
q
;
int
last_to_free
;
...
...
@@ -973,12 +961,12 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
/*Since we free until index _not_ inclusive, the one before index is
* the last we will free. This one must be used */
last_to_free
=
iwl_queue_dec_wrap
(
tfd_num
,
q
->
n_bd
);
last_to_free
=
iwl_queue_dec_wrap
(
tfd_num
);
if
(
!
iwl_queue_used
(
q
,
last_to_free
))
{
IWL_ERR
(
trans
,
"%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.
\n
"
,
__func__
,
txq_id
,
last_to_free
,
q
->
n_bd
,
__func__
,
txq_id
,
last_to_free
,
TFD_QUEUE_SIZE_MAX
,
q
->
write_ptr
,
q
->
read_ptr
);
goto
out
;
}
...
...
@@ -988,7 +976,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
for
(;
q
->
read_ptr
!=
tfd_num
;
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
,
q
->
n_bd
))
{
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
))
{
if
(
WARN_ON_ONCE
(
txq
->
entries
[
txq
->
q
.
read_ptr
].
skb
==
NULL
))
continue
;
...
...
@@ -1027,16 +1015,16 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
lockdep_assert_held
(
&
txq
->
lock
);
if
((
idx
>=
q
->
n_bd
)
||
(
!
iwl_queue_used
(
q
,
idx
)))
{
if
((
idx
>=
TFD_QUEUE_SIZE_MAX
)
||
(
!
iwl_queue_used
(
q
,
idx
)))
{
IWL_ERR
(
trans
,
"%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.
\n
"
,
__func__
,
txq_id
,
idx
,
q
->
n_bd
,
__func__
,
txq_id
,
idx
,
TFD_QUEUE_SIZE_MAX
,
q
->
write_ptr
,
q
->
read_ptr
);
return
;
}
for
(
idx
=
iwl_queue_inc_wrap
(
idx
,
q
->
n_bd
);
q
->
read_ptr
!=
idx
;
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
,
q
->
n_bd
))
{
for
(
idx
=
iwl_queue_inc_wrap
(
idx
);
q
->
read_ptr
!=
idx
;
q
->
read_ptr
=
iwl_queue_inc_wrap
(
q
->
read_ptr
))
{
if
(
nfreed
++
>
0
)
{
IWL_ERR
(
trans
,
"HCMD skipped: index (%d) %d %d
\n
"
,
...
...
@@ -1327,28 +1315,39 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
cmd_pos
=
offsetof
(
struct
iwl_device_cmd
,
payload
);
copy_size
=
sizeof
(
out_cmd
->
hdr
);
for
(
i
=
0
;
i
<
IWL_MAX_CMD_TBS_PER_TFD
;
i
++
)
{
int
copy
=
0
;
int
copy
;
if
(
!
cmd
->
len
[
i
])
continue
;
/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */
if
(
copy_size
<
IWL_HCMD_SCRATCHBUF_SIZE
)
{
copy
=
IWL_HCMD_SCRATCHBUF_SIZE
-
copy_size
;
if
(
copy
>
cmd
->
len
[
i
])
copy
=
cmd
->
len
[
i
];
}
/* copy everything if not nocopy/dup */
if
(
!
(
cmd
->
dataflags
[
i
]
&
(
IWL_HCMD_DFL_NOCOPY
|
IWL_HCMD_DFL_DUP
)))
IWL_HCMD_DFL_DUP
)))
{
copy
=
cmd
->
len
[
i
];
if
(
copy
)
{
memcpy
((
u8
*
)
out_cmd
+
cmd_pos
,
cmd
->
data
[
i
],
copy
);
cmd_pos
+=
copy
;
copy_size
+=
copy
;
continue
;
}
/*
* Otherwise we need at least IWL_HCMD_SCRATCHBUF_SIZE copied
* in total (for the scratchbuf handling), but copy up to what
* we can fit into the payload for debug dump purposes.
*/
copy
=
min_t
(
int
,
TFD_MAX_PAYLOAD_SIZE
-
cmd_pos
,
cmd
->
len
[
i
]);
memcpy
((
u8
*
)
out_cmd
+
cmd_pos
,
cmd
->
data
[
i
],
copy
);
cmd_pos
+=
copy
;
/* However, treat copy_size the proper way, we need it below */
if
(
copy_size
<
IWL_HCMD_SCRATCHBUF_SIZE
)
{
copy
=
IWL_HCMD_SCRATCHBUF_SIZE
-
copy_size
;
if
(
copy
>
cmd
->
len
[
i
])
copy
=
cmd
->
len
[
i
];
copy_size
+=
copy
;
}
}
...
...
@@ -1363,7 +1362,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
memcpy
(
&
txq
->
scratchbufs
[
q
->
write_ptr
],
&
out_cmd
->
hdr
,
scratch_size
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
iwl_pcie_get_scratchbuf_dma
(
txq
,
q
->
write_ptr
),
scratch_size
,
1
);
scratch_size
,
true
);
/* map first command fragment, if any remains */
if
(
copy_size
>
scratch_size
)
{
...
...
@@ -1379,7 +1378,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
}
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
phys_addr
,
copy_size
-
scratch_size
,
0
);
copy_size
-
scratch_size
,
false
);
}
/* map the remaining (adjusted) nocopy/dup fragments */
...
...
@@ -1402,7 +1401,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
goto
out
;
}
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
phys_addr
,
cmdlen
[
i
],
0
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
phys_addr
,
cmdlen
[
i
],
false
);
}
out_meta
->
flags
=
cmd
->
flags
;
...
...
@@ -1445,7 +1444,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
}
/* Increment and update queue's write index */
q
->
write_ptr
=
iwl_queue_inc_wrap
(
q
->
write_ptr
,
q
->
n_bd
);
q
->
write_ptr
=
iwl_queue_inc_wrap
(
q
->
write_ptr
);
iwl_pcie_txq_inc_wr_ptr
(
trans
,
txq
);
spin_unlock_irqrestore
(
&
trans_pcie
->
reg_lock
,
flags
);
...
...
@@ -1740,7 +1739,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
memcpy
(
&
txq
->
scratchbufs
[
q
->
write_ptr
],
&
dev_cmd
->
hdr
,
IWL_HCMD_SCRATCHBUF_SIZE
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb0_phys
,
IWL_HCMD_SCRATCHBUF_SIZE
,
1
);
IWL_HCMD_SCRATCHBUF_SIZE
,
true
);
/* there must be data left over for TB1 or this code must be changed */
BUILD_BUG_ON
(
sizeof
(
struct
iwl_tx_cmd
)
<
IWL_HCMD_SCRATCHBUF_SIZE
);
...
...
@@ -1750,7 +1749,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
tb1_phys
=
dma_map_single
(
trans
->
dev
,
tb1_addr
,
tb1_len
,
DMA_TO_DEVICE
);
if
(
unlikely
(
dma_mapping_error
(
trans
->
dev
,
tb1_phys
)))
goto
out_err
;
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb1_phys
,
tb1_len
,
0
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb1_phys
,
tb1_len
,
false
);
/*
* Set up TFD's third entry to point directly to remainder
...
...
@@ -1766,7 +1765,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
&
txq
->
tfds
[
q
->
write_ptr
]);
goto
out_err
;
}
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb2_phys
,
tb2_len
,
0
);
iwl_pcie_txq_build_tfd
(
trans
,
txq
,
tb2_phys
,
tb2_len
,
false
);
}
/* Set up entry for this TFD in Tx byte-count array */
...
...
@@ -1788,7 +1787,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
mod_timer
(
&
txq
->
stuck_timer
,
jiffies
+
trans_pcie
->
wd_timeout
);
/* Tell device the write index *just past* this latest filled TFD */
q
->
write_ptr
=
iwl_queue_inc_wrap
(
q
->
write_ptr
,
q
->
n_bd
);
q
->
write_ptr
=
iwl_queue_inc_wrap
(
q
->
write_ptr
);
if
(
!
wait_write_ptr
)
iwl_pcie_txq_inc_wr_ptr
(
trans
,
txq
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment