Compare commits

...

157 commits

Author SHA1 Message Date
Jeff Johnson
6e3ee2446a ath10k-bdencoder: update ATH10K_FIRMWARE_URL to point to CLO
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-12-02 16:54:27 -08:00
Jeff Johnson
61d85e04cf Update ath12k-fw-repo
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-12-02 16:37:08 -08:00
Jeff Johnson
03252af2fe Update ath11k-fw-repo
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-12-02 16:37:08 -08:00
Jeff Johnson
c1e4ca6032 ath12k-check: Override ath12k_wifi7_dp_mon_*() long lines
The ath12k next generation refactoring resulted in some long function
names, which it turn resulted in some long lines in ath12k/wifi7
reported by checkpatch. Suppress those new warnings.

Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-11-10 09:02:29 -08:00
Jeff Johnson
852bd62202 ath12k-check: ignore sparse "context imbalance" warnings
Sparse does not fully understand the guard cleanup feature, and can
produce warnings of the form:

warning: context imbalance in '<function>' - wrong count at exit

These are false positives when guard() is being used, so ignore
them.

Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-10-31 09:20:09 -07:00
Jeff Johnson
c66ae81c34 ath11k-check: ignore sparse "context imbalance" warnings
Sparse does not fully understand the guard cleanup feature, and can
produce warnings of the form:

warning: context imbalance in '<function>' - wrong count at exit

These are false positives when guard() is being used, so ignore
them.

Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-10-23 11:17:35 -07:00
Jeff Johnson
a87e8e4971 ath12k-check: update checkpatch commit to 99b70ece33d87500ef7bee8e32cb99772c45ce14
Update to the latest checkpatch.

Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-10-21 15:57:29 -07:00
Jeff Johnson
e81a60303e ath11k-check: update checkpatch commit to 99b70ece33d87500ef7bee8e32cb99772c45ce14
Update to the latest checkpatch.

With this version there is a new warning that is tricky to fix
cleanly, so add that warning to the checkpatch_filter list.

Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-10-21 15:48:05 -07:00
Jeff Johnson
0ff2f11365 ath10k-check: update checkpatch commit to 99b70ece33d87500ef7bee8e32cb99772c45ce14
Update to the latest checkpatch.

With this version there is a new warning that is tricky to fix
cleanly, so add that warning to the checkpatch_filter list.

Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-10-21 15:36:44 -07:00
Jeff Johnson
7c191e5530 Update ath11k-fw-repo
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-06-03 10:37:03 -07:00
Jeff Johnson
34ba9a417a Update ath12k-bdencoder
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-06-03 10:31:00 -07:00
Jeff Johnson
0c0ecdde8d Update ath12k-fw-repo
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-06-03 10:31:00 -07:00
Jeff Johnson
e53ea71655 ath12k-check: Support subdirectories
The ath12k-ng refactoring of ath12k introduces subdirectories.
Update ath12k-check to properly handle the subdirectories.

Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-05-08 16:00:56 -07:00
Jeff Johnson
3349c9cfbd ath12k-check: ignore PREFER_PR_LEVEL warning
A new ath12k patch [1] triggers a PREFER_PR_LEVEL checkpatch warning:

drivers/net/wireless/ath/ath12k/debug.c:69: Prefer [subsystem eg: netdev]_dbg([subsystem]dev, ... then dev_dbg(dev, ... then pr_debug(...  to printk(KERN_DEBUG ...

Add a rule to ignore it.

Link: https://lore.kernel.org/all/20250204-unlink_link_arvif_from_chanctx-v2-2-764fb5973c1a@oss.qualcomm.com/
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-02-07 09:10:34 -08:00
Jeff Johnson
8adc4981da ath12k-check: fix long line comment check for copyright
Fix the check for long line copyright comments.

Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-01-21 10:27:18 -08:00
Jeff Johnson
4883953301 ath12k-check: ignore long line comment warnings for copyrights
Filter the warnings about copyright statements exceeding the max line
length. Since the global tool won't associate these with a symbol
name, filter on the literal "Copyright (c)" itself.

Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
2025-01-14 10:52:02 -08:00
Kalle Valo
7a1463a442 Update ath12k-fwencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-10-01 10:38:35 +03:00
Kalle Valo
4af5153126 Update ath12k-fw-repo
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-08-13 19:47:58 +03:00
Kalle Valo
a5ef12e166 Update ath12k-fw-repo
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-08-13 18:50:30 +03:00
Kalle Valo
06cbf01a58 Update ath11k-fw-repo
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-08-13 18:50:30 +03:00
Kalle Valo
583eed7e66 ath12k-check: ignore macro reuse warnings about for_each_ar()
Filter the warnings about the upcoming for_each_ar() macro's variable reuse. As
the global tool apparently doesn't create symbol names for macro. Add a hack
for those cases where we check if the actual line in the file contains the tag
name.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-03-28 17:28:14 +02:00
Kalle Valo
e9a0327f3f Add ath12k-fw-repo
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-03-04 19:13:01 +02:00
Kalle Valo
741a9f6d27 Update ath11k-fw-repo
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-03-04 19:12:39 +02:00
Kalle Valo
d23aaaec6e Update ath10k-fw-repo
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-03-04 19:12:39 +02:00
Kalle Valo
8ec3e5dbb8 Add ath12k-fwencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-02-12 12:10:45 +02:00
Kalle Valo
88724401e4 ath11k-check: update checkpatch commit to 296455ade1fdcf5f8f8c033201633b60946c589a
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-01-26 18:40:24 +02:00
Kalle Valo
0982c0f22e ath12k-check: update checkpatch commit to 296455ade1fdcf5f8f8c033201633b60946c589a
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-01-26 18:38:33 +02:00
Kalle Valo
ef11ea4c7a ath12k-check: run kernel-doc
Idea and example from Jeff Johnson.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-01-26 18:31:11 +02:00
Kalle Valo
0a556ac040 ath12k-check: get_commited_files(): use --name-only
No need to use cut as git ls-tree has --name-only. No functional changes.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-01-26 18:20:54 +02:00
Kalle Valo
02efab2e3e ath12k-check: refactor code to get_commited_files()
This function is needed also elsewhere.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2024-01-26 18:17:26 +02:00
Kalle Valo
f216408592 Update ath12k-bdencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-12-21 01:53:49 +02:00
Kalle Valo
60d4be5e42 Add ath11k-fwencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-12-21 01:53:49 +02:00
Kalle Valo
6209ad4248 Update ath11k-bdencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-12-21 01:53:49 +02:00
Kalle Valo
0df6dcf34f Update ath10k-fw-repo
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-12-21 01:53:49 +02:00
Kalle Valo
b011424559 Update ath10k-bdencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-12-21 01:53:49 +02:00
Kalle Valo
32f41c2db0 ath12k-check: ignore PREFER_DEV_LEVEL warning
Needed for patch:

wifi: ath12k: fix debug messages

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-10-04 18:27:09 +03:00
Kalle Valo
779e51b9de ath12k-check: improve installation instructions in the help text
As people have had problems setting ath12k-check improve the instructions how
to set up everything. Hopefully we get more consistent results that way. The
instructions are visible --help switch.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-10-04 11:53:29 +03:00
Kalle Valo
8aafad4337 ath12k-check: print compiler version specified in kernel .config file
As the compiler used to compile the kernel can be different from the default
host compiler, print both the host GCC and the compiler specified in .config
file.

Screenshot:

ath12k-check (md5sum a143ac447ffce2545530c2b4ad96a2e8)

python:		3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0]
host gcc:	gcc (Debian 12.2.0-14) 12.2.0
config cc:	x86_64-linux-gcc (GCC) 13.2.0
sparse:		v0.6.4-39-gce1a6720f69e
checkpatch.pl:	Version: 0.32 (md5sum 47ef327d772c156e53a36597723fc781)
gtags:		gtags (Global) 6.6.9

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-10-03 20:56:51 +03:00
Kalle Valo
d0f69db447 ath12k-check: add location of sparse git repository
Latest sparse is needed for testing the kernel, document where to
install it from.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-09-27 15:22:53 +03:00
Kalle Valo
cc349436fe ath11k-check: print python version in --version
Hopefully makes it easier to debug reported problems.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-09-27 10:04:04 +03:00
Kalle Valo
e5372e1524 ath11k-check: use shutil.which()
Distutils module is deprecated so use shutil.which() instead.
    
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-09-27 10:02:00 +03:00
Kalle Valo
d5ebee489e ath12k-check: print python version in --version
Screenshot:

$ ath12k-check --version
ath12k-check (md5sum 5da1780d8e06bb2db43abce01dda1ca8)

python:		3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0]
gcc:		gcc (Debian 12.2.0-14) 12.2.0
sparse:		v0.6.4-39-gce1a6720f69e
checkpatch.pl:	Version: 0.32 (md5sum 47ef327d772c156e53a36597723fc781)
gtags:		gtags (Global) 6.6.9

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-09-27 09:58:29 +03:00
Kalle Valo
2bd53768fa ath12k-check: using shutil.which()
Distutils module is deprecated so use shutil.which() instead.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-09-27 09:52:49 +03:00
Kalle Valo
9a16a4abec ath11k-check: verify checkpatch.pl md5sum
Print a warning if checkpatch.pl md5sum doesn't match. This way it's easier to
make sure that correct version of checkpatch is used.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-09-06 16:55:49 +03:00
Kalle Valo
c880314adb ath12k-check: verify checkpatch.pl md5sum
Print a warning if checkpatch.pl md5sum doesn't match. This way it's easier to
make sure that correct version of checkpatch is used.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-09-06 16:46:46 +03:00
Kalle Valo
27d9574ce6 ath1[0-2]-check: update checkpatch commit id to 362173572a40
Document the checkpatch.pl version I'm using at the moment:

362173572a40 checkpatch: improve EMBEDDED_FILENAME test

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-09-06 15:48:39 +03:00
Kalle Valo
a163e2363f Update ath10k-bdencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-03-20 19:59:55 +02:00
Kalle Valo
b0e7d9c976 Update ath10k-bdencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-03-17 14:12:54 +02:00
Kalle Valo
69808f48c1 Update ath10k_pktlog.py
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-01-10 15:08:10 +02:00
Kalle Valo
1a320ce216 Update ath10k.py
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-01-10 15:08:10 +02:00
Kalle Valo
1b7c9fb32c Add ath12k-bdencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-01-10 15:08:10 +02:00
Kalle Valo
df3a159d34 Update ath11k-bdencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-01-10 15:08:10 +02:00
Kalle Valo
c3dde80180 Update ath10k-fw-repo
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2023-01-10 15:08:10 +02:00
Kalle Valo
b0e905ff7b ath12k-check: don't filter dubious warnings
They are not seen with ath12k anymore, most likely switch to u32_get_bits()
fixed those.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-08-11 16:55:08 +03:00
Kalle Valo
1b102ba512 ath12k-check: enable more checkpatch warnings
Most of the disabled warnings are now fixed so can enable more warnings.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-07-01 12:24:48 +03:00
Kalle Valo
581c684881 ath12k-check: enable more checkpatch warnings
As these warnings are now fixed in ath12k it's possible to enable them.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-06-27 21:02:04 +03:00
Kalle Valo
16978c25c8 ath12k-check: ignore more long lines from qmi commands
Had to do one workaround due to gtags working strangely.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-06-11 15:03:45 +03:00
Kalle Valo
29b0a2607f Update ath11k-fw-repo
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-05-27 17:22:41 +03:00
Kalle Valo
014bb0c6ac Update ath10k-fw-repo
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-05-27 17:22:40 +03:00
Kalle Valo
d2fb7b932a Update ath11k-bdencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-04-13 11:16:54 +03:00
Kalle Valo
4661dc4994 Add ath12k-check
This is a copy from ath11k-check with minor modifications:

e471454ac6 ath11k-check: port to python3

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-02-08 17:43:54 +02:00
Kalle Valo
e471454ac6 ath11k-check: port to python3
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-02-08 17:31:16 +02:00
Kalle Valo
25a662da8a ath10k-check: port to python3
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-02-08 17:20:32 +02:00
Kalle Valo
105e81816d ath10k-check: support multiline checkpatch warnings
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-02-08 17:13:36 +02:00
Kalle Valo
52d3a2f0fc ath10k-check: don't use global with Kconfig and Makefile
Starting from Debian 10 global returns an error with Kconfig and
Makefile, add a workaround for that.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-02-08 17:05:47 +02:00
Kalle Valo
9983705ee8 ath11k-check: don't use global with Kconfig and Makefile
Starting from Debian 10 global returns an error with Kconfig and
Makefile, add a workaround for that.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-02-08 17:05:47 +02:00
Kalle Valo
64a3e2aabf ath11k-check: support multiline checkpatch warnings
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-02-08 16:53:40 +02:00
Kalle Valo
ae8de256db Remove obsolete qca-wireless-regdb.txt 2022-01-24 21:21:19 +02:00
Kalle Valo
8e32e24877 Update ath10k-fwencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-01-24 21:00:55 +02:00
Kalle Valo
3c1f22bdc4 Merge branch 'py3' of https://github.com/lumag/qca-swiss-army-knife 2022-01-24 20:11:22 +02:00
Kalle Valo
fe60d963b2 Update ath10k-bdencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-01-24 20:05:53 +02:00
Kalle Valo
df3e162316 Merge branch 'python3-bdencoder' of https://github.com/ecsv/qca-swiss-army-knife into pull-3 2022-01-24 19:54:39 +02:00
Kalle Valo
f85b165960 Update ath10k-fwencoder
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
2022-01-24 19:25:59 +02:00
Kalle Valo
b8f89c13d0 Merge branch 'python3-fixes' of https://github.com/erstrom/qca-swiss-army-knife into pull-2 2022-01-24 19:08:23 +02:00
Kalle Valo
ec8783694c scripts: move ath11k-bdencoder under ath11k directory
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2021-03-02 16:44:13 +02:00
Kalle Valo
5be8c832f5 Add ath11k-bdencoder
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2021-03-01 14:06:56 +02:00
Kalle Valo
4b2b0e0c16 Update ath11k-fw-repo
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2021-03-01 14:06:56 +02:00
Kalle Valo
8633532930 Update ath10k-fw-repo
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2021-03-01 14:06:56 +02:00
Dmitry Baryshkov
26ca6eff75 scripts: port to python3
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
2020-12-17 01:37:58 +03:00
Dmitry Baryshkov
3d23932fd8 ath10k-fwencoder: port to python3
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
2020-12-17 01:37:58 +03:00
Dmitry Baryshkov
4ffa07ff68 read-powers: port to python3
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
2020-12-17 01:37:58 +03:00
Kalle Valo
5ede3cc07e Add ath11k-fw-repo
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2020-10-21 19:45:53 +03:00
Kalle Valo
45f9903552 Update ath10k-fw-repo
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2020-10-21 19:45:53 +03:00
Sven Eckelmann
cc7558fe2c ath10k-bdencoder: Switch to python3
Python 2.x is EOL since January 2020. The first distributions already
started to drop the interpreters from their next distribution release. Just
add some minor changes to make it python3 compatible.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
2020-10-14 16:14:47 +02:00
Erik Stromdahl
6fef42b8a8 Update ath10k-fwencoder to run properly with Python 3
Explicit string encoding and decoding of UTF-8 strings was added
in order to make the script work with python 3.

Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
2020-07-06 10:00:55 +02:00
Erik Stromdahl
c2bd6f580d Update ath10k-bdencoder to run properly with Python 3
Explicit string encoding and decoding of UTF-8 strings was added in order
to make the script work with python 3.

Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
2020-07-06 10:00:55 +02:00
Erik Stromdahl
60bec5a5b9 Fix Python 3 syntax errors in ath10k tools
Since Python 2 is soon to be deprecated it would be nice if the tool
works with a python3 interpreter (default on many distros).

Previous commits addressing these issues did not solve all issues (not
all print statements were converted etc.).

Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
2020-07-06 10:00:55 +02:00
Kalle Valo
8c813ad8b8 Merge branch 'master' of https://github.com/alimon/qca-swiss-army-knife 2020-05-20 17:33:15 +03:00
Kalle Valo
6cb86fb99b Update ath10k_pktlog.py
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2020-05-20 16:31:24 +03:00
Kalle Valo
31bc69fe0c Update ath10k.py
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2020-05-20 16:31:24 +03:00
Kalle Valo
15852ea927 Update ath10k-bdencoder
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2020-05-20 16:31:24 +03:00
Aníbal Limón
0c01a2abc3 tools/*/ath10k: Add support for python3 in ath10k-bencoder
Now compatible with Python2 and Python3,

- Minimal changes in print add ().
- Changes in struct due to default byte strings in Python3.

Tested building board-2.bin for Dragonboard845c.

Signed-off-by: Aníbal Limón <anibal.limon@linaro.org>
2020-04-06 15:46:09 -05:00
Kalle Valo
4d397963b1 Update ath11k-check
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2019-06-27 22:02:02 +03:00
Kalle Valo
30ea075ea1 Update ath10k-fwencoder
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2019-06-27 22:02:02 +03:00
Kalle Valo
bec3a2f191 Update ath10k-check
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2019-06-27 22:02:02 +03:00
Kalle Valo
f9cbcad82a Add ath11k-check
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2019-06-12 12:00:34 +03:00
Kalle Valo
7c5ac7ec65 Update ath10k-fwencoder
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2019-06-03 13:14:41 +03:00
Kalle Valo
497200c3fd Update ath10k-check
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2019-06-03 13:14:41 +03:00
Kalle Valo
063dff9967 Update ath10k-fw-repo
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2018-10-13 14:24:20 +03:00
Kalle Valo
141f3b0e02 Update ath10k-bdencoder
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2018-10-13 14:24:20 +03:00
Kalle Valo
605442e9a8 Update ath10k.py
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2018-07-03 21:16:33 +03:00
Kalle Valo
99c601ea1f Update ath10k-fw-repo
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2018-07-03 21:16:33 +03:00
Kalle Valo
6c34812fc7 Update ath10k-bdencoder
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2018-07-03 21:16:33 +03:00
Kalle Valo
26f9460b33 Update ath10k-fwencoder
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2018-07-03 21:16:33 +03:00
Kalle Valo
f371c26cea Update ath10k-check
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2018-07-03 21:16:33 +03:00
Kalle Valo
db953a5381 Update ath10k_pktlog.py
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-10-31 13:27:10 +02:00
Kalle Valo
e1df87fd10 Update ath10k.py
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-10-31 13:27:10 +02:00
Kalle Valo
3ead7a23e8 Update ath10k-fw-repo
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-10-31 13:27:10 +02:00
Kalle Valo
e92ab4b9b9 Update ath10k-bdencoder
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-10-31 13:27:10 +02:00
Kalle Valo
a208017c60 Update ath10k-fwencoder
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-10-31 13:27:10 +02:00
Kalle Valo
30da9160b8 Update ath10k-check
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-10-31 13:27:10 +02:00
Maharaja Kennadyrajan
8a80300141 tracing: Fix pktlog support for QCA9888 & QCA9984 chipsets
This patch enables the support for parsing pktlog from trace
points taken on a QCA9888 & QCA9984 chipsets.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-08-15 12:09:27 +03:00
Kalle Valo
d9c3d5857a tools: ath10k-check: enable SYMBOLIC_PERMS checkpatch check
The issues in ath10k have been fixed now.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-05-05 10:46:58 +03:00
Kalle Valo
e23fbd3c96 tools: ath10k-check: enable BLOCK_COMMENT_STYLE checkpatch warning
Since ath10k commit 37ff1b0df37a ("ath10k: clean header files from bad block
comments", going to 4.12) ath10k has been cleaned with all block comment
issues. So now we can enable the checkpatch warning.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-04-05 11:42:37 +03:00
Kalle Valo
d278f25bc9 tools: update ath10k-[fw|bd]encoder
New features and bugfixes.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-02-10 13:05:18 +02:00
Kalle Valo
496c42817e tools: ath10k-check: add --extra command line switch
This is for running optional checks which we haven't fixed yet or might be
false positive. Currently enables only W=1 for kernel.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-02-08 11:28:04 +02:00
Kalle Valo
25d27878f4 tools: ath10k-check: document more ignored checkpatch warnings
I should clean up that at some point and try to reduce it.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-02-07 15:08:51 +02:00
Kalle Valo
ceb26e3416 tools: ath10k-check: apply --no-filter switch also for checkpatch filter
Just for consistency.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-02-07 15:00:07 +02:00
Kalle Valo
b9a32cfd44 tools: ath10k-check: add --version command line switch
To make it easier to check all versions.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-02-07 14:53:19 +02:00
Kalle Valo
f33d779002 scripts: ath10k-check: filter warnings not coming from ath directory
By default the script now does not show any warnings outside ath directory, but
with --no-filter that can be disabled:

$ ath10k-check
$ ath10k-check --no-filter
./arch/x86/include/asm/uaccess.h:714:18: warning: incorrect type in argument 1 (different modifiers)
./arch/x86/include/asm/uaccess.h:714:18:    expected void *<noident>
./arch/x86/include/asm/uaccess.h:714:18:    got void const *from
./include/linux/relay.h:209:16: warning: incorrect type in initializer (different address spaces)
./include/linux/relay.h:209:16:    expected void const [noderef] <asn:3>*__vpp_verify
./include/linux/relay.h:209:16:    got struct rchan_buf **<noident>
$

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-02-02 15:05:21 +02:00
Kalle Valo
4d0fe54348 scripts: ath10k-check: fix nproc command
For testing purposes I had used 'nproc2' but forgot to change that before
commit.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-02-02 14:45:36 +02:00
Kalle Valo
e07a588ad4 scripts: ath10k-check: add usage and installation instructions
Hopefully this is now easier for people to use. Also use nproc to get the
number of cores available.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2017-02-02 13:58:58 +02:00
Maharaja Kennadyrajan
cc5a3bd6f6 tracing: Fix the buf usage while parsing ath10k_htt_stats
This patch solves the buf usage prob when parsing the
ath10k_htt_stats and updated the ibf_VHT_TX_TxBF count.
2016-11-24 14:26:00 +02:00
Kalle Valo
d2a219ab16 tools: ath10k-check: run checkpatch in parallel
A lot faster now.
2016-08-31 10:02:35 +03:00
Ashok Raj Nagarajan
cf8d9a8c83 tracing: update hw revision enumeration
Updating the hw enumeration here to keep in sync with ath10k.

kvalo: ath10k accidentally broke the backwards compatibility in
hw revision in these commits:

e565c3125e03 ath10k: enable support for QCA9888
651b4cdcf97e ath10k: enable support for QCA9984

But this should not happen anymore. I added a comment to document
that.
2016-08-30 09:31:53 +03:00
Kalle Valo
a34666a4fc ath10k scripts: add ath10k-fw-repo
Add a script for installing firmware images from ath10k-firmware.git
repository and help with other firmware management related tasks.

usage: ath10k-fw-repo [-h] [--debug] [--dry-run] [--check] [--list]
                      [--install DESTINATION] [--unit-test]

Install firmware images from the ath10k-firmware git repository. Run it from
the top directory of the working tree.

optional arguments:
  -h, --help            show this help message and exit
  --debug               Enable debug messages.
  --dry-run             Do not run any actual commands.
  --check               Check the ath10k-firmware repository content for
                        validity.
  --list                List all files found from the ath10k-firmware
                        repository.
  --install DESTINATION
                        Install all ath10k firmware images to DESTINATION
                        folder, for example /lib/firmware.
  --unit-test           Run unit tests for this script.


Screenshot:

$ ath10k-fw-repo --install /lib/firmware
Unknown file: QCA99X0/hw2.0/boardData_AR900B_CUS239_5G_v2_001.bin
Unknown file: QCA99X0/hw2.0/boardData_AR900B_CUS260_2G_v2_002.bin
Installing QCA9377/hw1.0/firmware-5.bin (WLAN.TF.1.0-00267-1)
Installing QCA9377/hw1.0/notice_ath10k_firmware-5.txt (WLAN.TF.1.0-00267-1)
Installing QCA9377/hw1.0/board.bin
Installing QCA9377/hw1.0/board-2.bin
Installing QCA988X/hw2.0/firmware-5.bin (10.2.4.70.54)
Installing QCA988X/hw2.0/notice_ath10k_firmware-5.txt (10.2.4.70.54)
Installing QCA988X/hw2.0/board.bin
Installing QCA4019/hw1.0/firmware-5.bin (10.4-3.2-00080)
Installing QCA4019/hw1.0/notice_ath10k_firmware-5.txt (10.4-3.2-00080)
Installing QCA4019/hw1.0/board-2.bin
Installing QCA9888/hw2.0/firmware-5.bin (10.4-3.2-00072)
Installing QCA9888/hw2.0/board-2.bin
Installing QCA9887/hw1.0/firmware-5.bin (10.2.4-1.0-00013)
Installing QCA9887/hw1.0/notice_ath10k_firmware-5.txt (10.2.4-1.0-00013)
Installing QCA9887/hw1.0/board.bin
Installing QCA99X0/hw2.0/firmware-5.bin (10.4.1.00030-1)
Installing QCA99X0/hw2.0/notice_ath10k_firmware-5.txt (10.4.1.00030-1)
Installing QCA6174/hw3.0/firmware-4.bin (WLAN.RM.2.0-00180-QCARMSWPZ-1)
Installing QCA6174/hw3.0/notice_ath10k_firmware-4.txt (WLAN.RM.2.0-00180-QCARMSWPZ-1)
Installing QCA6174/hw3.0/board-2.bin
Installing QCA6174/hw3.0/board.bin
Installing QCA6174/hw2.1/firmware-5.bin (SW_RM.1.1.1-00157-QCARMSWPZ-1)
Installing QCA6174/hw2.1/notice_ath10k_firmware-5.txt (SW_RM.1.1.1-00157-QCARMSWPZ-1)
Installing QCA6174/hw2.1/board.bin
Installing QCA6174/hw2.1/board-2.bin
Installing QCA9984/hw1.0/firmware-5.bin (10.4-3.2-00072)
Installing QCA9984/hw1.0/notice_ath10k_firmware-5.txt (10.4-3.2-00072)
Installing QCA9984/hw1.0/board-2.bin
$
2016-08-23 14:08:06 +03:00
Ashok Raj Nagarajan
e5f25e1af0 tracing: don't throw exception when payload given is higher
With "ath10k: simplify pktlog htt event processing" approach, driver passes
entire payload stipping the htt_response header. By this method, we could
receive pktlog events that has payload size higher than mentioned in pktlog
header (for alignment reasons)

This issue is seen with 10.2 FW for ATH10K_PKTLOG_TYPE_TX_MSDU_ID type events.

So throw exception only when payload size is lesser than the one mentioned in
pktlog header
2016-06-22 14:05:56 +03:00
Rajkumar Manoharan
dfd83b4336 tracing: fix txctl handling
txctl log type manipulates pktlog header and log data as well. payload
length should be handled differently for 10.2 and 10.4 based firmware.
Not doing so, will generate invalid pktlog data file.
2016-06-22 14:05:53 +03:00
Rajkumar Manoharan
4b4ce97aa9 tracing: fix hw_type checks for qca40xx 2016-06-22 14:05:53 +03:00
Rajkumar Manoharan
40f0f7474b tracing: fix hw revision enumeration 2016-06-22 14:05:53 +03:00
Ashok Raj Nagarajan
17622eeb5d tracing: add pktlog support for QCA40xx chipsets
This patch enables the support for generate pktlog.dat from trace points
taken on a QCA40xx chipsets
2016-06-07 10:10:37 +03:00
Maharaja Kennadyrajan
25e5adbb2d tracing: ath10k: Add New Data Path related HTT stats support for QCA99XX & QCA40XX
Below stats are added in this patch
1.tx_desc stats 2.tx_fetch_mgr info stats 3.tx_pf_sched info stats

Signed-off-by: Maharaja Kennadyrajan <c_mkenna@qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2016-04-12 15:36:16 +03:00
Maharaja Kennadyrajan
91c07af56b tracing: ath10k: Add SIFS resp info, Reset info and mac wdog related HTT stats support for QCA99XX & QCA40XX
Below stats are added in this patch
1.sifs_resp info stats 2.reset info stats 3.mac_wdog stats

Signed-off-by: Maharaja Kennadyrajan <c_mkenna@qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2016-04-12 15:36:16 +03:00
Maharaja Kennadyrajan
7e2081c04b tracing: ath10k: Add Tx Beam Forming Mu-MIMO related HTT stats support for QCA99XX & QCA40XX
Below stats are added in this patch
1.txbf_data stats 2.txbf_send_info stats 3.tx_selfgen stats
4.tx_mu stats

Signed-off-by: Maharaja Kennadyrajan <c_mkenna@qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2016-04-12 15:36:16 +03:00
Maharaja Kennadyrajan
4a20ff7a97 tracing: ath10k: Add Tx Rx and TIDS related HTT stats support for QCA99XX & QCA40XX
ath10k_htt_stats doesn't have all the htt stats support.
Below stats are added in this patch
1.pdev_txrx stats 2.rx_reorder stats 3.rx_rate_info stats
4.tx_rate_info stats 5.tidq stats

Signed-off-by: Maharaja Kennadyrajan <c_mkenna@qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2016-04-12 15:36:16 +03:00
Kalle Valo
d610cee8b7 ath10k-check: add new checkpatch warnings to ignore
I updated checkpatch and saw quite a lot of new warnings. Disable the ones
which don't really make sense.
2016-03-24 16:24:53 +02:00
Ashok Raj Nagarajan
c991fcb638 tracing: extend plugin to support pktlog for 10.4 FW
Currently tracing plugin works only for QCA988X chipsets. This patch
extend the support to generate pktlog for QCA99X0.

With the ath10k commit "ath10k: add hw_rev to trace events to support
pktlog" we now have a new attribute passed with tracing events
"hw_type" that helps to determine the chipset used for taking the trace
points. This is helpful in getting FW variant used thereby generating
pktlog.dat accordingly.

To support backward compatibility for older versions of ath10k, assume the
default value of the hw_type, if not provided, to be HW_QCA988X (0).
2016-02-08 15:22:25 +02:00
Anilkumar Kolli
cfb531695a tracing: ath10k: fix htt_rx_desc for QCA988X
ath10k_htt_rx_desc has QCA988X,QCA99X0 and QCA6174 packet information.
ath10k_htt_rx_desc has QCA99X0 relted structures at various offsets. The current
script has not taken care of QCA99X0 changes.

This modification has fix for QCA988X chipsets.

We will fix this script for all the supported chipsets later by sending
one more trcing attribute from the driver.
2015-12-30 15:46:07 +02:00
Kalle Valo
b2b06517bb scripts: ath10k: add ath10k-fwencoder and ath10k-bdencoder
Scripts for handling ath10k firmware image container format.
2015-12-03 17:41:27 +02:00
Kalle Valo
41b194534b ath10k-check: fix object file deletion
It didn't work as I had forgetten to enable shell to get wildcard extensions
work.
2015-10-09 10:53:10 +03:00
Kalle Valo
587f0ca617 add ath10k-check 2015-10-01 12:15:40 +03:00
Rajkumar Manoharan
7903ede3c6 tracing: fix msdu_id processing pktlog_tx_msdu_id
Whenever trace record is started in middle of data flow, the
msdu_len_tbl is not fully populated. For the initial MSDU_ID log
types, msdu_id can not be found in msdu_len_tbl. If the entries
are not found set the msdu_len to 0. This will also fix below
errors.

  File "ath10k_pktlog.py", line 297, in <lambda>
    ath10k_htt_pktlog_handler(pevent, *args))
  File "ath10k_pktlog.py", line 238, in ath10k_htt_pktlog_handler
    pktlog_tx_msdu_id(buf)
  File "ath10k_pktlog.py", line 218, in pktlog_tx_msdu_id
    msdu_len = msdu_len_tbl[msdu_id]
2015-01-29 17:19:56 +02:00
Rajkumar Manoharan
04d7947835 tracing: fix rxdesc parsing in ath10k_pktlog.py
Since tsf is valid only for last mpdu and it is already part
of rx descriptor dump, tsf argument is removed from
ath10k_htt_rx_desc tracepoint in ath10k. Hence updating the
parser accordingly.
2015-01-12 20:20:43 +02:00
Kalle Valo
6e45f8edcd tracing: add ath10k_pktlog.py 2014-11-04 05:34:31 +02:00
Kalle Valo
6502f41f55 tracing: ath10k: add htt tx ppdu stats
Skeleton for parsing htt tx ppdu stats.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
2014-10-09 10:21:04 +03:00
Luis R. Rodriguez
957c4b05fb qca-swiss-army-knife: add qca-wireless-regdb.txt
This is what we are trying to get in synch with on the
public wireless-regdb. Its our goal. Snapshot taken today.

Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-11-20 21:54:56 +01:00
Kalle Valo
604f47bec1 qca-swiss-army-knife: add ath10k trace-cmd plugin
This one's a skeleton as well.

[mcgrof: removed trailing white space from empty lines]
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-09-04 11:01:03 -07:00
Kalle Valo
511deeff3a qca-swiss-army-knife: add ath6kl trace-cmd plugin
Just a skeleton for now.

[mcgrof: removed trailing white space on empty lines]
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-09-04 11:00:28 -07:00
Sujith Manoharan
6d32fea2d2 initvals: Add mix ob/db tx gain table for AR9462 2.0
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-07-15 12:05:35 -07:00
Sujith Manoharan
8acc7b7bc9 initvals: Add support for AR9462 2.1
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-07-15 12:05:35 -07:00
Sujith Manoharan
496ac7d700 initvals: Add rxgain tables for AR9462
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-07-15 12:05:34 -07:00
Sujith Manoharan
43438ab80b initvals: Add ar9462_2p0_5g_xlna_only_rxgain table
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-07-15 12:05:34 -07:00
Sujith Manoharan
65b32571db initvals: Add 5g-XLNA table for AR9462
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-07-15 12:05:34 -07:00
Sujith Manoharan
0c8d850849 initvals: Update inivals for AR9462 2.0
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-07-15 12:05:34 -07:00
Sujith Manoharan
fb0da09651 initvals: Update initivals for AR9565
* Register Modification for xLNA board.
* TX gain table modification for zero calibration.
* AUX chain (LNA2) sensitivity enhancement
* Modify diversity bias default setting in INI.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-05-09 00:48:10 -07:00
Sujith Manoharan
da261b1555 initvals: Update AR9462 initvals
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-03-06 18:04:55 -08:00
Sujith Manoharan
c6ac8ad9aa initvals: Remove unused ini files
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
2013-03-06 18:04:51 -08:00
22 changed files with 13788 additions and 155 deletions

View file

@ -9,21 +9,19 @@ ATHEROS_DEPS += \
ar5416.ini \
ar5416_howl.ini \
ar5416_sowl.ini \
ar9280.ini \
ar9280_merlin2.ini \
ar9285.ini \
ar9285_v1_2.ini \
ar9287.ini \
ar9287_1_1.ini \
ar9271.ini \
ar9300_osprey22.ini \
ar9330_11.ini \
ar9330_12.ini \
ar9340.ini \
ar9485.ini \
ar955x.ini \
ar9580.ini \
ar9300_jupiter20.ini \
ar9300_jupiter21.ini \
ar9300_aphrodite10.ini
endif
@ -39,6 +37,7 @@ ATH9K_HEADERS = \
ar955x-1p0:ar955x_1p0_initvals.h \
ar9580-1p0:ar9580_1p0_initvals.h \
ar9462-2p0:ar9462_2p0_initvals.h \
ar9462-2p1:ar9462_2p1_initvals.h \
ar9565-1p0:ar9565_1p0_initvals.h
ifndef ATHEROS

View file

@ -37,28 +37,28 @@ static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18253ede},
{0x00018c04, 0x000801d8},
{0x00018c08, 0x0003580c},
{0x00018c08, 0x0003780c},
};
static const u32 ar9462_2p0_baseband_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d},
{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a01ae},
{0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x63c640da},
{0x00009824, 0x63c640de, 0x5ac640d0, 0x5ac640d0, 0x63c640da},
{0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x09143e81},
{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
{0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
{0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a2},
{0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8},
{0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x32395d5e},
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e},
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
{0x00009e3c, 0xcf946222, 0xcf946222, 0xcfd5c782, 0xcfd5c282},
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
@ -78,13 +78,13 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
{0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a3a4, 0x00000010, 0x00000010, 0x00000000, 0x00000000},
{0x0000a3a4, 0x00000050, 0x00000050, 0x00000000, 0x00000000},
{0x0000a3a8, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa},
{0x0000a3ac, 0xaaaaaa00, 0xaaaaaa30, 0xaaaaaa00, 0xaaaaaa00},
{0x0000a3ac, 0xaaaaaa00, 0xaa30aa30, 0xaaaaaa00, 0xaaaaaa00},
{0x0000a41c, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce},
{0x0000a420, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce},
{0x0000a424, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce},
@ -363,14 +363,14 @@ static const u32 ar9462_pciephy_clkreq_disable_L1_2p0[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18213ede},
{0x00018c04, 0x000801d8},
{0x00018c08, 0x0003580c},
{0x00018c08, 0x0003780c},
};
static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18212ede},
{0x00018c04, 0x000801d8},
{0x00018c08, 0x0003580c},
{0x00018c08, 0x0003780c},
};
static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
@ -775,7 +775,7 @@ static const u32 ar9462_2p0_baseband_core[][2] = {
{0x00009fc0, 0x803e4788},
{0x00009fc4, 0x0001efb5},
{0x00009fcc, 0x40000014},
{0x00009fd0, 0x01193b93},
{0x00009fd0, 0x0a193b93},
{0x0000a20c, 0x00000000},
{0x0000a220, 0x00000000},
{0x0000a224, 0x00000000},
@ -850,7 +850,7 @@ static const u32 ar9462_2p0_baseband_core[][2] = {
{0x0000a7cc, 0x00000000},
{0x0000a7d0, 0x00000000},
{0x0000a7d4, 0x00000004},
{0x0000a7dc, 0x00000001},
{0x0000a7dc, 0x00000000},
{0x0000a7f0, 0x80000000},
{0x0000a8d0, 0x004b6a8e},
{0x0000a8d4, 0x00000820},
@ -879,6 +879,69 @@ static const u32 ar9462_2p0_radio_postamble[][5] = {
{0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
};
static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x0000d0da, 0x0000d0da, 0x0000d0de, 0x0000d0de},
{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
{0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
{0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
{0x0000a514, 0x18022622, 0x18022622, 0x12000400, 0x12000400},
{0x0000a518, 0x1b022822, 0x1b022822, 0x16000402, 0x16000402},
{0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
{0x0000a520, 0x22022c41, 0x22022c41, 0x1c000603, 0x1c000603},
{0x0000a524, 0x28023042, 0x28023042, 0x21000a02, 0x21000a02},
{0x0000a528, 0x2c023044, 0x2c023044, 0x25000a04, 0x25000a04},
{0x0000a52c, 0x2f023644, 0x2f023644, 0x28000a20, 0x28000a20},
{0x0000a530, 0x34025643, 0x34025643, 0x2c000e20, 0x2c000e20},
{0x0000a534, 0x38025a44, 0x38025a44, 0x30000e22, 0x30000e22},
{0x0000a538, 0x3b025e45, 0x3b025e45, 0x34000e24, 0x34000e24},
{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x38001640, 0x38001640},
{0x0000a540, 0x48025e6c, 0x48025e6c, 0x3c001660, 0x3c001660},
{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3f001861, 0x3f001861},
{0x0000a548, 0x55025eb3, 0x55025eb3, 0x43001a81, 0x43001a81},
{0x0000a54c, 0x58025ef3, 0x58025ef3, 0x47001a83, 0x47001a83},
{0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x4a001c84, 0x4a001c84},
{0x0000a554, 0x62025f56, 0x62025f56, 0x4e001ce3, 0x4e001ce3},
{0x0000a558, 0x66027f56, 0x66027f56, 0x52001ce5, 0x52001ce5},
{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x56001ce9, 0x56001ce9},
{0x0000a560, 0x70049f56, 0x70049f56, 0x5a001ceb, 0x5a001ceb},
{0x0000a564, 0x751ffff6, 0x751ffff6, 0x5c001eec, 0x5c001eec},
{0x0000a568, 0x751ffff6, 0x751ffff6, 0x5e001ef0, 0x5e001ef0},
{0x0000a56c, 0x751ffff6, 0x751ffff6, 0x60001ef4, 0x60001ef4},
{0x0000a570, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6},
{0x0000a574, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6},
{0x0000a578, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6},
{0x0000a57c, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
{0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
{0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
};
static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
@ -886,7 +949,7 @@ static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a410, 0x000050da, 0x000050da, 0x000050de, 0x000050de},
{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
@ -906,20 +969,20 @@ static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
{0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
{0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
{0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83},
{0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84},
{0x0000a548, 0x55025eb3, 0x55025eb3, 0x3e001a81, 0x3e001a81},
{0x0000a54c, 0x58025ef3, 0x58025ef3, 0x42001a83, 0x42001a83},
{0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001a84, 0x44001a84},
{0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
{0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a564, 0x751ffff6, 0x751ffff6, 0x56001eec, 0x56001eec},
{0x0000a568, 0x751ffff6, 0x751ffff6, 0x58001ef0, 0x58001ef0},
{0x0000a56c, 0x751ffff6, 0x751ffff6, 0x5a001ef4, 0x5a001ef4},
{0x0000a570, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
{0x0000a574, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
{0x0000a578, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
{0x0000a57c, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@ -1053,7 +1116,6 @@ static const u32 ar9462_2p0_mac_core[][2] = {
{0x00008044, 0x00000000},
{0x00008048, 0x00000000},
{0x0000804c, 0xffffffff},
{0x00008050, 0xffffffff},
{0x00008054, 0x00000000},
{0x00008058, 0x00000000},
{0x0000805c, 0x000fc78f},
@ -1117,9 +1179,9 @@ static const u32 ar9462_2p0_mac_core[][2] = {
{0x000081f8, 0x00000000},
{0x000081fc, 0x00000000},
{0x00008240, 0x00100000},
{0x00008244, 0x0010f424},
{0x00008244, 0x0010f400},
{0x00008248, 0x00000800},
{0x0000824c, 0x0001e848},
{0x0000824c, 0x0001e800},
{0x00008250, 0x00000000},
{0x00008254, 0x00000000},
{0x00008258, 0x00000000},
@ -1450,4 +1512,284 @@ static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = {
{0x0000b1fc, 0x00000196},
};
static const u32 ar9462_2p0_baseband_postamble_5g_xlna[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
};
static const u32 ar9462_2p0_5g_xlna_only_rxgain[][2] = {
/* Addr allmodes */
{0x0000a000, 0x00010000},
{0x0000a004, 0x00030002},
{0x0000a008, 0x00050004},
{0x0000a00c, 0x00810080},
{0x0000a010, 0x00830082},
{0x0000a014, 0x01810180},
{0x0000a018, 0x01830182},
{0x0000a01c, 0x01850184},
{0x0000a020, 0x01890188},
{0x0000a024, 0x018b018a},
{0x0000a028, 0x018d018c},
{0x0000a02c, 0x03820190},
{0x0000a030, 0x03840383},
{0x0000a034, 0x03880385},
{0x0000a038, 0x038a0389},
{0x0000a03c, 0x038c038b},
{0x0000a040, 0x0390038d},
{0x0000a044, 0x03920391},
{0x0000a048, 0x03940393},
{0x0000a04c, 0x03960395},
{0x0000a050, 0x00000000},
{0x0000a054, 0x00000000},
{0x0000a058, 0x00000000},
{0x0000a05c, 0x00000000},
{0x0000a060, 0x00000000},
{0x0000a064, 0x00000000},
{0x0000a068, 0x00000000},
{0x0000a06c, 0x00000000},
{0x0000a070, 0x00000000},
{0x0000a074, 0x00000000},
{0x0000a078, 0x00000000},
{0x0000a07c, 0x00000000},
{0x0000a080, 0x29292929},
{0x0000a084, 0x29292929},
{0x0000a088, 0x29292929},
{0x0000a08c, 0x29292929},
{0x0000a090, 0x22292929},
{0x0000a094, 0x1d1d2222},
{0x0000a098, 0x0c111117},
{0x0000a09c, 0x00030303},
{0x0000a0a0, 0x00000000},
{0x0000a0a4, 0x00000000},
{0x0000a0a8, 0x00000000},
{0x0000a0ac, 0x00000000},
{0x0000a0b0, 0x00000000},
{0x0000a0b4, 0x00000000},
{0x0000a0b8, 0x00000000},
{0x0000a0bc, 0x00000000},
{0x0000a0c0, 0x001f0000},
{0x0000a0c4, 0x01000101},
{0x0000a0c8, 0x011e011f},
{0x0000a0cc, 0x011c011d},
{0x0000a0d0, 0x02030204},
{0x0000a0d4, 0x02010202},
{0x0000a0d8, 0x021f0200},
{0x0000a0dc, 0x0302021e},
{0x0000a0e0, 0x03000301},
{0x0000a0e4, 0x031e031f},
{0x0000a0e8, 0x0402031d},
{0x0000a0ec, 0x04000401},
{0x0000a0f0, 0x041e041f},
{0x0000a0f4, 0x0502041d},
{0x0000a0f8, 0x05000501},
{0x0000a0fc, 0x051e051f},
{0x0000a100, 0x06010602},
{0x0000a104, 0x061f0600},
{0x0000a108, 0x061d061e},
{0x0000a10c, 0x07020703},
{0x0000a110, 0x07000701},
{0x0000a114, 0x00000000},
{0x0000a118, 0x00000000},
{0x0000a11c, 0x00000000},
{0x0000a120, 0x00000000},
{0x0000a124, 0x00000000},
{0x0000a128, 0x00000000},
{0x0000a12c, 0x00000000},
{0x0000a130, 0x00000000},
{0x0000a134, 0x00000000},
{0x0000a138, 0x00000000},
{0x0000a13c, 0x00000000},
{0x0000a140, 0x001f0000},
{0x0000a144, 0x01000101},
{0x0000a148, 0x011e011f},
{0x0000a14c, 0x011c011d},
{0x0000a150, 0x02030204},
{0x0000a154, 0x02010202},
{0x0000a158, 0x021f0200},
{0x0000a15c, 0x0302021e},
{0x0000a160, 0x03000301},
{0x0000a164, 0x031e031f},
{0x0000a168, 0x0402031d},
{0x0000a16c, 0x04000401},
{0x0000a170, 0x041e041f},
{0x0000a174, 0x0502041d},
{0x0000a178, 0x05000501},
{0x0000a17c, 0x051e051f},
{0x0000a180, 0x06010602},
{0x0000a184, 0x061f0600},
{0x0000a188, 0x061d061e},
{0x0000a18c, 0x07020703},
{0x0000a190, 0x07000701},
{0x0000a194, 0x00000000},
{0x0000a198, 0x00000000},
{0x0000a19c, 0x00000000},
{0x0000a1a0, 0x00000000},
{0x0000a1a4, 0x00000000},
{0x0000a1a8, 0x00000000},
{0x0000a1ac, 0x00000000},
{0x0000a1b0, 0x00000000},
{0x0000a1b4, 0x00000000},
{0x0000a1b8, 0x00000000},
{0x0000a1bc, 0x00000000},
{0x0000a1c0, 0x00000000},
{0x0000a1c4, 0x00000000},
{0x0000a1c8, 0x00000000},
{0x0000a1cc, 0x00000000},
{0x0000a1d0, 0x00000000},
{0x0000a1d4, 0x00000000},
{0x0000a1d8, 0x00000000},
{0x0000a1dc, 0x00000000},
{0x0000a1e0, 0x00000000},
{0x0000a1e4, 0x00000000},
{0x0000a1e8, 0x00000000},
{0x0000a1ec, 0x00000000},
{0x0000a1f0, 0x00000396},
{0x0000a1f4, 0x00000396},
{0x0000a1f8, 0x00000396},
{0x0000a1fc, 0x00000196},
{0x0000b000, 0x00010000},
{0x0000b004, 0x00030002},
{0x0000b008, 0x00050004},
{0x0000b00c, 0x00810080},
{0x0000b010, 0x00830082},
{0x0000b014, 0x01810180},
{0x0000b018, 0x01830182},
{0x0000b01c, 0x01850184},
{0x0000b020, 0x02810280},
{0x0000b024, 0x02830282},
{0x0000b028, 0x02850284},
{0x0000b02c, 0x02890288},
{0x0000b030, 0x028b028a},
{0x0000b034, 0x0388028c},
{0x0000b038, 0x038a0389},
{0x0000b03c, 0x038c038b},
{0x0000b040, 0x0390038d},
{0x0000b044, 0x03920391},
{0x0000b048, 0x03940393},
{0x0000b04c, 0x03960395},
{0x0000b050, 0x00000000},
{0x0000b054, 0x00000000},
{0x0000b058, 0x00000000},
{0x0000b05c, 0x00000000},
{0x0000b060, 0x00000000},
{0x0000b064, 0x00000000},
{0x0000b068, 0x00000000},
{0x0000b06c, 0x00000000},
{0x0000b070, 0x00000000},
{0x0000b074, 0x00000000},
{0x0000b078, 0x00000000},
{0x0000b07c, 0x00000000},
{0x0000b080, 0x2a2d2f32},
{0x0000b084, 0x21232328},
{0x0000b088, 0x19191c1e},
{0x0000b08c, 0x12141417},
{0x0000b090, 0x07070e0e},
{0x0000b094, 0x03030305},
{0x0000b098, 0x00000003},
{0x0000b09c, 0x00000000},
{0x0000b0a0, 0x00000000},
{0x0000b0a4, 0x00000000},
{0x0000b0a8, 0x00000000},
{0x0000b0ac, 0x00000000},
{0x0000b0b0, 0x00000000},
{0x0000b0b4, 0x00000000},
{0x0000b0b8, 0x00000000},
{0x0000b0bc, 0x00000000},
{0x0000b0c0, 0x003f0020},
{0x0000b0c4, 0x00400041},
{0x0000b0c8, 0x0140005f},
{0x0000b0cc, 0x0160015f},
{0x0000b0d0, 0x017e017f},
{0x0000b0d4, 0x02410242},
{0x0000b0d8, 0x025f0240},
{0x0000b0dc, 0x027f0260},
{0x0000b0e0, 0x0341027e},
{0x0000b0e4, 0x035f0340},
{0x0000b0e8, 0x037f0360},
{0x0000b0ec, 0x04400441},
{0x0000b0f0, 0x0460045f},
{0x0000b0f4, 0x0541047f},
{0x0000b0f8, 0x055f0540},
{0x0000b0fc, 0x057f0560},
{0x0000b100, 0x06400641},
{0x0000b104, 0x0660065f},
{0x0000b108, 0x067e067f},
{0x0000b10c, 0x07410742},
{0x0000b110, 0x075f0740},
{0x0000b114, 0x077f0760},
{0x0000b118, 0x07800781},
{0x0000b11c, 0x07a0079f},
{0x0000b120, 0x07c107bf},
{0x0000b124, 0x000007c0},
{0x0000b128, 0x00000000},
{0x0000b12c, 0x00000000},
{0x0000b130, 0x00000000},
{0x0000b134, 0x00000000},
{0x0000b138, 0x00000000},
{0x0000b13c, 0x00000000},
{0x0000b140, 0x003f0020},
{0x0000b144, 0x00400041},
{0x0000b148, 0x0140005f},
{0x0000b14c, 0x0160015f},
{0x0000b150, 0x017e017f},
{0x0000b154, 0x02410242},
{0x0000b158, 0x025f0240},
{0x0000b15c, 0x027f0260},
{0x0000b160, 0x0341027e},
{0x0000b164, 0x035f0340},
{0x0000b168, 0x037f0360},
{0x0000b16c, 0x04400441},
{0x0000b170, 0x0460045f},
{0x0000b174, 0x0541047f},
{0x0000b178, 0x055f0540},
{0x0000b17c, 0x057f0560},
{0x0000b180, 0x06400641},
{0x0000b184, 0x0660065f},
{0x0000b188, 0x067e067f},
{0x0000b18c, 0x07410742},
{0x0000b190, 0x075f0740},
{0x0000b194, 0x077f0760},
{0x0000b198, 0x07800781},
{0x0000b19c, 0x07a0079f},
{0x0000b1a0, 0x07c107bf},
{0x0000b1a4, 0x000007c0},
{0x0000b1a8, 0x00000000},
{0x0000b1ac, 0x00000000},
{0x0000b1b0, 0x00000000},
{0x0000b1b4, 0x00000000},
{0x0000b1b8, 0x00000000},
{0x0000b1bc, 0x00000000},
{0x0000b1c0, 0x00000000},
{0x0000b1c4, 0x00000000},
{0x0000b1c8, 0x00000000},
{0x0000b1cc, 0x00000000},
{0x0000b1d0, 0x00000000},
{0x0000b1d4, 0x00000000},
{0x0000b1d8, 0x00000000},
{0x0000b1dc, 0x00000000},
{0x0000b1e0, 0x00000000},
{0x0000b1e4, 0x00000000},
{0x0000b1e8, 0x00000000},
{0x0000b1ec, 0x00000000},
{0x0000b1f0, 0x00000396},
{0x0000b1f4, 0x00000396},
{0x0000b1f8, 0x00000396},
{0x0000b1fc, 0x00000196},
};
static const u32 ar9462_2p0_baseband_core_mix_rxgain[][2] = {
/* Addr allmodes */
{0x00009fd0, 0x0a2d6b93},
};
static const u32 ar9462_2p0_baseband_postamble_mix_rxgain[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae},
{0x00009824, 0x63c640de, 0x5ac640d0, 0x63c640da, 0x63c640da},
{0x00009828, 0x0796be89, 0x0696b081, 0x0916be81, 0x0916be81},
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000d8, 0x6c4000d8},
{0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec86d2e, 0x7ec86d2e},
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32395c5e},
};
#endif /* INITVALS_9462_2P0_H */

File diff suppressed because it is too large Load diff

View file

@ -233,9 +233,9 @@ static const u32 ar9565_1p0_baseband_core[][2] = {
{0x00009d10, 0x01834061},
{0x00009d14, 0x00c00400},
{0x00009d18, 0x00000000},
{0x00009e08, 0x0078230c},
{0x00009e24, 0x990bb515},
{0x00009e28, 0x126f0000},
{0x00009e08, 0x0038230c},
{0x00009e24, 0x9907b515},
{0x00009e28, 0x126f0600},
{0x00009e30, 0x06336f77},
{0x00009e34, 0x6af6532f},
{0x00009e38, 0x0cc80c00},
@ -337,7 +337,7 @@ static const u32 ar9565_1p0_baseband_core[][2] = {
static const u32 ar9565_1p0_baseband_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a800d},
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8009},
{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a01ae},
{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x63c640da},
{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x09143c81},
@ -345,9 +345,9 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = {
{0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
{0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
{0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8},
{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
{0x00009e04, 0x00802020, 0x00802020, 0x00142020, 0x00142020},
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
@ -450,6 +450,8 @@ static const u32 ar9565_1p0_soc_postamble[][5] = {
static const u32 ar9565_1p0_Common_rx_gain_table[][2] = {
/* Addr allmodes */
{0x00004050, 0x00300300},
{0x0000406c, 0x00100000},
{0x0000a000, 0x00010000},
{0x0000a004, 0x00030002},
{0x0000a008, 0x00050004},
@ -498,27 +500,27 @@ static const u32 ar9565_1p0_Common_rx_gain_table[][2] = {
{0x0000a0b4, 0x00000000},
{0x0000a0b8, 0x00000000},
{0x0000a0bc, 0x00000000},
{0x0000a0c0, 0x001f0000},
{0x0000a0c4, 0x01000101},
{0x0000a0c8, 0x011e011f},
{0x0000a0cc, 0x011c011d},
{0x0000a0d0, 0x02030204},
{0x0000a0d4, 0x02010202},
{0x0000a0d8, 0x021f0200},
{0x0000a0dc, 0x0302021e},
{0x0000a0e0, 0x03000301},
{0x0000a0e4, 0x031e031f},
{0x0000a0e8, 0x0402031d},
{0x0000a0ec, 0x04000401},
{0x0000a0f0, 0x041e041f},
{0x0000a0f4, 0x0502041d},
{0x0000a0f8, 0x05000501},
{0x0000a0fc, 0x051e051f},
{0x0000a100, 0x06010602},
{0x0000a104, 0x061f0600},
{0x0000a108, 0x061d061e},
{0x0000a10c, 0x07020703},
{0x0000a110, 0x07000701},
{0x0000a0c0, 0x00bf00a0},
{0x0000a0c4, 0x11a011a1},
{0x0000a0c8, 0x11be11bf},
{0x0000a0cc, 0x11bc11bd},
{0x0000a0d0, 0x22632264},
{0x0000a0d4, 0x22612262},
{0x0000a0d8, 0x227f2260},
{0x0000a0dc, 0x4322227e},
{0x0000a0e0, 0x43204321},
{0x0000a0e4, 0x433e433f},
{0x0000a0e8, 0x4462433d},
{0x0000a0ec, 0x44604461},
{0x0000a0f0, 0x447e447f},
{0x0000a0f4, 0x5582447d},
{0x0000a0f8, 0x55805581},
{0x0000a0fc, 0x559e559f},
{0x0000a100, 0x66816682},
{0x0000a104, 0x669f6680},
{0x0000a108, 0x669d669e},
{0x0000a10c, 0x77627763},
{0x0000a110, 0x77607761},
{0x0000a114, 0x00000000},
{0x0000a118, 0x00000000},
{0x0000a11c, 0x00000000},
@ -530,27 +532,27 @@ static const u32 ar9565_1p0_Common_rx_gain_table[][2] = {
{0x0000a134, 0x00000000},
{0x0000a138, 0x00000000},
{0x0000a13c, 0x00000000},
{0x0000a140, 0x001f0000},
{0x0000a144, 0x01000101},
{0x0000a148, 0x011e011f},
{0x0000a14c, 0x011c011d},
{0x0000a150, 0x02030204},
{0x0000a154, 0x02010202},
{0x0000a158, 0x021f0200},
{0x0000a15c, 0x0302021e},
{0x0000a160, 0x03000301},
{0x0000a164, 0x031e031f},
{0x0000a168, 0x0402031d},
{0x0000a16c, 0x04000401},
{0x0000a170, 0x041e041f},
{0x0000a174, 0x0502041d},
{0x0000a178, 0x05000501},
{0x0000a17c, 0x051e051f},
{0x0000a180, 0x06010602},
{0x0000a184, 0x061f0600},
{0x0000a188, 0x061d061e},
{0x0000a18c, 0x07020703},
{0x0000a190, 0x07000701},
{0x0000a140, 0x00bf00a0},
{0x0000a144, 0x11a011a1},
{0x0000a148, 0x11be11bf},
{0x0000a14c, 0x11bc11bd},
{0x0000a150, 0x22632264},
{0x0000a154, 0x22612262},
{0x0000a158, 0x227f2260},
{0x0000a15c, 0x4322227e},
{0x0000a160, 0x43204321},
{0x0000a164, 0x433e433f},
{0x0000a168, 0x4462433d},
{0x0000a16c, 0x44604461},
{0x0000a170, 0x447e447f},
{0x0000a174, 0x5582447d},
{0x0000a178, 0x55805581},
{0x0000a17c, 0x559e559f},
{0x0000a180, 0x66816682},
{0x0000a184, 0x669f6680},
{0x0000a188, 0x669d669e},
{0x0000a18c, 0x77e677e7},
{0x0000a190, 0x77e477e5},
{0x0000a194, 0x00000000},
{0x0000a198, 0x00000000},
{0x0000a19c, 0x00000000},
@ -770,7 +772,7 @@ static const u32 ar9565_1p0_Modes_lowest_ob_db_tx_gain_table[][5] = {
static const u32 ar9565_1p0_pciephy_clkreq_disable_L1[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18213ede},
{0x00018c00, 0x18212ede},
{0x00018c04, 0x000801d8},
{0x00018c08, 0x0003780c},
};
@ -889,8 +891,8 @@ static const u32 ar9565_1p0_common_wo_xlna_rx_gain_table[][2] = {
{0x0000a180, 0x66816682},
{0x0000a184, 0x669f6680},
{0x0000a188, 0x669d669e},
{0x0000a18c, 0x77627763},
{0x0000a190, 0x77607761},
{0x0000a18c, 0x77e677e7},
{0x0000a190, 0x77e477e5},
{0x0000a194, 0x00000000},
{0x0000a198, 0x00000000},
{0x0000a19c, 0x00000000},
@ -1114,7 +1116,7 @@ static const u32 ar9565_1p0_modes_high_ob_db_tx_gain_table[][5] = {
{0x0000a2e0, 0xffecec00, 0xffecec00, 0xfd339c84, 0xfd339c84},
{0x0000a2e4, 0xfc0f0000, 0xfc0f0000, 0xfec3e000, 0xfec3e000},
{0x0000a2e8, 0xfc100000, 0xfc100000, 0xfffc0000, 0xfffc0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050df, 0x000050df},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
{0x0000a508, 0x0b022220, 0x0b022220, 0x08000004, 0x08000004},
@ -1140,13 +1142,13 @@ static const u32 ar9565_1p0_modes_high_ob_db_tx_gain_table[][5] = {
{0x0000a558, 0x69027f56, 0x69027f56, 0x53001ce5, 0x53001ce5},
{0x0000a55c, 0x6d029f56, 0x6d029f56, 0x57001ce9, 0x57001ce9},
{0x0000a560, 0x73049f56, 0x73049f56, 0x5b001ceb, 0x5b001ceb},
{0x0000a564, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a568, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a56c, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a570, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a574, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a578, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a57c, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a564, 0x7804ff56, 0x7804ff56, 0x60001cf0, 0x60001cf0},
{0x0000a568, 0x7804ff56, 0x7804ff56, 0x61001cf1, 0x61001cf1},
{0x0000a56c, 0x7804ff56, 0x7804ff56, 0x62001cf2, 0x62001cf2},
{0x0000a570, 0x7804ff56, 0x7804ff56, 0x63001cf3, 0x63001cf3},
{0x0000a574, 0x7804ff56, 0x7804ff56, 0x64001cf4, 0x64001cf4},
{0x0000a578, 0x7804ff56, 0x7804ff56, 0x66001ff6, 0x66001ff6},
{0x0000a57c, 0x7804ff56, 0x7804ff56, 0x66001ff6, 0x66001ff6},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@ -1174,7 +1176,7 @@ static const u32 ar9565_1p0_modes_high_power_tx_gain_table[][5] = {
{0x0000a2e0, 0xffecec00, 0xffecec00, 0xfd339c84, 0xfd339c84},
{0x0000a2e4, 0xfc0f0000, 0xfc0f0000, 0xfec3e000, 0xfec3e000},
{0x0000a2e8, 0xfc100000, 0xfc100000, 0xfffc0000, 0xfffc0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050df, 0x000050df},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
@ -1200,13 +1202,13 @@ static const u32 ar9565_1p0_modes_high_power_tx_gain_table[][5] = {
{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
{0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a564, 0x7504ff56, 0x7504ff56, 0x59001cf0, 0x59001cf0},
{0x0000a568, 0x7504ff56, 0x7504ff56, 0x5a001cf1, 0x5a001cf1},
{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x5b001cf2, 0x5b001cf2},
{0x0000a570, 0x7504ff56, 0x7504ff56, 0x5c001cf3, 0x5c001cf3},
{0x0000a574, 0x7504ff56, 0x7504ff56, 0x5d001cf4, 0x5d001cf4},
{0x0000a578, 0x7504ff56, 0x7504ff56, 0x5f001ff6, 0x5f001ff6},
{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x5f001ff6, 0x5f001ff6},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},

View file

@ -138,24 +138,50 @@ ca6088034f339ea8f106f7f034d34baafec0c0ca ar9340Modes_high_ob_db_tx_gain_t
481b3066bd6b4dfa425027157f7c6252b535ebe4 ar9340Common_wo_xlna_rx_gain_table_1p0
1b9f617ab8c10ec0760e81fe61d469692f2acc29 ar9340_1p0_soc_preamble
d9efd1c575ac43d60c310d717c59617a5323c111 ar9462_modes_fast_clock_2p0
8bf1688079add33889085f3d35a5fab61c33487f ar9462_pciephy_clkreq_enable_L1_2p0
8dacf543535b605143b40aef74f7d46af064cb43 ar9462_2p0_baseband_postamble
222ed8213d3ffb0d12cf4c7019bdfd874e45c7d7 ar9462_pciephy_clkreq_enable_L1_2p0
d7a2102c22264c288fa3d9de27e5ae84b8f3812e ar9462_2p0_baseband_postamble
d0f7aff1a1ab7e6f6bbda0da067714459341ce5f ar9462_common_rx_gain_table_2p0
bc232a96b4c1530bebe654420652a9f080a09db8 ar9462_pciephy_clkreq_disable_L1_2p0
f4c2241d40995e09f8736ed2ef5eaa5d6f051aa5 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0
2fbe90336971cd66f0264c0cc57605c2de069d5f ar9462_pciephy_clkreq_disable_L1_2p0
a3173672141a2ac797e660228d41a609f9ab2c4c ar9462_pciephy_pll_on_clkreq_disable_L1_2p0
057d1ee3d10321f1cc4d6c19cf1927e2ae56af28 ar9462_2p0_radio_postamble_sys2ant
481b3066bd6b4dfa425027157f7c6252b535ebe4 ar9462_common_wo_xlna_rx_gain_table_2p0
dfaefa89122b4b769bfcf93b4bd9569f2b0ee961 ar9462_2p0_baseband_core_txfir_coeff_japan_2484
a36b90fcdeeb4071fd090537f008f8091d885581 ar9462_modes_low_ob_db_tx_gain_table_2p0
7c0a54aaf0f77f5bf048126e43feea746732d43f ar9462_2p0_soc_postamble
e87864956a7209224880cff035b4441b0ab3fbcc ar9462_2p0_baseband_core
53d41e2eb8eadab02e1b615f4f596a55cf2a8905 ar9462_2p0_baseband_core
b50d2fe654b069110bdbe06e5065f2aa9b117e3e ar9462_2p0_radio_postamble
5a98e71e601539bf31af7b9d18b210ab70f99dae ar9462_modes_high_ob_db_tx_gain_table_2p0
f7a7bdff0af20658239e4b491f470a8c9517c0ae ar9462_modes_mix_ob_db_tx_gain_table_2p0
068b0f30229b9cbf385a49303d29b8fb979f25b3 ar9462_modes_high_ob_db_tx_gain_table_2p0
fd98d0361e085b102131c2dc07c601e0a7ccdd13 ar9462_2p0_radio_core
3e60b14761abfa24d758727954d1d5cc398abf7f ar9462_2p0_soc_preamble
fc8623151293cc7739d0fb8e2873256749c74930 ar9462_2p0_mac_core
2e6ddfe3c7e291ca6bebb5791d8a73c492db0399 ar9462_2p0_mac_core
c8dc777b012068116cd5282aade8eb460f397d20 ar9462_2p0_mac_postamble
72675fd0f308e6f31502e283119e12469d262f40 ar9462_common_mixed_rx_gain_table_2p0
185f0537e40b74dcc4db33c7e111c1bfe79f3104 ar9462_2p0_baseband_postamble_5g_xlna
72675fd0f308e6f31502e283119e12469d262f40 ar9462_2p0_5g_xlna_only_rxgain
8f24703571c460bced3d0fea95b5cfeac34a724d ar9462_2p0_baseband_core_mix_rxgain
cb83a8c304aae0b6fc937e61d145253a8f470d24 ar9462_2p0_baseband_postamble_mix_rxgain
e6f8d81842a61171ac17eff584e93b4e95b5dbbf ar9462_2p1_mac_core
c8dc777b012068116cd5282aade8eb460f397d20 ar9462_2p1_mac_postamble
53d41e2eb8eadab02e1b615f4f596a55cf2a8905 ar9462_2p1_baseband_core
d7a2102c22264c288fa3d9de27e5ae84b8f3812e ar9462_2p1_baseband_postamble
fd98d0361e085b102131c2dc07c601e0a7ccdd13 ar9462_2p1_radio_core
b50d2fe654b069110bdbe06e5065f2aa9b117e3e ar9462_2p1_radio_postamble
3e60b14761abfa24d758727954d1d5cc398abf7f ar9462_2p1_soc_preamble
7c0a54aaf0f77f5bf048126e43feea746732d43f ar9462_2p1_soc_postamble
057d1ee3d10321f1cc4d6c19cf1927e2ae56af28 ar9462_2p1_radio_postamble_sys2ant
d0f7aff1a1ab7e6f6bbda0da067714459341ce5f ar9462_2p1_common_rx_gain
72675fd0f308e6f31502e283119e12469d262f40 ar9462_2p1_common_mixed_rx_gain
8f24703571c460bced3d0fea95b5cfeac34a724d ar9462_2p1_baseband_core_mix_rxgain
cb83a8c304aae0b6fc937e61d145253a8f470d24 ar9462_2p1_baseband_postamble_mix_rxgain
185f0537e40b74dcc4db33c7e111c1bfe79f3104 ar9462_2p1_baseband_postamble_5g_xlna
481b3066bd6b4dfa425027157f7c6252b535ebe4 ar9462_2p1_common_wo_xlna_rx_gain
72675fd0f308e6f31502e283119e12469d262f40 ar9462_2p1_common_5g_xlna_only_rx_gain
a36b90fcdeeb4071fd090537f008f8091d885581 ar9462_2p1_modes_low_ob_db_tx_gain
068b0f30229b9cbf385a49303d29b8fb979f25b3 ar9462_2p1_modes_high_ob_db_tx_gain
f7a7bdff0af20658239e4b491f470a8c9517c0ae ar9462_2p1_modes_mix_ob_db_tx_gain
d9efd1c575ac43d60c310d717c59617a5323c111 ar9462_2p1_modes_fast_clock
dfaefa89122b4b769bfcf93b4bd9569f2b0ee961 ar9462_2p1_baseband_core_txfir_coeff_japan_2484
c8dc777b012068116cd5282aade8eb460f397d20 ar9485_1_1_mac_postamble
5d20e4848b97566ad55e0e95458463d622ee5480 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1
d9a90632a00a7b417154173b947dfffdeab23e51 ar9485Common_wo_xlna_rx_gain_1_1
@ -194,20 +220,20 @@ b836a622916e66da6a23c9cd34a7d933571ff6db ar955x_1p0_modes_no_xpa_tx_gain_
d9efd1c575ac43d60c310d717c59617a5323c111 ar955x_1p0_modes_fast_clock
839b2486a70775db100fca6421860d4922fbf945 ar9565_1p0_mac_core
c8dc777b012068116cd5282aade8eb460f397d20 ar9565_1p0_mac_postamble
be2a958615907b5f7766336b124d79cb3dbb3c1f ar9565_1p0_baseband_core
7ae44b5234dc536c5fe3bd484ecbf4bd4f8f8ee1 ar9565_1p0_baseband_postamble
26297fd915614c1f9ad22fb611335a2ac715a2d9 ar9565_1p0_baseband_core
e719a3c597fa3511cfb436aeb4cfdda3b5949685 ar9565_1p0_baseband_postamble
98708e6c8cde013777cd5c5c9ded6dfe038b652f ar9565_1p0_radio_core
bc722e44e8c7039983b485fc099275c6629974cf ar9565_1p0_radio_postamble
524fae156c2942a28c62603dac8f9ee99ff0e25a ar9565_1p0_soc_preamble
b045882e6e5b3f54d9eed19022abe6a44bc04e73 ar9565_1p0_soc_postamble
bc0a956de3b035894bf68722ca4c8a4365fe0f4b ar9565_1p0_Common_rx_gain_table
6af86113836112173aab7266f22acee984d956a9 ar9565_1p0_Common_rx_gain_table
4bf703cdebf0bfb9ad867cb53b79d6c3957b6f91 ar9565_1p0_Modes_lowest_ob_db_tx_gain_table
2fbe90336971cd66f0264c0cc57605c2de069d5f ar9565_1p0_pciephy_clkreq_disable_L1
a3173672141a2ac797e660228d41a609f9ab2c4c ar9565_1p0_pciephy_clkreq_disable_L1
6db24dff7f419466d4734d59063314b9e52d4640 ar9565_1p0_modes_fast_clock
d297fe8586260e902a2b629323e4802fe207f2b7 ar9565_1p0_common_wo_xlna_rx_gain_table
9cbace0a26242ed035a0c2fbae7cec34267c7258 ar9565_1p0_common_wo_xlna_rx_gain_table
4bf703cdebf0bfb9ad867cb53b79d6c3957b6f91 ar9565_1p0_modes_low_ob_db_tx_gain_table
7e7f55da5f2572348ddf79e41e9ab9647d94caff ar9565_1p0_modes_high_ob_db_tx_gain_table
a67925a1d3f3263537a4a0d6096f3f8994190f14 ar9565_1p0_modes_high_power_tx_gain_table
e1be4dc91b540109b236b6b4002a9108ad3a01de ar9565_1p0_modes_high_ob_db_tx_gain_table
19ed468cdcc0c0be512a64d55f40c609e6d75720 ar9565_1p0_modes_high_power_tx_gain_table
87e0ecae5df96673e22bc448b17d813510964de8 ar9580_1p0_modes_fast_clock
6b0fb5b3698c99f42a885c8e982ae436363f1865 ar9580_1p0_radio_postamble
5b81bf27a30c826cfde3e8f6746473e949cb41ef ar9580_1p0_baseband_core

View file

@ -65,6 +65,7 @@ struct initval_family {
#include <ar955x_1p0_initvals.h>
#include <ar9580_1p0_initvals.h>
#include <ar9462_2p0_initvals.h>
#include <ar9462_2p1_initvals.h>
#include <ar9565_1p0_initvals.h>
#else
@ -112,9 +113,6 @@ struct initval_family {
#include "ar5416_sowl.ini"
#include "ar9280.ini"
#define ar9280Modes_merlin2 ar9280Modes_9280_2
#define ar9280Common_merlin2 ar9280Common_9280_2
#define ar9280Modes_fast_clock_merlin2 ar9280Modes_fast_clock_9280_2
@ -148,10 +146,6 @@ struct initval_family {
#include "ar9285_v1_2.ini"
#define ar9287PciePhy_AWOW_kiwi1_0 ar9287PciePhy_AWOW_9287_1_0
#include "ar9287.ini"
#define ar9287Modes_kiwi1_1 ar9287Modes_9287_1_1
#define ar9287Common_kiwi1_1 ar9287Common_9287_1_1
#define ar9287Common_normal_cck_fir_coeff_kiwi1_1 ar9287Common_normal_cck_fir_coeff_9287_1_1
@ -318,15 +312,44 @@ struct initval_family {
#define ar9300_jupiter_2p0_soc_postamble ar9462_2p0_soc_postamble
#define ar9300_jupiter_2p0_baseband_core ar9462_2p0_baseband_core
#define ar9300_jupiter_2p0_radio_postamble ar9462_2p0_radio_postamble
#define ar9300Modes_mix_ob_db_tx_gain_table_jupiter_2p0 ar9462_modes_mix_ob_db_tx_gain_table_2p0
#define ar9300Modes_high_ob_db_tx_gain_table_jupiter_2p0 ar9462_modes_high_ob_db_tx_gain_table_2p0
#define ar9300_jupiter_2p0_radio_core ar9462_2p0_radio_core
#define ar9300_jupiter_2p0_soc_preamble ar9462_2p0_soc_preamble
#define ar9300_jupiter_2p0_mac_core ar9462_2p0_mac_core
#define ar9300_jupiter_2p0_mac_postamble ar9462_2p0_mac_postamble
#define ar9300Common_mixed_rx_gain_table_jupiter_2p0 ar9462_common_mixed_rx_gain_table_2p0
#define ar9300_jupiter_2p0_baseband_postamble_5g_xlna ar9462_2p0_baseband_postamble_5g_xlna
#define ar9300Common_5g_xlna_only_rx_gain_table_jupiter_2p0 ar9462_2p0_5g_xlna_only_rxgain
#define ar9300_jupiter_2p0_baseband_core_mix_rxgain ar9462_2p0_baseband_core_mix_rxgain
#define ar9300_jupiter_2p0_baseband_postamble_mix_rxgain ar9462_2p0_baseband_postamble_mix_rxgain
#include "ar9300_jupiter20.ini"
#define ar9300_jupiter_2p1_mac_core ar9462_2p1_mac_core
#define ar9300_jupiter_2p1_mac_postamble ar9462_2p1_mac_postamble
#define ar9300_jupiter_2p1_baseband_core ar9462_2p1_baseband_core
#define ar9300_jupiter_2p1_baseband_postamble ar9462_2p1_baseband_postamble
#define ar9300_jupiter_2p1_radio_core ar9462_2p1_radio_core
#define ar9300_jupiter_2p1_radio_postamble ar9462_2p1_radio_postamble
#define ar9300_jupiter_2p1_soc_preamble ar9462_2p1_soc_preamble
#define ar9300_jupiter_2p1_soc_postamble ar9462_2p1_soc_postamble
#define ar9300_jupiter_2p1_radio_postamble_sys2ant ar9462_2p1_radio_postamble_sys2ant
#define ar9300Common_rx_gain_table_jupiter_2p1 ar9462_2p1_common_rx_gain
#define ar9300Common_mixed_rx_gain_table_jupiter_2p1 ar9462_2p1_common_mixed_rx_gain
#define ar9300_jupiter_2p1_baseband_core_mix_rxgain ar9462_2p1_baseband_core_mix_rxgain
#define ar9300_jupiter_2p1_baseband_postamble_mix_rxgain ar9462_2p1_baseband_postamble_mix_rxgain
#define ar9300_jupiter_2p1_baseband_postamble_5g_xlna ar9462_2p1_baseband_postamble_5g_xlna
#define ar9300Common_wo_xlna_rx_gain_table_jupiter_2p1 ar9462_2p1_common_wo_xlna_rx_gain
#define ar9300Common_5g_xlna_only_rx_gain_table_jupiter_2p1 ar9462_2p1_common_5g_xlna_only_rx_gain
#define ar9300Modes_low_ob_db_tx_gain_table_jupiter_2p1 ar9462_2p1_modes_low_ob_db_tx_gain
#define ar9300Modes_high_ob_db_tx_gain_table_jupiter_2p1 ar9462_2p1_modes_high_ob_db_tx_gain
#define ar9300Modes_mix_ob_db_tx_gain_table_jupiter_2p1 ar9462_2p1_modes_mix_ob_db_tx_gain
#define ar9300Modes_fast_clock_jupiter_2p1 ar9462_2p1_modes_fast_clock
#define ar9300_jupiter_2p1_baseband_core_txfir_coeff_japan_2484 ar9462_2p1_baseband_core_txfir_coeff_japan_2484
#include "ar9300_jupiter21.ini"
#define ar9340_wasp_1p0_radio_postamble ar9340_1p0_radio_postamble
#define ar9340Modes_lowest_ob_db_tx_gain_table_wasp_1p0 ar9340Modes_lowest_ob_db_tx_gain_table_1p0
#define ar9340Modes_fast_clock_wasp_1p0 ar9340Modes_fast_clock_1p0
@ -903,12 +926,42 @@ static void ar9462_2p0_hw_print_initvals(bool check)
INI_PRINT(ar9462_2p0_soc_postamble);
INI_PRINT(ar9462_2p0_baseband_core);
INI_PRINT(ar9462_2p0_radio_postamble);
INI_PRINT(ar9462_modes_mix_ob_db_tx_gain_table_2p0);
INI_PRINT(ar9462_modes_high_ob_db_tx_gain_table_2p0);
INI_PRINT(ar9462_2p0_radio_core);
INI_PRINT(ar9462_2p0_soc_preamble);
INI_PRINT(ar9462_2p0_mac_core);
INI_PRINT(ar9462_2p0_mac_postamble);
INI_PRINT(ar9462_common_mixed_rx_gain_table_2p0);
INI_PRINT(ar9462_2p0_baseband_postamble_5g_xlna);
INI_PRINT(ar9462_2p0_5g_xlna_only_rxgain);
INI_PRINT(ar9462_2p0_baseband_core_mix_rxgain);
INI_PRINT(ar9462_2p0_baseband_postamble_mix_rxgain);
}
static void ar9462_2p1_hw_print_initvals(bool check)
{
INI_PRINT(ar9462_2p1_mac_core);
INI_PRINT(ar9462_2p1_mac_postamble);
INI_PRINT(ar9462_2p1_baseband_core);
INI_PRINT(ar9462_2p1_baseband_postamble);
INI_PRINT(ar9462_2p1_radio_core);
INI_PRINT(ar9462_2p1_radio_postamble);
INI_PRINT(ar9462_2p1_soc_preamble);
INI_PRINT(ar9462_2p1_soc_postamble);
INI_PRINT(ar9462_2p1_radio_postamble_sys2ant);
INI_PRINT(ar9462_2p1_common_rx_gain);
INI_PRINT(ar9462_2p1_common_mixed_rx_gain);
INI_PRINT(ar9462_2p1_baseband_core_mix_rxgain);
INI_PRINT(ar9462_2p1_baseband_postamble_mix_rxgain);
INI_PRINT(ar9462_2p1_baseband_postamble_5g_xlna);
INI_PRINT(ar9462_2p1_common_wo_xlna_rx_gain);
INI_PRINT(ar9462_2p1_common_5g_xlna_only_rx_gain);
INI_PRINT(ar9462_2p1_modes_low_ob_db_tx_gain);
INI_PRINT(ar9462_2p1_modes_high_ob_db_tx_gain);
INI_PRINT(ar9462_2p1_modes_mix_ob_db_tx_gain);
INI_PRINT(ar9462_2p1_modes_fast_clock);
INI_PRINT(ar9462_2p1_baseband_core_txfir_coeff_japan_2484);
}
static void ar9565_1p0_hw_print_initvals(bool check)
@ -947,6 +1000,7 @@ struct initval_family families[] = {
FAM("ar9330-1p2", "9330_1P2", NULL , ar9330_1p2_hw_print_initvals),
FAM("ar9340" , "9340" , NULL , ar9340_hw_print_initvals),
FAM("ar9462-2p0", "9462_2P0", "AR9462 2.0", ar9462_2p0_hw_print_initvals),
FAM("ar9462-2p1", "9462_2P1", "AR9462 2.1", ar9462_2p1_hw_print_initvals),
FAM("ar9485" , "9485" , "AR9485 1.1", ar9485_hw_print_initvals),
FAM("ar955x-1p0", "955X_1P0", "AR955X 1.0", ar955x_1p0_hw_print_initvals),
FAM("ar9565-1p0", "9565_1P0", "AR9565 1.0", ar9565_1p0_hw_print_initvals),

View file

@ -0,0 +1,734 @@
#!/usr/bin/python3
#
# Copyright (c) 2015 Qualcomm Atheros, Inc.
# Copyright (c) 2018, The Linux Foundation. All rights reserved.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
import struct
import ctypes
import os.path
import argparse
import json
import binascii
import hashlib
import tempfile
import subprocess
import logging
import sys
import shutil
import mailbox
MAX_BUF_LEN = 2000000
# the signature length also includes null byte and padding
ATH10K_BOARD_SIGNATURE = b"QCA-ATH10K-BOARD"
ATH10K_BOARD_SIGNATURE_LEN = 20
PADDING_MAGIC = 0x6d
DEFAULT_BD_API = 2
DEFAULT_BOARD_FILE = 'board-%d.bin' % DEFAULT_BD_API
DEFAULT_JSON_FILE = 'board-%d.json' % DEFAULT_BD_API
TYPE_LENGTH_SIZE = 8
BIN_SUFFIX = '.bin'
ATH10K_FIRMWARE_URL = 'https://git.codelinaro.org/clo/ath-firmware/ath10k-firmware/-/commit'
ATH10K_BD_IE_BOARD = 0
ATH10K_BD_IE_BOARD_EXT = 1
ATH10K_BD_IE_BOARD_NAME = 0
ATH10K_BD_IE_BOARD_DATA = 1
ATH10K_BD_IE_BOARD_EXT_NAME = 0
ATH10K_BD_IE_BOARD_EXT_DATA = 1
def padding_needed(len):
if len % 4 != 0:
return 4 - len % 4
return 0
def add_ie(buf, offset, id, value):
length = len(value)
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, PADDING_MAGIC)
fmt = '<2i%ds%ds' % (len(value), padding_len)
if not isinstance(value, bytes):
value = value.encode()
struct.pack_into(fmt, buf, offset, id, len(value), value, padding.raw)
offset = offset + TYPE_LENGTH_SIZE + len(value) + padding_len
return offset
def xclip(msg):
p = subprocess.Popen(['xclip', '-selection', 'clipboard'],
stdin=subprocess.PIPE)
p.communicate(msg.encode())
# to workaround annoying python feature of returning negative hex values
def hex32(val):
return val & 0xffffffff
# match with kernel crc32_le(0, buf, buf_len) implementation
def _crc32(buf):
return hex32(~(hex32(binascii.crc32(buf, 0xffffffff))))
def pretty_array_str(array):
return '\',\''.join(array)
class BoardName():
@staticmethod
def parse_ie(buf, offset, length):
self = BoardName()
fmt = '<%ds' % length
(name, ) = struct.unpack_from(fmt, buf, offset)
self.name = name.decode()
logging.debug('BoardName.parse_ie(): offset %d length %d self %s' %
(offset, length, self))
return self
def add_to_buf(self, ebdf, buf, offset):
ie_id = ATH10K_BD_IE_BOARD_NAME
if ebdf:
ie_id = ATH10K_BD_IE_BOARD_EXT_NAME
return add_ie(buf, offset, ie_id, self.name.encode('utf-8'))
def __eq__(self, other):
return self.name == other.name
def __repr__(self):
return self.__str__()
def __str__(self):
return 'BoardName(%s)' % self.name
def __init__(self, name=None):
self.name = name
class BoardData():
@staticmethod
def parse_ie(buf, offset, length):
self = BoardData()
fmt = '<%ds' % length
(self.data, ) = struct.unpack_from(fmt, buf, offset)
logging.debug('BoardData.parse_ie(): offset %d length %d self %s' %
(offset, length, self))
return self
def add_to_buf(self, ebdf, buf, offset):
ie_id = ATH10K_BD_IE_BOARD_DATA
if ebdf:
ie_id = ATH10K_BD_IE_BOARD_EXT_DATA
return add_ie(buf, offset, ie_id, self.data)
def __repr__(self):
return self.__str__()
def __str__(self):
if self.data is not None:
s = '%d B' % (len(self.data))
else:
s = 'n/a'
return 'BoardData(%s)' % (s)
def __init__(self, data=None):
self.data = data
class Board():
@staticmethod
def parse_ie(buf, offset, length):
logging.debug('Board.parse_ie(): offset %d length %d' % (offset, length))
self = Board()
# looping board IEs
while length > 0:
(ie_id, ie_len) = struct.unpack_from('<2i', buf, offset)
logging.debug('Board.parse_ie(): found ie_id %d ie_len %d offset %d length %d' %
(ie_id, ie_len, offset, length))
if TYPE_LENGTH_SIZE + ie_len > length:
raise Exception('Error: ie_len too big (%d > %d)' % (ie_len,
length))
offset += TYPE_LENGTH_SIZE
length -= TYPE_LENGTH_SIZE
# FIXME: create separate ExtenderBoard() class so that we
# don't need these "or" hacks here. Maybe add a common
# abstract class to avoid code duplication?
if ie_id == ATH10K_BD_IE_BOARD_NAME or ie_id == ATH10K_BD_IE_BOARD_EXT_NAME:
self.names.append(BoardName.parse_ie(buf, offset, ie_len))
elif ie_id == ATH10K_BD_IE_BOARD_DATA or ie_id == ATH10K_BD_IE_BOARD_EXT_DATA:
self.data = BoardData.parse_ie(buf, offset, ie_len)
offset += ie_len + padding_needed(ie_len)
length -= ie_len + padding_needed(ie_len)
return self
def add_to_buf(self, buf, offset):
# store position ie header of this element
ie_offset = offset
offset += TYPE_LENGTH_SIZE
ie_id = ATH10K_BD_IE_BOARD
if self.ebdf:
ie_id = ATH10K_BD_IE_BOARD_EXT
for name in self.names:
offset = name.add_to_buf(self.ebdf, buf, offset)
offset = self.data.add_to_buf(self.ebdf, buf, offset)
# write ie header as now we know the full length
ie_len = offset - ie_offset - TYPE_LENGTH_SIZE
struct.pack_into('<2i', buf, ie_offset, ie_id, ie_len)
return offset
def get_names_as_str(self):
names = []
for boardname in self.names:
names.append(boardname.name)
return names
def __repr__(self):
return self.__str__()
def __str__(self):
names = []
for boardname in self.names:
names.append(str(boardname))
return 'Board(%s, %s)' % (','.join(names), self.data)
def __init__(self):
self.data = None
self.names = []
self.ebdf = False
class BoardContainer:
def find_board(self, name):
for board in self.boards:
for boardname in board.names:
if name == boardname.name:
return board
def add_board(self, data, names):
boardnames = []
ebdf = False
for name in names:
b = self.find_board(name)
if b:
self.boards.remove(b)
if "bmi-eboard-id" in name:
ebdf = True
boardnames.append(BoardName(name))
board = Board()
board.ebdf = ebdf
board.data = BoardData(data)
board.names = boardnames
self.boards.append(board)
@staticmethod
def open_json(filename):
self = BoardContainer()
if not os.path.exists(filename):
print('mapping file %s not found' % (filename))
return
f = open(filename, 'r')
mapping = json.loads(f.read())
f.close()
for b in mapping:
board_filename = b['data']
f = open(board_filename, 'rb')
data = f.read()
f.close()
self.add_board(data, b['names'])
return self
def validate(self):
allnames = []
for board in self.boards:
for name in board.names:
if name in allnames:
# TODO: Find a better way to report problems,
# maybe return a list of strings? Or use an
# exception?
print('Warning: duplicate board name: %s' % (name.name))
return
allnames.append(name)
def _add_signature(self, buf, offset):
signature = ATH10K_BOARD_SIGNATURE + b'\0'
length = len(signature)
pad_len = padding_needed(length)
length = length + pad_len
padding = ctypes.create_string_buffer(pad_len)
for i in range(pad_len):
struct.pack_into('<B', padding, i, PADDING_MAGIC)
fmt = '<%ds%ds' % (len(signature), pad_len)
struct.pack_into(fmt, buf, offset, signature, padding.raw)
offset += length
# make sure ATH10K_BOARD_SIGNATURE_LEN is correct
assert ATH10K_BOARD_SIGNATURE_LEN == length
return offset
@staticmethod
def open(name):
self = BoardContainer()
f = open(name, 'rb')
buf = f.read()
f.close()
buf_len = len(buf)
logging.debug('BoardContainer.open(): name %s' % (name))
offset = 0
fmt = '<%dsb' % (len(ATH10K_BOARD_SIGNATURE))
(signature, null) = struct.unpack_from(fmt, buf, offset)
if signature != ATH10K_BOARD_SIGNATURE or null != 0:
print("invalid signature found in %s" % name)
return 1
offset += ATH10K_BOARD_SIGNATURE_LEN
# looping main IEs
while offset < buf_len:
(ie_id, ie_len) = struct.unpack_from('<2i', buf, offset)
logging.debug('BoardContainer.open(): found offset %d ie_id %d ie_len %d' %
(offset, ie_id, ie_len))
offset += TYPE_LENGTH_SIZE
if offset + ie_len > buf_len:
print('Error: Buffer too short (%d + %d > %d)' % (offset,
ie_len,
buf_len))
return 1
# FIXME: create separate ExtenderBoard() class and
# self.extender_boards list
if ie_id == ATH10K_BD_IE_BOARD or ie_id == ATH10K_BD_IE_BOARD_EXT:
self.boards.append(Board.parse_ie(buf, offset, ie_len))
offset += ie_len + padding_needed(ie_len)
self.validate()
return self
def write(self, name):
(buf, buf_len) = self.get_bin()
fd = open(name, 'wb')
fd.write(buf.raw[0:buf_len])
fd.close()
self.validate()
print("board binary file '%s' is created" % name)
def get_bin(self):
buf = ctypes.create_string_buffer(MAX_BUF_LEN)
offset = 0
offset = self._add_signature(buf, offset)
for board in self.boards:
offset = board.add_to_buf(buf, offset)
# returns buffer and it's length
return buf, offset
def get_summary(self, sort=False):
(buf, buf_len) = self.get_bin()
s = ''
s += 'FileSize: %d\n' % (buf_len)
s += 'FileCRC32: %08x\n' % (_crc32(buf[0:buf_len]))
s += 'FileMD5: %s\n' % (hashlib.md5(buf[0:buf_len]).hexdigest())
boards = self.boards
if sort:
boards = sorted(boards, key=lambda board: board.get_names_as_str())
index = 0
for board in boards:
if not sort:
index_s = '[%d]' % (index)
else:
index_s = ''
s += 'BoardNames%s: \'%s\'\n' % (index_s, pretty_array_str(board.get_names_as_str()))
s += 'BoardLength%s: %d\n' % (index_s, len(board.data.data))
s += 'BoardCRC32%s: %08x\n' % (index_s, _crc32(board.data.data))
s += 'BoardMD5%s: %s\n' % (index_s, hashlib.md5(board.data.data).hexdigest())
index += 1
return s
def __init__(self):
self.boards = []
def cmd_extract(args):
cont = BoardContainer().open(args.extract)
mapping = []
for board in cont.boards:
filename = board.names[0].name + '.bin'
b = {}
b['names'] = board.get_names_as_str()
b['data'] = filename
mapping.append(b)
f = open(filename, 'wb')
f.write(board.data.data)
f.close()
print("%s created size: %d" % (filename, len(board.data.data)))
filename = DEFAULT_JSON_FILE
f = open(filename, 'w')
f.write(json.dumps(mapping, indent=4))
f.close()
print("%s created" % (filename))
def cmd_info(args):
filename = args.info
cont = BoardContainer().open(filename)
print(cont.get_summary())
def cmd_diff(args):
if args.diff:
filename1 = args.diff[0]
filename2 = args.diff[1]
else:
filename1 = args.diffstat[0]
filename2 = args.diffstat[1]
print(diff_boardfiles(filename1, filename2, args.diff))
def diff_boardfiles(filename1, filename2, diff):
result = ''
container1 = BoardContainer().open(filename1)
(temp1_fd, temp1_pathname) = tempfile.mkstemp()
os.write(temp1_fd, container1.get_summary(sort=True).encode())
container2 = BoardContainer().open(filename2)
(temp2_fd, temp2_pathname) = tempfile.mkstemp()
os.write(temp2_fd, container2.get_summary(sort=True).encode())
# this function is used both with --diff and --diffstat
if diff:
# '--less-mode' and '--auto-page' would be nice when running on
# terminal but don't know how to get the control character
# through. For terminal detection sys.stdout.isatty() can be used.
cmd = ['wdiff', temp1_pathname, temp2_pathname]
# wdiff is braindead and returns 1 in a succesfull case
try:
output = subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
if e.returncode == 1:
output = e.output
else:
print('Failed to run wdiff: %d\n%s' % (e.returncode, e.output))
return 1
except OSError as e:
print('Failed to run wdiff: %s' % (e))
return 1
result += '%s\n' % (output.decode())
# create simple statistics about changes in board images
new_boards = {}
deleted_boards = {}
changed_boards = {}
for board in container2.boards:
# convert the list to a string
s = pretty_array_str(board.get_names_as_str())
new_boards[s] = board
for board in container1.boards:
# convert the list to a string
names = pretty_array_str(board.get_names_as_str())
if names not in new_boards:
# board image has been deleted
deleted_boards[names] = board
continue
board2 = new_boards[names]
del new_boards[names]
if board.data.data == board2.data.data:
# board image hasn't changed
continue
# board image has changed
changed_boards[names] = board2
result += 'New:\n%s\n\n' % ('\n'.join(new_boards.keys()))
result += 'Changed:\n%s\n\n' % ('\n'.join(changed_boards.keys()))
result += 'Deleted:\n%s\n' % ('\n'.join(deleted_boards.keys()))
result += '%d board image(s) added, %d changed, %d deleted, %d in total' % (len(new_boards),
len(changed_boards),
len(deleted_boards),
len(container2.boards))
os.close(temp1_fd)
os.close(temp2_fd)
return result
def cmd_create(args):
mapping_file = args.create
if args.output:
output = args.output
else:
output = DEFAULT_BOARD_FILE
cont = BoardContainer.open_json(mapping_file)
cont.write(output)
def cmd_add_board(args):
if len(args.add_board) < 3:
print('error: --add-board requires 3 or more arguments, only %d given' % (len(args.add_board)))
sys.exit(1)
board_filename = args.add_board[0]
new_filename = args.add_board[1]
new_names = args.add_board[2:]
f = open(new_filename, 'rb')
new_data = f.read()
f.close()
# copy the original file for diff
(temp_fd, temp_pathname) = tempfile.mkstemp()
shutil.copyfile(board_filename, temp_pathname)
container = BoardContainer.open(board_filename)
container.add_board(new_data, new_names)
container.write(board_filename)
print(diff_boardfiles(temp_pathname, board_filename, False))
os.remove(temp_pathname)
def git_get_head_id():
return subprocess.check_output(['git', 'log', '--format=format:%H', '-1'], text=True)
def cmd_add_mbox(args):
board_filename = args.add_mbox[0]
mbox_filename = args.add_mbox[1]
mbox = mailbox.mbox(mbox_filename)
for msg in mbox:
board_files = {}
for part in msg.walk():
filename = part.get_filename()
if not filename:
# not an attachment
continue
if not filename.endswith(BIN_SUFFIX):
continue
name = filename[:-len(BIN_SUFFIX)]
board_files[name] = part.get_payload(decode=True)
print('Found mail "%s" with %d board files' % (msg['Subject'],
len(board_files)))
# copy the original file for diff
(temp_fd, temp_pathname) = tempfile.mkstemp()
shutil.copyfile(board_filename, temp_pathname)
container = BoardContainer.open(board_filename)
for name, data in board_files.items():
names = [name]
container.add_board(data, names)
container.write(board_filename)
applied_msg = ''
if args.commit:
cmd = ['git', 'commit', '--quiet', '-m', msg['Subject'], board_filename]
subprocess.check_call(cmd)
applied_msg += 'Thanks, added to %s:\n\n' % (board_filename)
applied_msg += diff_boardfiles(temp_pathname, board_filename, False)
applied_msg += '\n\n'
if args.commit:
applied_msg += '%s/%s\n\n' % (ATH10K_FIRMWARE_URL, git_get_head_id())
os.remove(temp_pathname)
print('----------------------------------------------')
print(applied_msg)
print('----------------------------------------------')
xclip(applied_msg)
def main():
description = '''ath10k board-N.bin files manegement tool
ath10k-bdencoder is for creating (--create), listing (--info) and
comparing (--diff, --diffstat) ath10k board-N.bin files. The
board-N.bin is a container format which can have unlimited number of
actual board images ("board files"), each image containing one or
names which ath10k uses to find the correct image.
For creating board files you need a mapping file in JSON which
contains the names and filenames for the actual binary:
[
{"names": ["AAA1", "AAAA2"], "data": "A.bin"},
{"names": ["B"], "data": "B.bin"},
{"names": ["C"], "data": "C.bin"},
]
In this example the board-N.bin will contain three board files which
are read from files named A.bin (using names AAA1 and AAAA2 in the
board-N.bin file), B.bin (using name B) and C.bin (using name C). You
can use --extract switch to see examples from real board-N.bin files.
'''
parser = argparse.ArgumentParser(description=description,
formatter_class=argparse.RawTextHelpFormatter)
cmd_group = parser.add_mutually_exclusive_group(required=True)
cmd_group.add_argument("-c", "--create", metavar='JSON_FILE',
help='create board-N.bin from a mapping file in JSON format')
cmd_group.add_argument("-e", "--extract", metavar='BOARD_FILE',
help='extract board-N.bin file to a JSON mapping file and individual board files, compatible with the format used with --create command')
cmd_group.add_argument("-i", "--info", metavar='BOARD_FILE',
help='show all details about a board-N.bin file')
cmd_group.add_argument('-d', '--diff', metavar='BOARD_FILE', nargs=2,
help='show differences between two board-N.bin files')
cmd_group.add_argument('-D', '--diffstat', metavar='BOARD_FILE', nargs=2,
help='show a summary of differences between two board-N.bin files')
cmd_group.add_argument('-a', '--add-board', metavar='NAME', nargs='+',
help='add a board file to an existing board-N.bin, first argument is the filename of board-N.bin to add to, second is the filename board file (board.bin) to add and then followed by one or more arguments are names used in board-N.bin')
cmd_group.add_argument('-A', '--add-mbox', metavar='FILENAME', nargs=2,
help='FIXME')
parser.add_argument('-C', '--commit', action='store_true',
help='commit changes to a git repository')
parser.add_argument('-v', '--verbose', action='store_true',
help='enable verbose (debug) messages')
parser.add_argument("-o", "--output", metavar="BOARD_FILE",
help='name of the output file, otherwise the default is: %s' %
(DEFAULT_BOARD_FILE))
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
if args.create:
return cmd_create(args)
elif args.extract:
return cmd_extract(args)
elif args.info:
return cmd_info(args)
elif args.diff:
return cmd_diff(args)
elif args.diffstat:
return cmd_diff(args)
elif args.add_board:
return cmd_add_board(args)
elif args.add_mbox:
return cmd_add_mbox(args)
if __name__ == "__main__":
main()

501
tools/scripts/ath10k/ath10k-check Executable file
View file

@ -0,0 +1,501 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2017 Qualcomm Atheros, Inc.
# Copyright (c) 2018, The Linux Foundation. All rights reserved.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Run 'ath10k-check --help' to see the instructions
#
import subprocess
import os
import logging
import sys
import argparse
import re
import tempfile
import queue
import threading
import string
import hashlib
import distutils.spawn
CHECKPATCH_COMMIT = '99b70ece33d87500ef7bee8e32cb99772c45ce14'
GIT_URL = 'https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/scripts/checkpatch.pl?id=%s'
DRIVER_DIR = 'drivers/net/wireless/ath/ath10k/'
FILTER_REGEXP = r'/ath'
IGNORE_FILES = ['trace.h']
CHECKPATCH_IGNORE = ['MSLEEP',
'USLEEP_RANGE',
'PRINTK_WITHOUT_KERN_LEVEL',
# ath10k does not follow networking comment style
'NETWORKING_BLOCK_COMMENT_STYLE',
'LINUX_VERSION_CODE',
'COMPLEX_MACRO',
'PREFER_DEV_LEVEL',
'PREFER_PR_LEVEL',
'COMPARISON_TO_NULL',
'BIT_MACRO',
'CONSTANT_COMPARISON',
'MACRO_WITH_FLOW_CONTROL',
# Spams hundreds of lines useless 'struct should
# normally be const' warnings, maybe a bug in
# checkpatch?
'CONST_STRUCT',
# TODO: look like valid warnings, investigate
'MACRO_ARG_REUSE',
'OPEN_ENDED_LINE',
'FUNCTION_ARGUMENTS',
'CONFIG_DESCRIPTION',
'ASSIGNMENT_CONTINUATIONS',
'UNNECESSARY_PARENTHESES',
# Not sure if these really useful warnings,
# disable for now.
'MACRO_ARG_PRECEDENCE',
'BOOL_MEMBER',
]
CHECKPATCH_OPTS = ['--strict', '-q', '--terse', '--no-summary',
'--max-line-length=90', '--show-types']
checkpatch_filter = [
('ath10k_read_simulate_fw_crash', 'LONG_LINE'),
('wmi_ops', 'LONG_LINE'),
('wmi_tlv_policy', 'SPACING'),
('ath10k_core_register_work', 'RETURN_VOID'),
('ATH10K_HW_RATE_CCK_.*', 'LONG_LINE'),
('ATH10K_DFS_STAT_INC', 'MACRO_ARG_UNUSED'),
# checkpatch doesn't like uninitialized_var()
('ath10k_init_hw_params', 'FUNCTION_ARGUMENTS'),
]
# global variables
logger = logging.getLogger('ath10k-check')
threads = 1
class CPWarning():
def __str__(self):
return 'CPWarning(%s, %s, %s, %s, %s)' % (self.path, self.lineno,
self.tag, self.type,
self.msg)
def __init__(self):
self.path = ''
self.lineno = ''
self.type = ''
self.msg = ''
self.tag = ''
def run_gcc(args):
# to disable utf-8 from gcc, easier to paste that way
os.environ['LC_CTYPE'] = 'C'
cmd = 'rm -f %s/*.o' % (DRIVER_DIR)
logger.debug('%s' % cmd)
subprocess.call(cmd, shell=True, universal_newlines=True)
cmd = ['make', '-k', '-j', str(threads)]
if not args.no_extra:
cmd.append('W=1')
cmd.append(DRIVER_DIR)
env = os.environ.copy()
# disable ccache in case it's in use, it's useless as we are
# compiling only few files and it also breaks GCC's
# -Wimplicit-fallthrough check
env['CCACHE_DISABLE'] = '1'
logger.debug('%s' % cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=env, universal_newlines=True)
(stdout, stderr) = p.communicate()
stderr = stderr.strip()
if len(stderr) > 0:
for line in stderr.splitlines():
match = re.search(FILTER_REGEXP, line)
if not args.no_filter and not match:
logger.debug('FILTERED: %s' % line)
continue
print(line.strip())
return p.returncode
def run_sparse(args):
cmd = ['make', '-k', '-j',
str(threads), DRIVER_DIR, 'C=2', 'CF="-D__CHECK_ENDIAN__"']
logger.debug('%s' % cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
(stdout, stderr) = p.communicate()
stderr = stderr.strip()
if len(stderr) > 0:
for line in stderr.splitlines():
match = re.search(FILTER_REGEXP, line)
if not args.no_filter and not match:
logger.debug('FILTERED: %s' % line)
continue
print(line.strip())
return p.returncode
def find_tagname(tag_map, filename, lineno):
if filename.find('Kconfig') != -1:
return None
if filename not in tag_map:
return None
# we need the tags sorted per linenumber
sorted_tags = sorted(tag_map[filename], key=lambda tup: tup[0])
lineno = int(lineno)
prev = None
# find the tag which is in lineno
for (l, tag) in sorted_tags:
if l > lineno:
return prev
prev = tag
return None
def parse_checkpatch_warning(line):
m = re.match(r'(.*?):(\d+): .*?:(.*?): (.*)', line, re.M | re.I)
result = CPWarning()
result.path = m.group(1)
result.lineno = m.group(2)
result.type = m.group(3)
result.msg = m.group(4)
return result
def is_filtered(cpwarning):
if cpwarning.tag is None:
return False
for (tag, type) in checkpatch_filter:
matchobj = re.match(tag, cpwarning.tag)
if matchobj is None:
continue
if cpwarning.type == type:
return True
return False
def get_checkpatch_cmdline():
return ['checkpatch.pl'] + CHECKPATCH_OPTS + \
['--ignore', ",".join(CHECKPATCH_IGNORE)]
def run_checkpatch_cmd(args, q, tag_map):
checkpatch_cmd = get_checkpatch_cmdline() + ['-f']
while True:
try:
f = q.get_nowait()
except queue.Empty:
# no more files to check
break
cmd = checkpatch_cmd + [f]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
(stdoutdata, stderrdata) = p.communicate()
if stdoutdata is None:
continue
lines = stdoutdata.splitlines()
for line in lines:
w = parse_checkpatch_warning(line)
w.tag = find_tagname(tag_map, f, w.lineno)
if not args.no_filter and is_filtered(w):
logger.debug('FILTERED: %s' % w)
continue
logger.debug(w)
print('%s:%s: %s' % (w.path, w.lineno, w.msg))
q.task_done()
def run_checkpatch(args):
# get all files which need to be checked
cmd = 'git ls-tree HEAD %s | cut -f 2' % (DRIVER_DIR)
output = subprocess.check_output(cmd, shell=True, universal_newlines=True)
driver_files = output.splitlines()
# drop files we need to ignore
for name in IGNORE_FILES:
full_name = '%s%s' % (DRIVER_DIR, name)
if full_name in driver_files:
driver_files.remove(full_name)
logger.debug('driver_files: %s' % (driver_files))
# create global index file
(fd, tmpfilename) = tempfile.mkstemp()
f = os.fdopen(fd, 'w')
f.write('\n'.join(driver_files))
f.close()
# FIXME: do we need to call os.close(fd) still?
cmd = 'gtags -f %s' % (tmpfilename)
logger.debug('%s' % (cmd))
output = subprocess.check_output(cmd, shell=True, universal_newlines=True)
os.remove(tmpfilename)
# tag_map[FILENAME] = [(start line, tagname)]
tag_map = {}
# create tag mapping
for f in driver_files:
# global gives an error from Kconfig and Makefile
if f.endswith('Kconfig') or f.endswith('Makefile'):
continue
cmd = 'global -f %s' % (f)
output = subprocess.check_output(cmd, shell=True, universal_newlines=True)
lines = output.splitlines()
for l in lines:
columns = l.split()
tagname = columns[0]
line = int(columns[1])
if f not in tag_map:
tag_map[f] = []
tag_map[f].append((line, tagname))
q = queue.Queue()
for f in driver_files:
q.put(f)
# run checkpatch for all files
for i in range(threads):
t = threading.Thread(
target=run_checkpatch_cmd, args=(args, q, tag_map))
t.daemon = True
t.start()
q.join()
return 0
def show_version(args):
gcc_version = 'not found'
sparse_version = 'not found'
checkpatch_version = 'not found'
checkpatch_md5sum = 'N/A'
gtags_version = 'not found'
run = subprocess.check_output
f = open(sys.argv[0], 'rb')
ath10kcheck_md5sum = hashlib.md5(f.read()).hexdigest()
f.close()
try:
gcc_version = run(['gcc', '--version'],
universal_newlines=True).splitlines()[0]
except:
pass
try:
sparse_version = run(['sparse', '--version'],
universal_newlines=True).splitlines()[0]
except:
pass
try:
checkpatch_version = run(['checkpatch.pl', '--version'],
universal_newlines=True).splitlines()[1]
path = distutils.spawn.find_executable(
'checkpatch.pl', os.environ['PATH'])
f = open(path, 'rb')
checkpatch_md5sum = hashlib.md5(f.read()).hexdigest()
f.close()
except:
pass
try:
gtags_version = run(['gtags', '--version'],
universal_newlines=True).splitlines()[0]
except:
pass
print('ath10k-check (md5sum %s)' % (ath10kcheck_md5sum))
print
print('gcc:\t\t%s' % (gcc_version))
print('sparse:\t\t%s' % (sparse_version))
print('checkpatch.pl:\t%s (md5sum %s)' % (checkpatch_version, checkpatch_md5sum))
print('gtags:\t\t%s' % (gtags_version))
sys.exit(0)
def main():
global threads
checkpatch_url = GIT_URL % (CHECKPATCH_COMMIT)
description = '''ath10k source code checker
Runs various tests (gcc, sparse and checkpatch) with filtering
unnecessary warnings away, the goal is to have empty output from the
script.
Run this from the main kernel source directory which is preconfigured
with ath10k enabled. gcc recompilation is forced every time,
irrespective if there are any changes in source or not. So this can be
run multiple times and every time the same warnings will appear.
Requirements (all available in $PATH):
* gcc
* sparse
* checkpatch.pl
* gtags (from package global)
'''
s = '''Installation:
As checkpatch is evolving this script always matches a certain version
of checkpatch. Download the checkpatch version from the URL below and
install it somewhere in your $$PATH:
$CHECKPATCH_URL
Alternatively if you want manually run checkpatch with the same
settings as ath10k-check uses here's the command line:
$CHECKPATCH_CMDLINE
'''
checkpatch_cmdline = '%s foo.patch' % ' '.join(get_checkpatch_cmdline())
epilog = string.Template(s).substitute(CHECKPATCH_URL=checkpatch_url,
CHECKPATCH_CMDLINE=checkpatch_cmdline)
parser = argparse.ArgumentParser(description=description, epilog=epilog,
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-d', '--debug', action='store_true',
help='enable debug messages')
parser.add_argument('--fast', action='store_true',
help='run only tests which finish in few seconds')
parser.add_argument('--no-extra', action='store_true',
help='Do not run extra checks like W=1')
parser.add_argument('--no-filter', action='store_true',
help='Don\'t filter output with regexp: %r' % (FILTER_REGEXP))
parser.add_argument('--version', action='store_true',
help='Show version information about dependencies')
args = parser.parse_args()
timefmt = ''
if args.debug:
logger.setLevel(logging.DEBUG)
timefmt = '%(asctime)s '
logfmt = '%s%%(levelname)s: %%(message)s' % (timefmt)
logging.basicConfig(format=logfmt)
if args.version:
show_version(args)
if args.fast:
gcc = True
sparse = True
checkpatch = False
else:
gcc = True
sparse = True
checkpatch = True
try:
cores = subprocess.check_output(['nproc'], universal_newlines=True)
except (OSError, subprocess.CalledProcessError):
cores = '4'
logger.warning('Failed to run nproc, assuming %s cores' % (cores))
threads = int(cores) + 2
logger.debug('threads %d' % (threads))
if gcc:
ret = run_gcc(args)
if ret != 0:
logger.debug('gcc failed: %d', ret)
sys.exit(1)
if sparse:
ret = run_sparse(args)
if ret != 0:
logger.debug('sparse failed: %d', ret)
sys.exit(2)
if checkpatch:
ret = run_checkpatch(args)
if ret != 0:
logger.debug('checkpatch failed: %d', ret)
sys.exit(3)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,806 @@
#!/usr/bin/python3
#
# Copyright (c) 2016 Qualcomm Atheros, Inc.
# Copyright (c) 2018, The Linux Foundation. All rights reserved.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import os
import logging
import re
import argparse
import shutil
import sys
import filecmp
import functools
import subprocess
import email
# global variables
logger = None
blacklist = False
BRANCH_DEFAULT_PRIORITY = 1000
BRANCH_PRIORITY_FILE = '.priority'
BRANCH_IGNORE_FILE = '.ignore'
WHENCE_FILE = 'WHENCE'
FIRMWARE_BLACKLIST = [
'999.999.0.636',
'10.2-00082-4-2'
]
@functools.total_ordering
class Hardware():
def get_path(self):
return os.path.join(self.hw, self.hw_ver)
def __eq__(self, other):
return self.name == other.name
def __lt__(self, other):
return self.name < other.name
def __repr__(self):
return self.__str__()
def __str__(self):
return 'Hardware(\'%s\'): %s %s' % (self.name, self.board_files,
sorted(self.firmware_branches))
def __init__(self, hw, hw_ver):
# QCA6174
self.hw = hw
# hw3.0
self.hw_ver = hw_ver
self.name = '%s %s' % (hw, hw_ver)
self.firmware_branches = []
self.board_files = []
@functools.total_ordering
class FirmwareBranch():
def __eq__(self, other):
return self.priority == other.priority and self.name == other.name
def __lt__(self, other):
# '.' is always of the lower priority
if self.name == '.':
return True
if other.name == '.':
return False
if self.priority != other.priority:
if self.priority < other.priority:
return True
else:
return False
return self.name < other.name
def __repr__(self):
return self.__str__()
def __str__(self):
return 'FirmwareBranch(\'%s\'): %s' % (self.name, sorted(self.firmwares))
def __init__(self, name, path=None):
self.name = name
self.firmwares = []
self.priority = BRANCH_DEFAULT_PRIORITY
if path:
priority_path = os.path.join(path, BRANCH_PRIORITY_FILE)
if os.path.isfile(priority_path):
try:
f = open(priority_path, 'r')
buf = f.read()
f.close()
self.priority = int(buf)
except Exception as e:
print('Failed to read %s: %s' % (priority_path, e))
class BoardFile():
@staticmethod
def create_from_path(path):
filename = os.path.basename(path)
match = re.search(r'^board-(\d+).bin', filename)
if match is None:
match = re.search(r'^board.bin', filename)
if match is None:
return None
if len(match.groups()) > 1:
bd_api = match.group(1)
else:
bd_api = None
return BoardFile(path, bd_api)
def get_installation_name(self):
return os.path.basename(self.path)
def __repr__(self):
return self.__str__()
def __str__(self):
return '%s' % (self.get_installation_name())
def __init__(self, path, bd_api):
self.path = path
self.bd_api = bd_api
class Firmware():
@staticmethod
def create_from_path(path):
filename = os.path.basename(path)
match = re.search(r'^firmware-(\d+).bin_(.+)', filename)
if match is None:
return None
fw_api = match.group(1)
fw_ver = match.group(2)
return Firmware(fw_ver, path, fw_api)
def get_installation_name(self):
return 'firmware-%s.bin' % (self.fw_api)
def get_notice_filename(self):
return 'notice_ath10k_firmware-%s.txt' % (self.fw_api)
def __eq__(self, other):
return self.fw_ver == other.fw_ver
def __ne__(self, other):
return not self.__eq__(other)
# FIXME: firmware-5.bin_10.4-3.2-00080 and
# firmware-5.bin_10.4-3.2.1-00028 are sorted incorrectly
def __lt__(self, other):
s = self.fw_ver
o = other.fw_ver
# FIXME: An ugly hack that to make the comparison easier to
# implement. Just to get some sort of simple sorting working
# replace '-' with '.' in version string. But now for example
# '10.2.4.70.2 > 10.2.4.70-2' is not compared correctly.
s = s.replace('-', '.')
o = o.replace('-', '.')
s = s.split('.')
o = o.split('.')
s2 = s
o2 = o
s = []
o = []
for t in s2:
try:
k = int(t)
except:
k = t
s.append(k)
for t in o2:
try:
k = int(t)
except:
k = t
o.append(k)
l = min(len(s), len(o))
for i in range(l):
if s[i] < o[i]:
return True
elif s[i] > o[i]:
return False
if len(s) > len(o):
return False
return True
def __le__(self, other):
return self.__lt__(other) or self.__eq__(other)
def __gt__(self, other):
return not self.__le__(other)
def __ge__(self, other):
return self.__gt__(other) or self.__eq__(other)
def __repr__(self):
return self.__str__()
def __str__(self):
return '%s' % (self.fw_ver)
# path can be None with unittests
def __init__(self, fw_ver, path=None, fw_api=None):
self.path = path
self.fw_api = fw_api
self.fw_ver = fw_ver
self.notice_path = None
if path:
s = 'notice.txt_%s' % (self.fw_ver)
n = os.path.join(os.path.dirname(path), s)
if os.path.isfile(n):
self.notice_path = n
def scan_dir(path):
fw_list = []
bd_list = []
files = os.listdir(path)
files.sort()
for f in files:
f_path = os.path.join(path, f)
if not os.path.isfile(f_path):
continue
firmware = Firmware.create_from_path(f_path)
if firmware:
if blacklist and firmware.fw_ver in FIRMWARE_BLACKLIST:
logger.debug('\'%s\' blacklisted' % (firmware.fw_ver))
continue
fw_list.append(firmware)
continue
boardfile = BoardFile.create_from_path(f_path)
if boardfile:
bd_list.append(boardfile)
continue
# skip notice files
if f.startswith('notice.txt'):
continue
if f == BRANCH_PRIORITY_FILE:
continue
logger.warning('Unknown file: %s' % (f_path))
return fw_list, bd_list
# QCA988X/hw2.0
def scan_hw_ver(hw):
path = hw.get_path()
files = os.listdir(path)
files.sort()
for fw_branch in files:
fw_branch_path = os.path.join(path, fw_branch)
if not os.path.isdir(fw_branch_path):
continue
if os.path.exists(os.path.join(fw_branch_path, BRANCH_IGNORE_FILE)):
logger.debug('Ignoring firmware branch: %s' % (fw_branch))
continue
logger.debug('Found firmware branch: %s' % (fw_branch))
fb = FirmwareBranch(fw_branch, fw_branch_path)
hw.firmware_branches.append(fb)
(fw, bd) = scan_dir(fw_branch_path)
fb.firmwares += fw
# board file should be only in "." (main) branch, not in other branches
# this is the main branch named "."
fb = FirmwareBranch('.')
(fw, bd) = scan_dir(path)
fb.firmwares += fw
hw.board_files += bd
hw.firmware_branches.append(fb)
# QCA98XX
def scan_hw(path):
hws = []
files = os.listdir(path)
files.sort()
for hw_ver in files:
hw_ver_path = os.path.join(path, hw_ver)
if not os.path.isdir(hw_ver_path):
continue
logger.debug('Found hw version: %s' % (hw_ver))
hw = Hardware(path, hw_ver)
scan_hw_ver(hw)
hws.append(hw)
return hws
def scan_repository(directory):
hws = {}
files = os.listdir(directory)
files.sort()
for hw_name in files:
if not os.path.isdir(hw_name):
continue
# skip hidden directories
if hw_name.startswith('.'):
continue
logger.debug('Found hw: %s' % (hw_name))
hw_list = scan_hw(hw_name)
for hw in hw_list:
hws[hw.name] = hw
return hws
def install_file(args, src, installdir, dest):
if args.dry_run:
return
destpath = os.path.join(installdir, dest)
destdir = os.path.dirname(destpath)
if not os.path.isdir(destdir):
os.makedirs(destdir)
shutil.copyfile(src, destpath)
return destpath
def get_firmware_version(path):
cmd = ['ath10k-fwencoder', '--info', path]
info = subprocess.check_output(cmd, universal_newlines=True)
msg = email.message_from_string(info)
return msg['FirmwareVersion']
def get_board_crc32(path):
cmd = ['ath10k-fwencoder', '--crc32', path]
return subprocess.check_output(cmd, universal_newlines=True).strip()
# print indent
def pi(level, msg):
print('%s%s' % (level * '\t', msg))
def whence_update(linux_firmware, firmware_path, version):
f = open(os.path.join(linux_firmware, WHENCE_FILE), 'r')
buf = f.read()
f.close()
pattern = r'(File: %s\nVersion: ).*\n' % (firmware_path)
# \g<1> is same as \1 but needed to separate from the version string
replace = r'\g<1>%s\n' % (version)
(buf, sub_count) = re.subn(pattern, replace, buf, flags=re.MULTILINE)
if sub_count != 1:
print('Failed to update %s to WHENCE: %d' % (firmware_path, sub_count))
return
f = open(os.path.join(linux_firmware, WHENCE_FILE), 'w')
f.write(buf)
f.close()
def whence_add(linux_firmware, firmware_path, version, license_path=None):
f = open(os.path.join(linux_firmware, WHENCE_FILE), 'r')
buf = f.read()
f.close()
pattern = r'(Driver: ath10k.*?\n\n.*?)\n\n'
# \g<1> is same as \1 but needed to separate from the version string
replace = r'\g<1>\nFile: %s\n' % (firmware_path)
replace += r'Version: %s\n' % (version)
if license_path is not None:
replace += r'File: %s\n' % (license_path)
replace += r'\n'
(buf, sub_count) = re.subn(pattern, replace, buf, flags=re.MULTILINE | re.DOTALL)
if sub_count != 1:
print('Failed to add %s to WHENCE: %d' % (firmware_path, sub_count))
return
f = open(os.path.join(linux_firmware, WHENCE_FILE), 'w')
f.write(buf)
f.close()
def git_commit(args, msg, repodir, files):
if not args.commit:
# nothing to do
return
cmd = ['git', '-C', repodir, 'commit', '--quiet', '--signoff', '-m', msg] + files
logger.debug('Running: %r' % (cmd))
subprocess.check_call(cmd)
def git_add(args, repodir, files):
if not args.commit:
# nothing to do
return
cmd = ['git', '-C', repodir, 'add'] + files
logger.debug('Running: %r' % (cmd))
subprocess.check_call(cmd)
def cmd_check(args):
scan_repository('.')
def cmd_list(args):
level = 0
hws = scan_repository('.')
for hw in sorted(hws.values()):
pi(level, '%s:' % (hw.name))
level += 1
# print board files
if len(hw.board_files) > 0:
pi(level, 'board')
level += 1
for board_file in sorted(hw.board_files):
pi(level, board_file)
level -= 1
# print firmware branches
for branch in sorted(hw.firmware_branches):
if len(branch.firmwares) == 0:
# don't print empty branches
continue
pi(level, '%s' % (branch.name))
level += 1
for fw in sorted(branch.firmwares):
pi(level, fw.fw_ver)
level -= 1
level -= 1
def cmd_list_lib_dir(args):
fw_dir = args.list_lib_dir[0]
ath10k_dir = os.path.join(fw_dir, 'ath10k')
if not os.path.exists(ath10k_dir):
print('directory %s does not exist, aborting' % (ath10k_dir))
sys.exit(1)
if not os.path.isdir(ath10k_dir):
print('%s is not a directory, aborting' % (ath10k_dir))
sys.exit(1)
# sort the results based on dirpath
for (dirpath, dirnames, filenames) in sorted(os.walk(ath10k_dir)):
found = []
for filename in sorted(filenames):
path = os.path.join(dirpath, filename)
match = re.match(r'firmware.*\.bin', filename)
if match is not None:
# this is a firmware file
s = '%s\t%s' % (filename, get_firmware_version(path))
found.append(s)
match = re.match(r'board.*\.bin', filename)
if match is not None:
# this is a board file
s = '%s\t%s' % (filename, get_board_crc32(path))
found.append(s)
if len(found) > 0:
# Just show QCA1234/hw1.0 directories. I would have liked
# to use os.path functions here but just could not find
# anything sensible there.
pi(0, '%s:' % ('/'.join(dirpath.split('/')[-2:])))
for line in found:
pi(1, line)
def cmd_get_latest_in_branch(args):
# As this command is mostly for scripts to parse, don't show
# warnings etc to clutter the output, unless we are debugging of
# course.
if not args.debug:
logger.setLevel(logging.ERROR)
hws = scan_repository('.')
args_hw = args.get_latest_in_branch[0]
args_hwver = args.get_latest_in_branch[1]
args_fwbranch = args.get_latest_in_branch[2]
# TODO: hw is always in uppercase and hwver lower case, check that
hw_name = '%s %s' % (args_hw, args_hwver)
if hw_name not in hws:
print('Did not find hardware: %s' % (hw_name))
sys.exit(1)
hw = hws[hw_name]
fw_branch = None
for b in hw.firmware_branches:
if b.name == args_fwbranch:
fw_branch = b
break
if fw_branch is None:
print('Did not find firmware branch: %s' % (args_fwbranch))
sys.exit(1)
if len(fw_branch.firmwares) == 0:
# no firmware images in this branch, just use return value 0 with no output
sys.exit(0)
print(sorted(fw_branch.firmwares)[-1].path)
sys.exit(0)
def cmd_get_latest_in_hw(args):
# As this command is mostly for scripts to parse, don't show
# warnings etc to clutter the output, unless we are debugging of
# course.
if not args.debug:
logger.setLevel(logging.ERROR)
hws = scan_repository('.')
args_hw = args.get_latest[0]
args_hwver = args.get_latest[1]
# TODO: hw is always in uppercase and hwver lower case, check that
hw_name = '%s %s' % (args_hw, args_hwver)
if hw_name not in hws:
print('Did not find hardware: %s' % (hw_name))
sys.exit(1)
hw = hws[hw_name]
fw_branch = sorted(hw.firmware_branches)[-1]
if len(fw_branch.firmwares) == 0:
# no firmware images in this branch, just use return value 0 with no output
sys.exit(0)
print(sorted(fw_branch.firmwares)[-1].path)
sys.exit(0)
def cmd_install(args):
global blacklist
blacklist = True
hws = scan_repository('.')
linux_firmware = args.install[0]
installdir = os.path.join(linux_firmware, 'ath10k')
if not os.path.isdir(installdir):
logger.error('%s is not a directory' % (installdir))
sys.exit(1)
logger.debug('Installing to directory %s' % (installdir))
# install firmware files
for hw in sorted(hws.values()):
# every Hardware() should have at least one firmware branch, the
# main '.' branch so no need to check the length
fw_list = sorted(sorted(hw.firmware_branches)[-1].firmwares)
if len(fw_list) == 0:
# no firmware images found
continue
destdir = hw.get_path()
# install latest firmware
#
# FIXME: should we install the latest for every FW API
# version (2, 4, 5 etc.), not just the latest?
fw = fw_list[-1]
dest = os.path.join(destdir, fw.get_installation_name())
d = os.path.join(installdir, dest)
if not os.path.exists(d) or not filecmp.cmp(fw.path, d):
installed = []
if os.path.exists(d):
action = 'update'
else:
action = 'add'
logger.info('Installing %s (%s)' % (dest, fw.fw_ver))
destpath = install_file(args, fw.path, installdir, dest)
installed.append(destpath)
firmware_path = os.path.join('ath10k', dest)
if fw.notice_path:
dest = os.path.join(destdir, fw.get_notice_filename())
logger.info('Installing %s (%s)' % (dest, fw.fw_ver))
destpath = install_file(args, fw.notice_path, installdir, dest)
installed.append(destpath)
notice_path = os.path.join('ath10k', dest)
else:
notice_path = None
if action == 'update':
# updating an existing firmware file
whence_update(linux_firmware, firmware_path, fw.fw_ver)
else:
# adding a new firmware file
whence_add(linux_firmware, firmware_path, fw.fw_ver, notice_path)
git_add(args, linux_firmware, installed)
installed.append(WHENCE_FILE)
# "ath10k: QCA9888 hw2.0: update firmware-5.bin to 10.4-3.5.1-00035"
log = 'ath10k: %s: %s %s to %s' % (hw.name,
action,
fw.get_installation_name(),
fw.fw_ver)
git_commit(args, log, linux_firmware, installed)
else:
logger.debug(
'No update needed for %s (%s)' % (dest, fw.fw_ver))
# install board files
for hw in sorted(hws.values()):
bd_list = hw.board_files
for bd in bd_list:
installed = []
dest = os.path.join(installdir, bd.path)
if not os.path.exists(dest) or not filecmp.cmp(bd.path, dest):
if os.path.exists(dest):
action = 'update'
else:
action = 'add'
logger.info('Installing %s' % (bd.path))
destpath = install_file(args, bd.path, installdir, bd.path)
installed.append(destpath)
# TODO: update WHENCE file when adding a new board
# file to linux-firmware
log = 'ath10k: %s: %s %s' % (hw.name,
action,
bd.get_installation_name())
git_commit(args, log, linux_firmware, installed)
else:
logger.debug('No update needed for %s' % (dest))
def main():
global logger
logger = logging.getLogger('ath10k-fw-repo')
parser = argparse.ArgumentParser(
description='Install firmware images from the ath10k-firmware git repository. Run it from the top directory of the working tree.')
parser.add_argument('--debug', action='store_true',
help='Enable debug messages.')
parser.add_argument('--dry-run', action='store_true',
help='Do not run any actual commands.')
parser.add_argument('--check', action='store_true',
help='Check the ath10k-firmware repository content for validity.')
parser.add_argument('--list', action='store_true',
help='List all files found from the ath10k-firmware repository.')
parser.add_argument('--list-lib-dir', action='store',
nargs=1, metavar='LIB_FIRMWARE_DIRECTORY',
help='List all files found from the specified directory, which can either be a linux-firmware repository or /lib/firmware directory.')
parser.add_argument('--install', action='store', nargs=1, metavar='DESTINATION',
help='Install all ath10k firmware images to DESTINATION folder, for example /lib/firmware.')
parser.add_argument('--commit', action='store_true',
help='When installing files also git commit them, for example when updating linux-firmware.git.')
parser.add_argument('--get-latest-in-branch', action='store', nargs=3,
metavar=('HW', 'HWVER', 'BRANCH'),
help='Show latest firmware version from a firmware branch. Just outputs the version for easy parsing in scripts.')
parser.add_argument('--get-latest', action='store', nargs=2,
metavar=('HW', 'HWVER'),
help='Show latest firmware version for hardware version. Just outputs the version for easy parsing in scripts.')
args = parser.parse_args()
if args.debug:
logging.basicConfig(format='%(levelname)s: %(message)s')
logger.setLevel(logging.DEBUG)
else:
logging.basicConfig(format='%(message)s')
logger.setLevel(logging.INFO)
# commands
if args.check:
cmd_check(args)
elif args.list:
cmd_list(args)
elif args.list_lib_dir:
cmd_list_lib_dir(args)
elif args.install:
cmd_install(args)
elif args.get_latest_in_branch:
cmd_get_latest_in_branch(args)
elif args.get_latest:
cmd_get_latest_in_hw(args)
else:
logger.error('No command defined')
parser.print_usage()
if __name__ == "__main__":
main()

View file

@ -0,0 +1,934 @@
#!/usr/bin/python3
#
# Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import ctypes
import struct
import optparse
import time
import math
import logging
import sys
import os.path
import traceback
import binascii
import tempfile
import subprocess
import hashlib
DEFAULT_FW_API_VERSION = 4
ATH10K_SIGNATURE = b"QCA-ATH10K"
MAX_LEN = 2000000
ATH10K_FW_IE_FW_VERSION = 0
ATH10K_FW_IE_TIMESTAMP = 1
ATH10K_FW_IE_FEATURES = 2
ATH10K_FW_IE_FW_IMAGE = 3
ATH10K_FW_IE_OTP_IMAGE = 4
ATH10K_FW_IE_WMI_OP_VERSION = 5
ATH10K_FW_IE_HTT_OP_VERSION = 6
ATH10K_FW_IE_FW_CODE_SWAP_IMAGE = 7
# enum ath10k_fw_features from ath10k/core.h
ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0
ATH10K_FW_FEATURE_WMI_10X = 1
ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX = 2
ATH10K_FW_FEATURE_NO_P2P = 3
ATH10K_FW_FEATURE_WMI_10_2 = 4
ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5
ATH10K_FW_FEATURE_WOWLAN_SUPPORT = 6
ATH10K_FW_FEATURE_IGNORE_OTP_RESULT = 7
ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING = 8
ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9
ATH10K_FW_FEATURE_RAW_MODE_SUPPORT = 10
ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA = 11
ATH10K_FW_FEATURE_MFP_SUPPORT = 12
ATH10K_FW_FEATURE_PEER_FLOW_CONTROL = 13
ATH10K_FW_FEATURE_BTCOEX_PARAM = 14
ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR = 15
ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST = 16
ATH10K_FW_FEATURE_NO_PS = 17
ATH10K_FW_FEATURE_MGMT_TX_BY_REF = 18
ATH10K_FW_FEATURE_NON_BMI = 19
ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL = 20
ATH10K_FW_FEATURE_PEER_FIXED_RATE = 21
ATH10K_FW_FEATURE_MAX = 22
feature_map = {
'ext-wmi-mgmt-rx': ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX,
'wmi-10x': ATH10K_FW_FEATURE_WMI_10X,
'wmi-mgmt-tx': ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
'no-p2p': ATH10K_FW_FEATURE_NO_P2P,
'wmi-10-2': ATH10K_FW_FEATURE_WMI_10_2,
'multi-vif-ps': ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT,
'wowlan': ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
'ignore-otp-result': ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
'no-nwifi-decap-4addr-padding':
ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
'skip-clock-init': ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
'raw-mode': ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,
'adaptive-cca': ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA,
'mfp-support': ATH10K_FW_FEATURE_MFP_SUPPORT,
'peer-flow-ctrl': ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
'btcoex-param': ATH10K_FW_FEATURE_BTCOEX_PARAM,
'skip-null-func-war': ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR,
'allows-mesh-bcast': ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST,
'no-ps': ATH10K_FW_FEATURE_NO_PS,
'mgmt-tx-by-ref': ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
'non-bmi': ATH10K_FW_FEATURE_NON_BMI,
'single-chan-info-per-channel': ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL,
'peer-fixed-rate': ATH10K_FW_FEATURE_PEER_FIXED_RATE,
}
# from enum ath10k_fw_wmi_op_version in ath10k/hw.h
ATH10K_FW_WMI_OP_VERSION_UNSET = 0
ATH10K_FW_WMI_OP_VERSION_MAIN = 1
ATH10K_FW_WMI_OP_VERSION_10_1 = 2
ATH10K_FW_WMI_OP_VERSION_10_2 = 3
ATH10K_FW_WMI_OP_VERSION_TLV = 4
ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5
ATH10K_FW_WMI_OP_VERSION_10_4 = 6
wmi_op_version_map = {
'unset': ATH10K_FW_WMI_OP_VERSION_UNSET,
'main': ATH10K_FW_WMI_OP_VERSION_MAIN,
'10.1': ATH10K_FW_WMI_OP_VERSION_10_1,
'10.2': ATH10K_FW_WMI_OP_VERSION_10_2,
'tlv': ATH10K_FW_WMI_OP_VERSION_TLV,
'10.2.4': ATH10K_FW_WMI_OP_VERSION_10_2_4,
'10.4': ATH10K_FW_WMI_OP_VERSION_10_4,
}
# from enum ath10k_fw_wmi_op_version in ath10k/hw.h
ATH10K_FW_HTT_OP_VERSION_UNSET = 0
ATH10K_FW_HTT_OP_VERSION_MAIN = 1
ATH10K_FW_HTT_OP_VERSION_10_1 = 2
ATH10K_FW_HTT_OP_VERSION_TLV = 3
ATH10K_FW_HTT_OP_VERSION_10_4 = 4
htt_op_version_map = {
'unset': ATH10K_FW_HTT_OP_VERSION_UNSET,
'main': ATH10K_FW_HTT_OP_VERSION_MAIN,
'10.1': ATH10K_FW_HTT_OP_VERSION_10_1,
'tlv': ATH10K_FW_HTT_OP_VERSION_TLV,
'10.4': ATH10K_FW_HTT_OP_VERSION_10_4,
}
ETHTOOL_FWVERS_LEN = 32
# global variables
logger = None
class FWEncoderError(Exception):
pass
def get_output_name(fw_api=None):
if fw_api is not None:
api = fw_api
else:
api = DEFAULT_FW_API_VERSION
return 'firmware-%s.bin' % api
class FirmwareContainer:
def add_element(self, type_id, value):
length = len(value)
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, 0x77)
logger.debug('adding id %d len(value) %d'
'padding_len %d' % (type_id,
len(value),
padding_len))
fmt = '<ii%ds%ds' % (len(value), padding_len)
struct.pack_into(fmt, self.buf, self.buf_len, type_id, len(value),
value, padding.raw)
self.buf_len = self.buf_len + 4 + 4 + len(value) + padding_len
def add_u32(self, type_id, value):
if not type(value) is int:
raise FWEncoderError('u32 IE %d is not int: %s' %
(type_id, str(value)))
buf = ctypes.create_string_buffer(4)
struct.pack_into("<i", buf, 0, value)
self.add_element(type_id, buf.raw)
def read_u32(self, type_id):
(val,) = struct.unpack_from("<i", self.elements[type_id])
return val
def add_bitmap(self, ie, enabled, maximum):
if (max(enabled) >= maximum):
logger.error("bitmap %d out of maximum (%d >= %d)" %
(ie, max(enabled), maximum))
return
bytes = [0] * maximum
for i in range(maximum):
if i not in enabled:
continue
max_set = i
index = int(i / 8)
bit = i % 8
bytes[index] = bytes[index] | (1 << bit)
# remove trailing null bits away, that changing only
# maximum doesn't affect created binary size
length = int(math.ceil((max_set + 1) / float(8)))
bytes = bytes[:length]
buf = ctypes.create_string_buffer(length)
for index in range(length):
struct.pack_into('<B', buf, index, bytes[index])
self.add_element(ie, buf.raw)
def read_bitmap(self, ie):
buf = self.elements[ie]
length = len(buf)
bits = []
for index in range(length):
val = struct.unpack_from('<B', buf, index)[0]
for bit in range(8):
if val & 0x1:
bits.append(index * 8 + bit)
val = val >> 1
return bits
def set_signature(self, signature):
self.signature = signature
self.signature_len = len(signature)
# include the null byte
length = len(signature) + 1
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, 0x77)
fmt = '<%dsb%ds' % (len(signature), padding_len)
struct.pack_into(fmt, self.buf, 0, signature, 0, padding.raw)
self.buf_len = length
def write(self, name):
f = open(name, 'wb')
f.write(self.buf.raw[:self.buf_len])
f.close()
return self.buf_len
def open(self, name):
f = open(name, 'rb')
self.buf = f.read()
self.buf_len = len(self.buf)
f.close()
offset = 0
fmt = '<%dsb' % (self.signature_len)
(signature, null) = struct.unpack_from(fmt, self.buf, offset)
offset = offset + self.signature_len + 1
if signature != self.signature or null != 0:
logger.error("Invalid signature!")
return False
offset = self.signature_len + 1
offset = offset + padding_needed(offset)
self.elements = {}
while offset + 4 + 4 < self.buf_len:
(type_id, length) = struct.unpack_from("<ii", self.buf, offset)
offset = offset + 4 + 4
if offset + length > self.buf_len:
logger.error("Buffer too short")
return
fmt = '<%ds' % length
(payload,) = struct.unpack_from(fmt, self.buf, offset)
offset = offset + length
offset = offset + padding_needed(offset)
self.elements[type_id] = payload
return True
def __init__(self, signature):
self.buf = ctypes.create_string_buffer(MAX_LEN)
self.buf_len = 0
self.set_signature(signature)
class Ath10kFirmwareContainer(object):
def _load_file(self, name):
if os.path.getsize(name) > MAX_LEN:
raise FWEncoderError('file %s is too large, maximum size is %d' %
(name, MAX_LEN))
f = open(name, 'rb')
buf = f.read()
f.close()
return buf
def set_fw_code_swap_image(self, fw_code_swap_image_name):
self.fw_code_swap_image = self._load_file(fw_code_swap_image_name)
def get_fw_code_swap_image(self):
return self.fw_code_swap_image
def set_htt_op_version(self, htt_op_version):
s = htt_op_version
# convert the string to integer
if s in htt_op_version_map:
version = htt_op_version_map[s]
elif is_int(s):
version = s
else:
print('Error: Invalid HTT OP version: %s' % s)
return 1
self.htt_op_version = version
def get_htt_op_version(self):
version = self.htt_op_version
# find value from the dict
try:
name = [key for key, value in htt_op_version_map.items()
if value == version][0]
except IndexError:
name = str(version)
return name
def set_wmi_op_version(self, wmi_op_version):
s = wmi_op_version
# convert the string to integer
if s in wmi_op_version_map:
version = wmi_op_version_map[s]
elif is_int(s):
version = s
else:
print('Error: Invalid WMI OP version: %s' % s)
return 1
self.wmi_op_version = version
def get_wmi_op_version(self):
version = self.wmi_op_version
# find value from the dict
try:
name = [key for key, value in wmi_op_version_map.items()
if value == version][0]
except IndexError:
name = str(version)
return name
def set_features(self, features):
self.features = features.split(',')
enabled = []
for capa in self.features:
if capa not in feature_map:
print("Error: '%s' not found from the feature map" % capa)
return 1
enabled.append(feature_map[capa])
self.features_bitmap = enabled
def get_features(self):
s = ""
if self.features_bitmap is None:
return None
for capa in self.features_bitmap:
# find value from the dict
try:
name = [key for key, value in feature_map.items()
if value == capa][0]
except IndexError:
name = str(capa)
s = s + name + ","
# strip last comma
if len(s) > 0:
s = s[:-1]
return s
def set_fw_image(self, fw_image_name):
self.fw_image = self._load_file(fw_image_name)
def get_fw_image(self):
return self.fw_image
def set_otp_image(self, otp_image_name):
self.otp_image = self._load_file(otp_image_name)
def get_otp_image(self):
return self.otp_image
def set_timestamp(self, timestamp):
self.timestamp = int(timestamp)
def get_timestamp(self):
return self.timestamp
def get_timestamp_as_iso8601(self):
if self.timestamp is None:
return None
return time.strftime('%Y-%m-%d %H:%M:%S',
time.gmtime(self.timestamp))
# fw_version must be a string
def set_fw_version(self, fw_version):
self.fw_version = fw_version
# reserve one byte for null
if len(self.fw_version) > ETHTOOL_FWVERS_LEN - 1:
print('Firmware version string too long: %d' % (len(self.fw_version)))
return 1
# returns a string
def get_fw_version(self):
return self.fw_version
def get_summary(self):
s = ''
s = s + 'FileSize: %s\n' % (len(self.file))
s = s + 'FileCRC32: %08x\n' % (_crc32(self.file))
s = s + 'FileMD5: %s\n' % (hashlib.md5(self.file).hexdigest())
if self.get_fw_version():
s = s + 'FirmwareVersion: %s\n' % (self.get_fw_version())
if self.get_timestamp():
s = s + 'Timestamp: %s\n' % (self.get_timestamp_as_iso8601())
if self.get_features():
s = s + 'Features: %s\n' % (self.get_features())
if self.get_fw_image():
s = s + 'FirmwareImageSize: %s\n' % (len(self.get_fw_image()))
s = s + 'FirmwareImageCRC32: %08x\n' % (_crc32(self.get_fw_image()))
if self.get_otp_image():
s = s + 'OTPImageSize: %s\n' % (len(self.get_otp_image()))
s = s + 'OTPImageCRC32: %08x\n' % (_crc32(self.get_otp_image()))
if self.get_wmi_op_version():
s = s + 'WMIOpVersion: %s\n' % (self.get_wmi_op_version())
if self.get_htt_op_version():
s = s + 'HTTOpVersion: %s\n' % (self.get_htt_op_version())
if self.get_fw_code_swap_image():
s = s + 'FirmwareCodeSwapImageSize: %s\n' % (len(self.get_fw_code_swap_image()))
s = s + 'FirmwareCodeSwapImageCRC32: %08x\n' % (_crc32(self.get_fw_code_swap_image()))
return s.strip()
def load(self, filename):
c = FirmwareContainer(ATH10K_SIGNATURE)
c.open(filename)
self.file = c.buf
for e in c.elements:
if e == ATH10K_FW_IE_FW_VERSION:
self.fw_version = c.elements[e].decode()
elif e == ATH10K_FW_IE_TIMESTAMP:
self.timestamp = c.read_u32(e)
elif e == ATH10K_FW_IE_OTP_IMAGE:
self.otp_image = c.elements[e]
elif e == ATH10K_FW_IE_FW_IMAGE:
self.fw_image = c.elements[e]
elif e == ATH10K_FW_IE_FEATURES:
self.features_bitmap = c.read_bitmap(ATH10K_FW_IE_FEATURES)
elif e == ATH10K_FW_IE_WMI_OP_VERSION:
self.wmi_op_version = c.read_u32(ATH10K_FW_IE_WMI_OP_VERSION)
elif e == ATH10K_FW_IE_HTT_OP_VERSION:
self.htt_op_version = c.read_u32(ATH10K_FW_IE_HTT_OP_VERSION)
elif e == ATH10K_FW_IE_FW_CODE_SWAP_IMAGE:
self.fw_code_swap_image = c.elements[e]
else:
print("Unknown IE: ", e)
def save(self, filename):
self.container = FirmwareContainer(ATH10K_SIGNATURE)
if self.fw_version:
self.container.add_element(ATH10K_FW_IE_FW_VERSION,
self.fw_version.encode())
if self.timestamp:
self.container.add_u32(ATH10K_FW_IE_TIMESTAMP, self.timestamp)
# FIXME: otp should be after fw_image but that breaks the
# current tests
if self.otp_image:
self.container.add_element(ATH10K_FW_IE_OTP_IMAGE, self.otp_image)
if self.fw_image:
self.container.add_element(ATH10K_FW_IE_FW_IMAGE, self.fw_image)
# FIXME: features should be before fw_image but that breaks
# the current tests
if self.features_bitmap:
self.container.add_bitmap(ATH10K_FW_IE_FEATURES,
self.features_bitmap,
ATH10K_FW_FEATURE_MAX)
if self.wmi_op_version:
self.container.add_u32(ATH10K_FW_IE_WMI_OP_VERSION, self.wmi_op_version)
if self.htt_op_version:
self.container.add_u32(ATH10K_FW_IE_HTT_OP_VERSION,
self.htt_op_version)
if self.fw_code_swap_image:
self.container.add_element(ATH10K_FW_IE_FW_CODE_SWAP_IMAGE,
self.fw_code_swap_image)
return self.container.write(filename)
def __init__(self):
self.fw_version = None
self.timestamp = None
self.features = None
self.features_bitmap = None
self.fw_image = None
self.otp_image = None
self.wmi_op_version = None
self.htt_op_version = None
self.fw_code_swap_image = None
# to workaround annoying python feature of returning negative hex values
def hex32(val):
return val & 0xffffffff
# match with kernel crc32_le(0, buf, buf_len) implementation
def _crc32(buf):
return hex32(~(hex32(binascii.crc32(buf, 0xffffffff))))
def padding_needed(length):
if length % 4 != 0:
return 4 - length % 4
return 0
def is_int(val):
try:
int(val)
return True
except ValueError:
return False
def write_file(filename, buf):
f = open(filename, 'wb')
f.write(buf)
f.close
def info(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath10kFirmwareContainer()
c.load(filename)
print(c.get_summary())
def dump(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath10kFirmwareContainer()
c.load(filename)
print("ath10k-fwencoder --create \\")
if c.get_fw_version():
print("--firmware-version=%s \\" % c.get_fw_version())
if c.get_timestamp() and options.show_timestamp:
print("--timestamp=%u \\" % c.get_timestamp())
if c.get_features():
print("--features=%s \\" % c.get_features())
if c.get_fw_image():
name = "athwlan.bin"
print("--firmware=%s \\" % name)
if c.get_otp_image():
name = "otp.bin"
print("--otp=%s \\" % name)
if c.get_wmi_op_version():
print('--set-wmi-op-version=%s \\' % c.get_wmi_op_version())
if c.get_htt_op_version():
print('--set-htt-op-version=%s \\' % (c.get_htt_op_version()))
if c.get_fw_code_swap_image():
name = "athwlan.codeswap.bin"
print("--firmware-codeswap=%s \\" % name)
print('')
def extract(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath10kFirmwareContainer()
c.load(filename)
if c.get_fw_image():
name = "athwlan.bin"
write_file(name, c.get_fw_image())
print('%s extracted: %d B' % (name, len(c.get_fw_image())))
if c.get_otp_image():
name = "otp.bin"
write_file(name, c.get_otp_image())
print('%s extracted: %d B' % (name, len(c.get_otp_image())))
if c.get_fw_code_swap_image():
name = "athwlan.codeswap.bin"
write_file(name, c.get_fw_code_swap_image())
print('%s extracted: %d B' % (name, len(c.get_fw_code_swap_image())))
print('')
def modify(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath10kFirmwareContainer()
c.load(filename)
if options.firmware_version:
c.set_fw_version(options.firmware_version)
if options.timestamp:
stamp = str(int(options.timestamp))
else:
# if no timestamp provided use the current time so that the
# timestamp shows the time of last modication
stamp = int(time.time())
c.set_timestamp(stamp)
if options.otp:
c.set_otp_image(options.otp)
if options.fw:
c.set_fw_image(options.fw)
if options.features:
c.set_features(options.features)
if options.wmi_op_version:
c.set_wmi_op_version(options.wmi_op_version)
if options.htt_op_version:
c.set_htt_op_version(options.htt_op_version)
if options.fw_codeswap:
c.set_fw_code_swap_image(options.fw_codeswap)
file_len = c.save(filename)
print('%s modified: %d B' % (filename, file_len))
def create(options):
output = get_output_name(options.fw_api)
if options.output:
output = options.output
c = Ath10kFirmwareContainer()
if options.firmware_version:
c.set_fw_version(options.firmware_version)
# always add a timestamp
if options.timestamp:
stamp = int(options.timestamp)
else:
stamp = int(time.time())
c.set_timestamp(stamp)
if options.otp:
c.set_otp_image(options.otp)
if options.fw:
c.set_fw_image(options.fw)
if options.features:
c.set_features(options.features)
if options.wmi_op_version:
c.set_wmi_op_version(options.wmi_op_version)
if options.htt_op_version:
c.set_htt_op_version(options.htt_op_version)
if options.fw_codeswap:
c.set_fw_code_swap_image(options.fw_codeswap)
file_len = c.save(output)
print('%s created: %d B' % (output, file_len))
def cmd_crc32(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
f = open(filename, 'rb')
buf = f.read()
print('%08x' % (_crc32(buf)))
f.close()
def cmd_diff(options, args):
if len(args) != 2:
print('Usage: ath10k-fwencoder --diff FILE FILE')
return 1
filename1 = args[0]
filename2 = args[1]
c1 = Ath10kFirmwareContainer()
c1.load(filename1)
(temp1_fd, temp1_pathname) = tempfile.mkstemp(text=True)
# for some reason text=True is not working with mkstemp() so open
# the file manually
f = open(temp1_pathname, 'w')
f.write(c1.get_summary())
f.close()
c2 = Ath10kFirmwareContainer()
c2.load(filename2)
(temp2_fd, temp2_pathname) = tempfile.mkstemp(text=True)
# for some reason text=True is not working with mkstemp() so open
# the file manually
f = open(temp2_pathname, 'w')
f.write(c2.get_summary())
f.close()
# '--less-mode' and '--auto-page' would be nice when running on
# terminal but don't know how to get the control character
# through. For terminal detection sys.stdout.isatty() can be used.
cmd = ['wdiff', temp1_pathname, temp2_pathname]
# wdiff is braindead and returns 1 in a succesfull case
try:
output = subprocess.check_output(cmd, universal_newlines=True)
except subprocess.CalledProcessError as e:
if e.returncode == 1:
output = e.output
else:
logger.error('Failed to run wdiff: %d\n%s' % (e.returncode, e.output))
return 1
except OSError as e:
logger.error('Failed to run wdiff: %s' % (e))
return 1
print(output)
os.close(temp1_fd)
os.close(temp2_fd)
def main():
global logger
logger = logging.getLogger('ath10k-fwencoder')
logging.basicConfig(format='%(levelname)s: %(message)s')
parser = optparse.OptionParser()
# actions
parser.add_option("-c", "--create", action="store_true", dest="create",
help='Create container file '
'for ath10k (%s)' % get_output_name())
parser.add_option("-D", "--dump-cmdline", action="store_true", dest="dump",
help='Show the cmdline used to create '
'this container file')
parser.add_option('--dump', action='store_true', dest='dump',
help='Same as --dump-cmdline '
'(for backwards compatibility)')
parser.add_option("-e", "--extract", action="store_true", dest="extract",
help='Extract binary files from the container file '
'and dump cmdline as well')
parser.add_option("--info", action="store_true", dest="info",
help='Show information about the container file')
parser.add_option("--modify", action="store_true", dest="modify",
help='Modify the container file')
parser.add_option('--crc32', action='store_true', dest='crc32',
help='Count crc32 checksum for a file')
parser.add_option('--diff', action='store_true', dest='diff',
help='Show differences between two firmware files')
# parameters
parser.add_option("-o", "--output", action="store", type="string",
dest="output", help='Name of output file')
# FW IEs, only use long style of option names!
parser.add_option("--otp", action="store", type="string",
dest="otp",
help='Name of otp.bin file')
parser.add_option("--firmware", action="store", type="string",
dest="fw",
help='Name of athwlan.bin file')
parser.add_option("--firmware-version", action="store",
type="string", dest="firmware_version",
help='Firmware version string to be used')
parser.add_option("--timestamp", action="store",
type="string", dest="timestamp",
help='Timestamp to be used (seconds)')
parser.add_option("--features", action="store",
type="string", dest="features",
help='feature bits to be enabled: %s' %
feature_map.keys())
parser.add_option("--set-wmi-op-version", action="store",
type="string", dest="wmi_op_version",
help='WMI op interface version: %s' %
wmi_op_version_map.keys())
parser.add_option("--set-fw-api", action="store",
type="string", dest="fw_api",
help='Set firmware API used in creating the name for '
'output file (Default: %s)' %
DEFAULT_FW_API_VERSION)
parser.add_option("--set-htt-op-version", action="store",
type="string", dest="htt_op_version",
help='HTT op interface version: %s' %
htt_op_version_map.keys())
parser.add_option("--firmware-codeswap", action="store", type="string",
dest="fw_codeswap",
help='Name of athwlan.codeswap.bin file')
# debug etc
parser.add_option('--show-timestamp', action='store_true',
dest='show_timestamp',
help='Show timestamp in --dump-cmdline action. '
'It is not shown by default so that the timestamp would be correct')
parser.add_option('-d', '--debug', action='store_true', dest='debug',
help='Enable debug messages')
(options, args) = parser.parse_args()
if options.debug:
logger.setLevel(logging.DEBUG)
if options.create:
try:
return create(options)
except FWEncoderError as e:
print('Create failed: %s' % e)
sys.exit(2)
except Exception as e:
print('Create failed: %s' % e)
traceback.print_exc()
sys.exit(3)
elif options.dump:
return dump(options, args)
elif options.extract:
return extract(options, args)
elif options.info:
return info(options, args)
elif options.modify:
return modify(options, args)
elif options.crc32:
return cmd_crc32(options, args)
elif options.diff:
return cmd_diff(options, args)
else:
print('Action command missing')
return 1
if __name__ == "__main__":
main()

View file

@ -0,0 +1,862 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2017 Qualcomm Atheros, Inc.
# Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Run 'ath11k-bdencoder --help' to see the instructions
#
import struct
import ctypes
import os.path
import argparse
import json
import binascii
import hashlib
import tempfile
import subprocess
import logging
import sys
import shutil
MAX_BUF_LEN = 20000000
# the signature length also includes null byte and padding
ATH11K_BOARD_SIGNATURE = b"QCA-ATH11K-BOARD"
ATH11K_BOARD_SIGNATURE_LEN = 20
PADDING_MAGIC = 0x6d
DEFAULT_BD_API = 2
DEFAULT_BOARD_FILE = 'board-%d.bin' % DEFAULT_BD_API
DEFAULT_JSON_FILE = 'board-%d.json' % DEFAULT_BD_API
TYPE_LENGTH_SIZE = 8
ATH11K_BD_IE_BOARD = 0
ATH11K_BD_IE_REGDB = 1
ATH11K_BD_IE_BOARD_NAME = 0
ATH11K_BD_IE_BOARD_DATA = 1
ATH11K_BD_IE_REGDB_NAME = 0
ATH11K_BD_IE_REGDB_DATA = 1
def padding_needed(len):
if len % 4 != 0:
return 4 - len % 4
return 0
def add_ie(buf, offset, id, value):
length = len(value)
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, PADDING_MAGIC)
fmt = '<2i%ds%ds' % (len(value), padding_len)
struct.pack_into(fmt, buf, offset, id, len(value), value, padding.raw)
offset = offset + TYPE_LENGTH_SIZE + len(value) + padding_len
return offset
# to workaround annoying python feature of returning negative hex values
def hex32(val):
return val & 0xffffffff
# match with kernel crc32_le(0, buf, buf_len) implementation
def _crc32(buf):
return hex32(~(hex32(binascii.crc32(buf, 0xffffffff))))
def pretty_array_str(array):
return '\',\''.join(array)
class RegdbName():
@staticmethod
def parse_ie(buf, offset, length):
self = RegdbName()
fmt = '<%ds' % length
(name, ) = struct.unpack_from(fmt, buf, offset)
self.name = name.decode()
logging.debug('RegdbName.parse_ie(): offset %d length %d self %s' %
(offset, length, self))
return self
def add_to_buf(self, buf, offset):
return add_ie(buf, offset, ATH11K_BD_IE_REGDB_NAME, self.name.encode())
def __eq__(self, other):
return self.name == other.name
def __repr__(self):
return self.__str__()
def __str__(self):
return 'RegdbName(%s)' % self.name
def __init__(self, name=None):
self.name = name
class RegdbData():
@staticmethod
def parse_ie(buf, offset, length):
self = RegdbData()
fmt = '<%ds' % length
(self.data, ) = struct.unpack_from(fmt, buf, offset)
logging.debug('RegdbData.parse_ie(): offset %d length %d self %s' %
(offset, length, self))
return self
def add_to_buf(self, buf, offset):
return add_ie(buf, offset, ATH11K_BD_IE_REGDB_DATA, self.data)
def __repr__(self):
return self.__str__()
def __str__(self):
if self.data is not None:
s = '%d B' % (len(self.data))
else:
s = 'n/a'
return 'RegdbData(%s)' % (s)
def __init__(self, data=None):
self.data = data
class Regdb():
@staticmethod
def parse_ie(buf, offset, length):
logging.debug('Regdb.parse_ie(): offset %d length %d' % (offset, length))
self = Regdb()
# looping regdb IEs
while length > 0:
(ie_id, ie_len) = struct.unpack_from('<2i', buf, offset)
logging.debug('Regdb.parse_ie(): found ie_id %d ie_len %d offset %d length %d' %
(ie_id, ie_len, offset, length))
if TYPE_LENGTH_SIZE + ie_len > length:
raise Exception('Error: ie_len too big (%d > %d)' % (ie_len,
length))
offset += TYPE_LENGTH_SIZE
length -= TYPE_LENGTH_SIZE
if ie_id == ATH11K_BD_IE_REGDB_NAME:
self.names.append(RegdbName.parse_ie(buf, offset, ie_len))
elif ie_id == ATH11K_BD_IE_REGDB_DATA:
self.data = RegdbData.parse_ie(buf, offset, ie_len)
offset += ie_len + padding_needed(ie_len)
length -= ie_len + padding_needed(ie_len)
return self
def add_to_buf(self, buf, offset):
# store position ie header of this element
ie_offset = offset
offset += TYPE_LENGTH_SIZE
for name in self.names:
offset = name.add_to_buf(buf, offset)
offset = self.data.add_to_buf(buf, offset)
# write ie header as now we know the full length
ie_len = offset - ie_offset - TYPE_LENGTH_SIZE
struct.pack_into('<2i', buf, ie_offset, ATH11K_BD_IE_REGDB, ie_len)
return offset
def get_names_as_str(self):
names = []
for regdbname in self.names:
names.append(regdbname.name)
return names
def __repr__(self):
return self.__str__()
def __str__(self):
names = []
for regdbname in self.names:
names.append(str(regdbname))
return 'Regdb(%s, %s)' % (','.join(names), self.data)
def __init__(self):
self.data = None
self.names = []
class BoardName():
@staticmethod
def parse_ie(buf, offset, length):
self = BoardName()
fmt = '<%ds' % length
(name, ) = struct.unpack_from(fmt, buf, offset)
self.name = name.decode()
logging.debug('BoardName.parse_ie(): offset %d length %d self %s' %
(offset, length, self))
return self
def add_to_buf(self, buf, offset):
return add_ie(buf, offset, ATH11K_BD_IE_BOARD_NAME, self.name.encode())
def __eq__(self, other):
return self.name == other.name
def __repr__(self):
return self.__str__()
def __str__(self):
return 'BoardName(%s)' % self.name
def __init__(self, name=None):
self.name = name
class BoardData():
@staticmethod
def parse_ie(buf, offset, length):
self = BoardData()
fmt = '<%ds' % length
(self.data, ) = struct.unpack_from(fmt, buf, offset)
logging.debug('BoardData.parse_ie(): offset %d length %d self %s' %
(offset, length, self))
return self
def add_to_buf(self, buf, offset):
return add_ie(buf, offset, ATH11K_BD_IE_BOARD_DATA, self.data)
def __repr__(self):
return self.__str__()
def __str__(self):
if self.data is not None:
s = '%d B' % (len(self.data))
else:
s = 'n/a'
return 'BoardData(%s)' % (s)
def __init__(self, data=None):
self.data = data
class Board():
@staticmethod
def parse_ie(buf, offset, length):
logging.debug('Board.parse_ie(): offset %d length %d' % (offset, length))
self = Board()
# looping board IEs
while length > 0:
(ie_id, ie_len) = struct.unpack_from('<2i', buf, offset)
logging.debug('Board.parse_ie(): found ie_id %d ie_len %d offset %d length %d' %
(ie_id, ie_len, offset, length))
if TYPE_LENGTH_SIZE + ie_len > length:
raise Exception('Error: ie_len too big (%d > %d)' % (ie_len,
length))
offset += TYPE_LENGTH_SIZE
length -= TYPE_LENGTH_SIZE
if ie_id == ATH11K_BD_IE_BOARD_NAME:
self.names.append(BoardName.parse_ie(buf, offset, ie_len))
elif ie_id == ATH11K_BD_IE_BOARD_DATA:
self.data = BoardData.parse_ie(buf, offset, ie_len)
offset += ie_len + padding_needed(ie_len)
length -= ie_len + padding_needed(ie_len)
return self
def add_to_buf(self, buf, offset):
# store position ie header of this element
ie_offset = offset
offset += TYPE_LENGTH_SIZE
for name in self.names:
offset = name.add_to_buf(buf, offset)
offset = self.data.add_to_buf(buf, offset)
# write ie header as now we know the full length
ie_len = offset - ie_offset - TYPE_LENGTH_SIZE
struct.pack_into('<2i', buf, ie_offset, ATH11K_BD_IE_BOARD, ie_len)
return offset
def get_names_as_str(self):
names = []
for boardname in self.names:
names.append(boardname.name)
return names
def __repr__(self):
return self.__str__()
def __str__(self):
names = []
for boardname in self.names:
names.append(str(boardname))
return 'Board(%s, %s)' % (','.join(names), self.data)
def __init__(self):
self.data = None
self.names = []
class BoardContainer:
def add_board(self, data, names):
boardnames = []
for name in names:
boardnames.append(BoardName(name))
board = Board()
board.data = BoardData(data)
board.names = boardnames
self.boards.append(board)
def add_regdb(self, data, names):
regdbnames = []
for name in names:
regdbnames.append(RegdbName(name))
regdb = Regdb()
regdb.data = RegdbData(data)
regdb.names = regdbnames
self.regdbs.append(regdb)
@staticmethod
def open_json(filename):
self = BoardContainer()
if not os.path.exists(filename):
print('mapping file %s not found' % (filename))
return
f = open(filename, 'r')
mapping = json.loads(f.read())
f.close()
if 'board' in mapping[0]:
for b in mapping[0]['board']:
board_filename = b['data']
f = open(board_filename, 'rb')
data = f.read()
f.close()
self.add_board(data, b['names'])
if 'regdb' in mapping[0]:
for b in mapping[0]['regdb']:
regdb_filename = b['data']
f = open(regdb_filename, 'rb')
data = f.read()
f.close()
self.add_regdb(data, b['names'])
return self
def validate(self):
allnames = []
for board in self.boards:
for name in board.names:
if name in allnames:
# TODO: Find a better way to report problems,
# maybe return a list of strings? Or use an
# exception?
print('Warning: duplicate board name: %s' % (name.name))
return
allnames.append(name)
def _add_signature(self, buf, offset):
signature = ATH11K_BOARD_SIGNATURE + b'\0'
length = len(signature)
pad_len = padding_needed(length)
length = length + pad_len
padding = ctypes.create_string_buffer(pad_len)
for i in range(pad_len):
struct.pack_into('<B', padding, i, PADDING_MAGIC)
fmt = '<%ds%ds' % (len(signature), pad_len)
struct.pack_into(fmt, buf, offset, signature, padding.raw)
offset += length
# make sure ATH11K_BOARD_SIGNATURE_LEN is correct
assert ATH11K_BOARD_SIGNATURE_LEN == length
return offset
@staticmethod
def open(name):
self = BoardContainer()
f = open(name, 'rb')
buf = f.read()
f.close()
buf_len = len(buf)
logging.debug('BoardContainer.open(): name %s' % (name))
offset = 0
fmt = '<%dsb' % (len(ATH11K_BOARD_SIGNATURE))
(signature, null) = struct.unpack_from(fmt, buf, offset)
if signature != ATH11K_BOARD_SIGNATURE or null != 0:
print("invalid signature found in %s" % name)
return 1
offset += ATH11K_BOARD_SIGNATURE_LEN
# looping main IEs
while offset < buf_len:
(ie_id, ie_len) = struct.unpack_from('<2i', buf, offset)
logging.debug('BoardContainer.open(): found offset %d ie_id %d ie_len %d' %
(offset, ie_id, ie_len))
offset += TYPE_LENGTH_SIZE
if offset + ie_len > buf_len:
print('Error: Buffer too short (%d + %d > %d)' % (offset,
ie_len,
buf_len))
return 1
if ie_id == ATH11K_BD_IE_BOARD:
self.boards.append(Board.parse_ie(buf, offset, ie_len))
elif ie_id == ATH11K_BD_IE_REGDB:
self.regdbs.append(Regdb.parse_ie(buf, offset, ie_len))
offset += ie_len + padding_needed(ie_len)
self.validate()
return self
def write(self, name):
(buf, buf_len) = self.get_bin()
fd = open(name, 'wb')
fd.write(buf.raw[0:buf_len])
fd.close()
self.validate()
print("board binary file '%s' is created" % name)
def get_bin(self):
buf = ctypes.create_string_buffer(MAX_BUF_LEN)
offset = 0
offset = self._add_signature(buf, offset)
for board in self.boards:
offset = board.add_to_buf(buf, offset)
for regdb in self.regdbs:
offset = regdb.add_to_buf(buf, offset)
# returns buffer and it's length
return buf, offset
def get_summary(self, sort=False):
(buf, buf_len) = self.get_bin()
s = ''
s += 'FileSize: %d\n' % (buf_len)
s += 'FileCRC32: %08x\n' % (_crc32(buf[0:buf_len]))
s += 'FileMD5: %s\n' % (hashlib.md5(buf[0:buf_len]).hexdigest())
boards = self.boards
if sort:
boards = sorted(boards, key=lambda board: board.get_names_as_str())
index = 0
for board in boards:
if not sort:
index_s = '[%d]' % (index)
else:
index_s = ''
s += 'BoardNames%s: \'%s\'\n' % (index_s, pretty_array_str(board.get_names_as_str()))
s += 'BoardLength%s: %d\n' % (index_s, len(board.data.data))
s += 'BoardCRC32%s: %08x\n' % (index_s, _crc32(board.data.data))
s += 'BoardMD5%s: %s\n' % (index_s, hashlib.md5(board.data.data).hexdigest())
index += 1
regdbs = self.regdbs
if sort:
regdbs = sorted(regdbs, key=lambda regdb: regdb.get_names_as_str())
index = 0
for regdb in regdbs:
if not sort:
index_s = '[%d]' % (index)
else:
index_s = ''
s += 'RegdbNames%s: \'%s\'\n' % (index_s, pretty_array_str(regdb.get_names_as_str()))
s += 'RegdbLength%s: %d\n' % (index_s, len(regdb.data.data))
s += 'RegdbCRC32%s: %08x\n' % (index_s, _crc32(regdb.data.data))
s += 'RegdbMD5%s: %s\n' % (index_s, hashlib.md5(regdb.data.data).hexdigest())
index += 1
return s
def __init__(self):
self.boards = []
self.regdbs = []
def cmd_extract(args):
cont = BoardContainer().open(args.extract)
mapping = []
d = {}
mapping.append(d)
mapping_board = []
d['board'] = mapping_board
for board in cont.boards:
filename = board.names[0].name + '.bin'
b = {}
b['names'] = board.get_names_as_str()
b['data'] = filename
mapping_board.append(b)
f = open(filename, 'wb')
f.write(board.data.data)
f.close()
print("%s created size: %d" % (filename, len(board.data.data)))
mapping_regdb = []
d['regdb'] = mapping_regdb
for regdb in cont.regdbs:
filename = regdb.names[0].name + '.regdb'
b = {}
b['names'] = regdb.get_names_as_str()
b['data'] = filename
mapping_regdb.append(b)
f = open(filename, 'wb')
f.write(regdb.data.data)
f.close()
print("%s created size: %d" % (filename, len(regdb.data.data)))
filename = DEFAULT_JSON_FILE
f = open(filename, 'w')
f.write(json.dumps(mapping, indent=4))
f.close()
print("%s created" % (filename))
def cmd_info(args):
filename = args.info
cont = BoardContainer().open(filename)
print(cont.get_summary())
def cmd_diff(args):
if args.diff:
filename1 = args.diff[0]
filename2 = args.diff[1]
else:
filename1 = args.diffstat[0]
filename2 = args.diffstat[1]
print(diff_boardfiles(filename1, filename2, args.diff))
def diff_boardfiles(filename1, filename2, diff):
result = ''
container1 = BoardContainer().open(filename1)
(temp1_fd, temp1_pathname) = tempfile.mkstemp()
os.write(temp1_fd, container1.get_summary(sort=True).encode())
container2 = BoardContainer().open(filename2)
(temp2_fd, temp2_pathname) = tempfile.mkstemp()
os.write(temp2_fd, container2.get_summary(sort=True).encode())
# this function is used both with --diff and --diffstat
if diff:
# '--less-mode' and '--auto-page' would be nice when running on
# terminal but don't know how to get the control character
# through. For terminal detection sys.stdout.isatty() can be used.
cmd = ['wdiff', temp1_pathname, temp2_pathname]
# wdiff is braindead and returns 1 in a succesfull case
try:
output = subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
if e.returncode == 1:
output = e.output
else:
print('Failed to run wdiff: %d\n%s' % (e.returncode, e.output))
return 1
except OSError as e:
print('Failed to run wdiff: %s' % (e))
return 1
result += '%s\n' % (output.decode())
# create simple statistics about changes in board images
new_boards = {}
deleted_boards = {}
changed_boards = {}
for board in container2.boards:
# convert the list to a string
s = pretty_array_str(board.get_names_as_str())
new_boards[s] = board
for board in container1.boards:
# convert the list to a string
names = pretty_array_str(board.get_names_as_str())
if names not in new_boards:
# board image has been deleted
deleted_boards[names] = board
continue
board2 = new_boards[names]
del new_boards[names]
if board.data.data == board2.data.data:
# board image hasn't changed
continue
# board image has changed
changed_boards[names] = board2
result += 'New board:\n%s\n\n' % ('\n'.join(list(new_boards.keys())))
result += 'Changed board:\n%s\n\n' % ('\n'.join(list(changed_boards.keys())))
result += 'Deleted board:\n%s\n' % ('\n'.join(list(deleted_boards.keys())))
result += '%d board image(s) added, %d changed, %d deleted, %d in total\n\n' % (len(new_boards),
len(changed_boards),
len(deleted_boards),
len(container2.boards))
# create simple statistics about changes in regdb images
new_regdbs = {}
deleted_regdbs = {}
changed_regdbs = {}
for regdb in container2.regdbs:
# convert the list to a string
s = pretty_array_str(regdb.get_names_as_str())
new_regdbs[s] = regdb
for regdb in container1.regdbs:
# convert the list to a string
names = pretty_array_str(regdb.get_names_as_str())
if names not in new_regdbs:
# regdb image has been deleted
deleted_regdbs[names] = regdb
continue
regdb2 = new_regdbs[names]
del new_regdbs[names]
if regdb.data.data == regdb2.data.data:
# regdb image hasn't changed
continue
# regdb image has changed
changed_regdbs[names] = regdb2
result += 'New regdb:\n%s\n\n' % ('\n'.join(list(new_regdbs.keys())))
result += 'Changed regdb:\n%s\n\n' % ('\n'.join(list(changed_regdbs.keys())))
result += 'Deleted regdb:\n%s\n' % ('\n'.join(list(deleted_regdbs.keys())))
result += '%d regdb image(s) added, %d changed, %d deleted, %d in total' % (len(new_regdbs),
len(changed_regdbs),
len(deleted_regdbs),
len(container2.regdbs))
os.close(temp1_fd)
os.close(temp2_fd)
return result
def cmd_create(args):
mapping_file = args.create
if args.output:
output = args.output
else:
output = DEFAULT_BOARD_FILE
cont = BoardContainer.open_json(mapping_file)
cont.write(output)
def cmd_add_board(args):
if len(args.add_board) < 3:
print('error: --add-board requires 3 or more arguments, only %d given' % (len(args.add_board)))
sys.exit(1)
board_filename = args.add_board[0]
new_filename = args.add_board[1]
new_names = args.add_board[2:]
f = open(new_filename, 'rb')
new_data = f.read()
f.close()
# copy the original file for diff
(temp_fd, temp_pathname) = tempfile.mkstemp()
shutil.copyfile(board_filename, temp_pathname)
container = BoardContainer.open(board_filename)
container.add_board(new_data, new_names)
container.write(board_filename)
print(diff_boardfiles(temp_pathname, board_filename, False))
os.remove(temp_pathname)
def main():
description = '''ath11k board-N.bin files manegement tool
ath11k-bdencoder is for creating (--create), listing (--info) and
comparing (--diff, --diffstat) ath11k board-N.bin files. The
board-N.bin is a container format which can have unlimited number of
actual board images ("board files"), each image containing one or
names which ath11k uses to find the correct image.
For creating board files you need a mapping file in JSON which
contains the names and filenames for the actual binary:
[
{
"board": [
{"names": ["AAA1", "AAAA2"], "data": "A.bin"},
{"names": ["B"], "data": "B.bin"},
{"names": ["C"], "data": "C.bin"},
],
"regdb": [
{"names": ["A"], "data": "A.regdb"}
]
}
]
In this example the board-N.bin will contain three board files which
are read from files named A.bin (using names AAA1 and AAAA2 in the
board-N.bin file), B.bin (using name B) and C.bin (using name C). The file also contains one regdb (regulatory database) from file A.regdb.
You can use --extract switch to see examples from real board-N.bin
files.
'''
parser = argparse.ArgumentParser(description=description,
formatter_class=argparse.RawTextHelpFormatter)
cmd_group = parser.add_mutually_exclusive_group(required=True)
cmd_group.add_argument("-c", "--create", metavar='JSON_FILE',
help='create board-N.bin from a mapping file in JSON format')
cmd_group.add_argument("-e", "--extract", metavar='BOARD_FILE',
help='extract board-N.bin file to a JSON mapping file and individual board files, compatible with the format used with --create command')
cmd_group.add_argument("-i", "--info", metavar='BOARD_FILE',
help='show all details about a board-N.bin file')
cmd_group.add_argument('-d', '--diff', metavar='BOARD_FILE', nargs=2,
help='show differences between two board-N.bin files')
cmd_group.add_argument('-D', '--diffstat', metavar='BOARD_FILE', nargs=2,
help='show a summary of differences between two board-N.bin files')
cmd_group.add_argument('-a', '--add-board', metavar='NAME', nargs='+',
help='add a board file to an existing board-N.bin, first argument is the filename of board-N.bin to add to, second is the filename board file (board.bin) to add and then followed by one or more arguments are names used in board-N.bin')
parser.add_argument('-v', '--verbose', action='store_true',
help='enable verbose (debug) messages')
parser.add_argument("-o", "--output", metavar="BOARD_FILE",
help='name of the output file, otherwise the default is: %s' %
(DEFAULT_BOARD_FILE))
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
if args.create:
return cmd_create(args)
elif args.extract:
return cmd_extract(args)
elif args.info:
return cmd_info(args)
elif args.diff:
return cmd_diff(args)
elif args.diffstat:
return cmd_diff(args)
elif args.add_board:
return cmd_add_board(args)
if __name__ == "__main__":
main()

529
tools/scripts/ath11k/ath11k-check Executable file
View file

@ -0,0 +1,529 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2017 Qualcomm Atheros, Inc.
# Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Run 'ath11k-check --help' to see the instructions
#
import subprocess
import os
import logging
import sys
import argparse
import re
import tempfile
import queue
import threading
import string
import hashlib
import shutil
CHECKPATCH_COMMIT = '99b70ece33d87500ef7bee8e32cb99772c45ce14'
CHECKPATCH_MD5SUM = 'b3c97930952745672f3408dabc244843'
GIT_URL = 'https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/scripts/checkpatch.pl?id=%s'
DRIVER_DIR = 'drivers/net/wireless/ath/ath11k/'
FILTER_REGEXP = r'/ath'
IGNORE_FILES = []
CHECKPATCH_IGNORE = ['MSLEEP',
'USLEEP_RANGE',
'PRINTK_WITHOUT_KERN_LEVEL',
# ath10k does not follow networking comment style
'NETWORKING_BLOCK_COMMENT_STYLE',
'LINUX_VERSION_CODE',
'COMPLEX_MACRO',
'PREFER_DEV_LEVEL',
'PREFER_PR_LEVEL',
'COMPARISON_TO_NULL',
'BIT_MACRO',
'CONSTANT_COMPARISON',
'MACRO_WITH_FLOW_CONTROL',
# Spams hundreds of lines useless 'struct should
# normally be const' warnings, maybe a bug in
# checkpatch?
'CONST_STRUCT',
# TODO: look like valid warnings, investigate
'MACRO_ARG_REUSE',
'OPEN_ENDED_LINE',
'FUNCTION_ARGUMENTS',
'CONFIG_DESCRIPTION',
'ASSIGNMENT_CONTINUATIONS',
'UNNECESSARY_PARENTHESES',
# Not sure if these really useful warnings,
# disable for now.
'MACRO_ARG_PRECEDENCE',
'BOOL_MEMBER',
# TODO: ath11k uses volatile for now, fix it
'VOLATILE',
# TODO: document all DT usage in ath11k
'UNDOCUMENTED_DT_STRING',
]
CHECKPATCH_OPTS = ['--strict', '-q', '--terse', '--no-summary',
'--max-line-length=90', '--show-types']
checkpatch_filter = [
('ath11k_read_simulate_fw_crash', 'LONG_LINE'),
('qmi_wlanfw_respond_mem_req_msg_v01', 'LONG_LINE'),
('DEFINE_EVENT', 'MACRO_ARG_UNUSED'),
]
sparse_filter = [
r'warning: dubious: x & !y',
# sparse doesn't correctly handle guard()
r'warning: context imbalance in .* - wrong count at exit',
]
# global variables
logger = logging.getLogger('ath11k-check')
threads = 1
class CPWarning():
def __str__(self):
return 'CPWarning(%s, %s, %s, %s, %s)' % (self.path, self.lineno,
self.tag, self.type,
self.msg)
def __init__(self):
self.path = ''
self.lineno = ''
self.type = ''
self.msg = ''
self.tag = ''
def run_gcc(args):
# to disable utf-8 from gcc, easier to paste that way
os.environ['LC_CTYPE'] = 'C'
cmd = 'rm -f %s/*.o' % (DRIVER_DIR)
logger.debug('%s' % cmd)
subprocess.call(cmd, shell=True, universal_newlines=True)
cmd = ['make', '-k', '-j', str(threads)]
if not args.no_extra:
cmd.append('W=1')
cmd.append(DRIVER_DIR)
env = os.environ.copy()
# disable ccache in case it's in use, it's useless as we are
# compiling only few files and it also breaks GCC's
# -Wimplicit-fallthrough check
env['CCACHE_DISABLE'] = '1'
logger.debug('%s' % cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=env, universal_newlines=True)
(stdout, stderr) = p.communicate()
stderr = stderr.strip()
if len(stderr) > 0:
for line in stderr.splitlines():
match = re.search(FILTER_REGEXP, line)
if not args.no_filter and not match:
logger.debug('FILTERED: %s' % line)
continue
print(line.strip())
return p.returncode
def run_sparse(args):
cmd = ['make', '-k', '-j',
str(threads), DRIVER_DIR, 'C=2', 'CF="-D__CHECK_ENDIAN__"']
logger.debug('%s' % cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
(stdout, stderr) = p.communicate()
stderr = stderr.strip()
if len(stderr) > 0:
for line in stderr.splitlines():
match = re.search(FILTER_REGEXP, line)
if not args.no_filter and not match:
logger.debug('FILTERED: %s' % line)
continue
drop = False
for f in sparse_filter:
match = re.search(f, line)
if not args.no_filter and match:
logger.debug('sparse_filter: %s' % line)
drop = True
break
if not drop:
print(line.strip())
return p.returncode
def find_tagname(tag_map, filename, lineno):
if filename.find('Kconfig') != -1:
return None
if filename not in tag_map:
return None
# we need the tags sorted per linenumber
sorted_tags = sorted(tag_map[filename], key=lambda tup: tup[0])
lineno = int(lineno)
prev = None
# find the tag which is in lineno
for (l, tag) in sorted_tags:
if l > lineno:
return prev
prev = tag
return None
def parse_checkpatch_warning(line):
m = re.match(r'(.*?):(\d+): .*?:(.*?): (.*)', line, re.M | re.I)
result = CPWarning()
result.path = m.group(1)
result.lineno = m.group(2)
result.type = m.group(3)
result.msg = m.group(4)
return result
def is_filtered(cpwarning):
if cpwarning.tag is None:
return False
for (tag, type) in checkpatch_filter:
matchobj = re.match(tag, cpwarning.tag)
if matchobj is None:
continue
if cpwarning.type == type:
return True
return False
def get_checkpatch_md5sum():
path = shutil.which('checkpatch.pl')
f = open(path, 'rb')
md5sum = hashlib.md5(f.read()).hexdigest()
f.close()
return md5sum
def get_checkpatch_cmdline():
return ['checkpatch.pl'] + CHECKPATCH_OPTS + \
['--ignore', ",".join(CHECKPATCH_IGNORE)]
def run_checkpatch_cmd(args, q, tag_map):
checkpatch_cmd = get_checkpatch_cmdline() + ['-f']
while True:
try:
f = q.get_nowait()
except queue.Empty:
# no more files to check
break
cmd = checkpatch_cmd + [f]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
(stdoutdata, stderrdata) = p.communicate()
if stdoutdata is None:
continue
lines = stdoutdata.splitlines()
for line in lines:
w = parse_checkpatch_warning(line)
w.tag = find_tagname(tag_map, f, w.lineno)
if not args.no_filter and is_filtered(w):
logger.debug('FILTERED: %s' % w)
continue
logger.debug(w)
print('%s:%s: %s' % (w.path, w.lineno, w.msg))
q.task_done()
def run_checkpatch(args):
md5sum = get_checkpatch_md5sum()
if md5sum != CHECKPATCH_MD5SUM:
print('WARNING: checkpatch.pl md5sum %s does not match with %s' %
(md5sum, CHECKPATCH_MD5SUM))
# get all files which need to be checked
cmd = 'git ls-tree HEAD %s | cut -f 2' % (DRIVER_DIR)
output = subprocess.check_output(cmd, shell=True, universal_newlines=True)
driver_files = output.splitlines()
# drop files we need to ignore
for name in IGNORE_FILES:
full_name = '%s%s' % (DRIVER_DIR, name)
if full_name in driver_files:
driver_files.remove(full_name)
logger.debug('driver_files: %s' % (driver_files))
# create global index file
(fd, tmpfilename) = tempfile.mkstemp()
f = os.fdopen(fd, 'w')
f.write('\n'.join(driver_files))
f.close()
# FIXME: do we need to call os.close(fd) still?
cmd = 'gtags -f %s' % (tmpfilename)
logger.debug('%s' % (cmd))
output = subprocess.check_output(cmd, shell=True, universal_newlines=True)
os.remove(tmpfilename)
# tag_map[FILENAME] = [(start line, tagname)]
tag_map = {}
# create tag mapping
for f in driver_files:
# global gives an error from Kconfig and Makefile
if f.endswith('Kconfig') or f.endswith('Makefile'):
continue
cmd = 'global -f %s' % (f)
output = subprocess.check_output(cmd, shell=True, universal_newlines=True)
lines = output.splitlines()
for l in lines:
columns = l.split()
tagname = columns[0]
line = int(columns[1])
if f not in tag_map:
tag_map[f] = []
tag_map[f].append((line, tagname))
q = queue.Queue()
for f in driver_files:
q.put(f)
# run checkpatch for all files
for i in range(threads):
t = threading.Thread(
target=run_checkpatch_cmd, args=(args, q, tag_map))
t.daemon = True
t.start()
q.join()
return 0
def show_version(args):
gcc_version = 'not found'
sparse_version = 'not found'
checkpatch_version = 'not found'
checkpatch_md5sum = 'N/A'
gtags_version = 'not found'
run = subprocess.check_output
f = open(sys.argv[0], 'rb')
ath11kcheck_md5sum = hashlib.md5(f.read()).hexdigest()
f.close()
try:
gcc_version = run(['gcc', '--version'],
universal_newlines=True).splitlines()[0]
except:
pass
try:
sparse_version = run(['sparse', '--version'],
universal_newlines=True).splitlines()[0]
except:
pass
try:
checkpatch_version = run(['checkpatch.pl', '--version'],
universal_newlines=True).splitlines()[1]
checkpatch_md5sum = get_checkpatch_md5sum()
except:
pass
try:
gtags_version = run(['gtags', '--version'],
universal_newlines=True).splitlines()[0]
except:
pass
print('ath11k-check (md5sum %s)' % (ath11kcheck_md5sum))
print()
print('python:\t\t%s' % (sys.version))
print('gcc:\t\t%s' % (gcc_version))
print('sparse:\t\t%s' % (sparse_version))
print('checkpatch.pl:\t%s (md5sum %s)' % (checkpatch_version, checkpatch_md5sum))
print('gtags:\t\t%s' % (gtags_version))
sys.exit(0)
def main():
global threads
checkpatch_url = GIT_URL % (CHECKPATCH_COMMIT)
description = '''ath11k source code checker
Runs various tests (gcc, sparse and checkpatch) with filtering
unnecessary warnings away, the goal is to have empty output from the
script.
Run this from the main kernel source directory which is preconfigured
with ath11k enabled. gcc recompilation is forced every time,
irrespective if there are any changes in source or not. So this can be
run multiple times and every time the same warnings will appear.
Requirements (all available in $PATH):
* gcc
* sparse
* checkpatch.pl
* gtags (from package global)
'''
s = '''Installation:
As checkpatch is evolving this script always matches a certain version
of checkpatch. Download the checkpatch version from the URL below and
install it somewhere in your $$PATH:
$CHECKPATCH_URL
Alternatively if you want manually run checkpatch with the same
settings as ath11k-check uses here's the command line:
$CHECKPATCH_CMDLINE
'''
checkpatch_cmdline = '%s foo.patch' % ' '.join(get_checkpatch_cmdline())
epilog = string.Template(s).substitute(CHECKPATCH_URL=checkpatch_url,
CHECKPATCH_CMDLINE=checkpatch_cmdline)
parser = argparse.ArgumentParser(description=description, epilog=epilog,
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-d', '--debug', action='store_true',
help='enable debug messages')
parser.add_argument('--fast', action='store_true',
help='run only tests which finish in few seconds')
parser.add_argument('--no-extra', action='store_true',
help='Do not run extra checks like W=1')
parser.add_argument('--no-filter', action='store_true',
help='Don\'t filter output with regexp: %r' % (FILTER_REGEXP))
parser.add_argument('--version', action='store_true',
help='Show version information about dependencies')
args = parser.parse_args()
timefmt = ''
if args.debug:
logger.setLevel(logging.DEBUG)
timefmt = '%(asctime)s '
logfmt = '%s%%(levelname)s: %%(message)s' % (timefmt)
logging.basicConfig(format=logfmt)
if args.version:
show_version(args)
if args.fast:
gcc = True
sparse = True
checkpatch = False
else:
gcc = True
sparse = True
checkpatch = True
try:
cores = subprocess.check_output(['nproc'], universal_newlines=True)
except OSError as xxx_todo_changeme:
subprocess.CalledProcessError = xxx_todo_changeme
cores = '4'
logger.warning('Failed to run nproc, assuming %s cores' % (cores))
threads = int(cores) + 2
logger.debug('threads %d' % (threads))
if gcc:
ret = run_gcc(args)
if ret != 0:
logger.debug('gcc failed: %d', ret)
sys.exit(1)
if sparse:
ret = run_sparse(args)
if ret != 0:
logger.debug('sparse failed: %d', ret)
sys.exit(2)
if checkpatch:
ret = run_checkpatch(args)
if ret != 0:
logger.debug('checkpatch failed: %d', ret)
sys.exit(3)
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,684 @@
#!/usr/bin/python3
#
# Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
# Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import ctypes
import struct
import optparse
import time
import math
import logging
import sys
import os.path
import traceback
import binascii
import tempfile
import subprocess
import hashlib
DEFAULT_FW_API_VERSION = 2
ATH11K_SIGNATURE = b'QCOM-ATH11K-FW'
MAX_LEN = 50000000
ATH11K_FW_IE_TIMESTAMP = 0
ATH11K_FW_IE_FEATURES = 1
ATH11K_FW_IE_AMSS_IMAGE = 2
ATH11K_FW_IE_M3_IMAGE = 3
# enum ath11k_fw_features from ath11k/fw.h
ATH11K_FW_FEATURE_MAX = 1
feature_map = {
}
# global variables
logger = None
class FWEncoderError(Exception):
pass
def get_output_name(fw_api=None):
if fw_api is not None:
api = fw_api
else:
api = DEFAULT_FW_API_VERSION
return 'firmware-%s.bin' % api
class FirmwareContainer:
def add_element(self, type_id, value):
length = len(value)
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, 0x77)
logger.debug('adding id %d len(value) %d'
'padding_len %d' % (type_id,
len(value),
padding_len))
fmt = '<ii%ds%ds' % (len(value), padding_len)
struct.pack_into(fmt, self.buf, self.buf_len, type_id, len(value),
value, padding.raw)
self.buf_len = self.buf_len + 4 + 4 + len(value) + padding_len
def add_u32(self, type_id, value):
if not type(value) is int:
raise FWEncoderError('u32 IE %d is not int: %s' %
(type_id, str(value)))
buf = ctypes.create_string_buffer(4)
struct.pack_into("<i", buf, 0, value)
self.add_element(type_id, buf.raw)
def read_u32(self, type_id):
(val,) = struct.unpack_from("<i", self.elements[type_id])
return val
def add_bitmap(self, ie, enabled, maximum):
if (max(enabled) >= maximum):
logger.error("bitmap %d out of maximum (%d >= %d)" %
(ie, max(enabled), maximum))
return
bytes = [0] * maximum
for i in range(maximum):
if i not in enabled:
continue
max_set = i
index = i / 8
bit = i % 8
bytes[index] = bytes[index] | (1 << bit)
# remove trailing null bits away, that changing only
# maximum doesn't affect created binary size
length = int(math.ceil((max_set + 1) / float(8)))
bytes = bytes[:length]
buf = ctypes.create_string_buffer(length)
for index in range(length):
struct.pack_into('<B', buf, index, bytes[index])
self.add_element(ie, buf.raw)
def read_bitmap(self, ie):
buf = self.elements[ie]
length = len(buf)
bits = []
for index in range(length):
val = struct.unpack_from('<B', buf, index)[0]
for bit in range(8):
if val & 0x1:
bits.append(index * 8 + bit)
val = val >> 1
return bits
def set_signature(self, signature):
self.signature = signature
self.signature_len = len(signature)
# include the null byte
length = len(signature) + 1
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, 0x77)
fmt = '<%dsb%ds' % (len(signature), padding_len)
struct.pack_into(fmt, self.buf, 0, signature, 0, padding.raw)
self.buf_len = length
def write(self, name):
f = open(name, 'wb')
f.write(self.buf.raw[:self.buf_len])
f.close()
return self.buf_len
def open(self, name):
f = open(name, 'rb')
self.buf = f.read()
self.buf_len = len(self.buf)
f.close()
offset = 0
fmt = '<%dsb' % (self.signature_len)
(signature, null) = struct.unpack_from(fmt, self.buf, offset)
offset = offset + self.signature_len + 1
if signature != self.signature or null != 0:
logger.error("Invalid signature!")
return False
offset = self.signature_len + 1
offset = offset + padding_needed(offset)
self.elements = {}
while offset + 4 + 4 < self.buf_len:
(type_id, length) = struct.unpack_from("<ii", self.buf, offset)
offset = offset + 4 + 4
if offset + length > self.buf_len:
logger.error("Buffer too short")
return
fmt = '<%ds' % length
(payload,) = struct.unpack_from(fmt, self.buf, offset)
offset = offset + length
offset = offset + padding_needed(offset)
self.elements[type_id] = payload
return True
def __init__(self, signature):
self.buf = ctypes.create_string_buffer(MAX_LEN)
self.buf_len = 0
self.set_signature(signature)
class Ath11kFirmwareContainer(object):
def _load_file(self, name):
if os.path.getsize(name) > MAX_LEN:
raise FWEncoderError('file %s is too large, maximum size is %d' %
(name, MAX_LEN))
f = open(name, 'rb')
buf = f.read()
f.close()
return buf
def set_features(self, features):
self.features = features.split(',')
enabled = []
for capa in self.features:
if capa not in feature_map:
print("Error: '%s' not found from the feature map" % capa)
return 1
enabled.append(feature_map[capa])
self.features_bitmap = enabled
def get_features(self):
s = ""
if self.features_bitmap is None:
return None
for capa in self.features_bitmap:
# find value from the dict
try:
name = [key for key, value in feature_map.items()
if value == capa][0]
except IndexError:
name = str(capa)
s = s + name + ","
# strip last comma
if len(s) > 0:
s = s[:-1]
return s
def set_amss_image(self, amss_image_name):
self.amss_image = self._load_file(amss_image_name)
def get_amss_image(self):
return self.amss_image
def set_m3_image(self, m3_image_name):
self.m3_image = self._load_file(m3_image_name)
def get_m3_image(self):
return self.m3_image
def set_timestamp(self, timestamp):
self.timestamp = int(timestamp)
def get_timestamp(self):
return self.timestamp
def get_timestamp_as_iso8601(self):
if self.timestamp is None:
return None
return time.strftime('%Y-%m-%d %H:%M:%S',
time.gmtime(self.timestamp))
def get_summary(self):
s = ''
s = s + 'FileSize: %s\n' % (len(self.file))
s = s + 'FileCRC32: %08x\n' % (_crc32(self.file))
s = s + 'FileMD5: %s\n' % (hashlib.md5(self.file).hexdigest())
if self.get_timestamp():
s = s + 'Timestamp: %s\n' % (self.get_timestamp_as_iso8601())
if self.get_features():
s = s + 'Features: %s\n' % (self.get_features())
if self.get_amss_image():
s = s + 'AMSSImageSize: %s\n' % (len(self.get_amss_image()))
s = s + 'AMSSImageCRC32: %08x\n' % (_crc32(self.get_amss_image()))
if self.get_m3_image():
s = s + 'M3ImageSize: %s\n' % (len(self.get_m3_image()))
s = s + 'M3ImageCRC32: %08x\n' % (_crc32(self.get_m3_image()))
return s.strip()
def load(self, filename):
c = FirmwareContainer(ATH11K_SIGNATURE)
c.open(filename)
self.file = c.buf
for e in c.elements:
if e == ATH11K_FW_IE_TIMESTAMP:
self.timestamp = c.read_u32(e)
elif e == ATH11K_FW_IE_M3_IMAGE:
self.m3_image = c.elements[e]
elif e == ATH11K_FW_IE_AMSS_IMAGE:
self.amss_image = c.elements[e]
elif e == ATH11K_FW_IE_FEATURES:
self.features_bitmap = c.read_bitmap(ATH11K_FW_IE_FEATURES)
else:
print("Unknown IE: ", e)
def save(self, filename):
self.container = FirmwareContainer(ATH11K_SIGNATURE)
if self.timestamp:
self.container.add_u32(ATH11K_FW_IE_TIMESTAMP, self.timestamp)
# FIXME: m3 should be after amss_image but that breaks the
# current tests
if self.m3_image:
self.container.add_element(ATH11K_FW_IE_M3_IMAGE, self.m3_image)
if self.amss_image:
self.container.add_element(ATH11K_FW_IE_AMSS_IMAGE, self.amss_image)
# FIXME: features should be before amss_image but that breaks
# the current tests
if self.features_bitmap:
self.container.add_bitmap(ATH11K_FW_IE_FEATURES,
self.features_bitmap,
ATH11K_FW_FEATURE_MAX)
return self.container.write(filename)
def __init__(self):
self.timestamp = None
self.features = None
self.features_bitmap = None
self.amss_image = None
self.m3_image = None
# to workaround annoying python feature of returning negative hex values
def hex32(val):
return val & 0xffffffff
# match with kernel crc32_le(0, buf, buf_len) implementation
def _crc32(buf):
return hex32(~(hex32(binascii.crc32(buf, 0xffffffff))))
def padding_needed(length):
if length % 4 != 0:
return 4 - length % 4
return 0
def is_int(val):
try:
int(val)
return True
except ValueError:
return False
def write_file(filename, buf):
f = open(filename, 'wb')
f.write(buf)
f.close
def info(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath11kFirmwareContainer()
c.load(filename)
print(c.get_summary())
def dump(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath11kFirmwareContainer()
c.load(filename)
print("ath11k-fwencoder --create \\")
if c.get_timestamp() and options.show_timestamp:
print("--timestamp=%u \\" % c.get_timestamp())
if c.get_features():
print("--features=%s \\" % c.get_features())
if c.get_amss_image():
name = "amss.bin"
print("--amss=%s \\" % name)
if c.get_m3_image():
name = "m3.bin"
print("--m3=%s \\" % name)
print()
def extract(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath11kFirmwareContainer()
c.load(filename)
if c.get_amss_image():
name = "amss.bin"
write_file(name, c.get_amss_image())
print('%s extracted: %d B' % (name, len(c.get_amss_image())))
if c.get_m3_image():
name = "m3.bin"
write_file(name, c.get_m3_image())
print('%s extracted: %d B' % (name, len(c.get_m3_image())))
print()
def modify(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath11kFirmwareContainer()
c.load(filename)
if options.timestamp:
stamp = str(int(options.timestamp))
else:
# if no timestamp provided use the current time so that the
# timestamp shows the time of last modication
stamp = int(time.time())
c.set_timestamp(stamp)
if options.m3:
c.set_m3_image(options.m3)
if options.amss:
c.set_amss_image(options.amss)
if options.features:
c.set_features(options.features)
file_len = c.save(filename)
print('%s modified: %d B' % (filename, file_len))
def create(options):
output = get_output_name(options.fw_api)
if options.output:
output = options.output
c = Ath11kFirmwareContainer()
# always add a timestamp
if options.timestamp:
stamp = int(options.timestamp)
else:
stamp = int(time.time())
c.set_timestamp(stamp)
if options.m3:
c.set_m3_image(options.m3)
if options.amss:
c.set_amss_image(options.amss)
if options.features:
c.set_features(options.features)
file_len = c.save(output)
print('%s created: %d B' % (output, file_len))
def cmd_crc32(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
f = open(filename, 'rb')
buf = f.read()
print('%08x' % (_crc32(buf)))
f.close()
def cmd_diff(options, args):
if len(args) != 2:
print('Usage: ath11k-fwencoder --diff FILE FILE')
return 1
filename1 = args[0]
filename2 = args[1]
c1 = Ath11kFirmwareContainer()
c1.load(filename1)
(temp1_fd, temp1_pathname) = tempfile.mkstemp(text=True)
# for some reason text=True is not working with mkstemp() so open
# the file manually
f = open(temp1_pathname, 'w')
f.write(c1.get_summary())
f.close()
c2 = Ath11kFirmwareContainer()
c2.load(filename2)
(temp2_fd, temp2_pathname) = tempfile.mkstemp(text=True)
# for some reason text=True is not working with mkstemp() so open
# the file manually
f = open(temp2_pathname, 'w')
f.write(c2.get_summary())
f.close()
# '--less-mode' and '--auto-page' would be nice when running on
# terminal but don't know how to get the control character
# through. For terminal detection sys.stdout.isatty() can be used.
cmd = ['wdiff', temp1_pathname, temp2_pathname]
# wdiff is braindead and returns 1 in a succesfull case
try:
output = subprocess.check_output(cmd, universal_newlines=True)
except subprocess.CalledProcessError as e:
if e.returncode == 1:
output = e.output
else:
logger.error('Failed to run wdiff: %d\n%s' % (e.returncode, e.output))
return 1
except OSError as e:
logger.error('Failed to run wdiff: %s' % (e))
return 1
print(output)
os.close(temp1_fd)
os.close(temp2_fd)
def main():
global logger
logger = logging.getLogger('ath11k-fwencoder')
logging.basicConfig(format='%(levelname)s: %(message)s')
parser = optparse.OptionParser()
# actions
parser.add_option("-c", "--create", action="store_true", dest="create",
help='Create container file '
'for ath11k (%s)' % get_output_name())
parser.add_option("-D", "--dump-cmdline", action="store_true", dest="dump",
help='Show the cmdline used to create '
'this container file')
parser.add_option('--dump', action='store_true', dest='dump',
help='Same as --dump-cmdline '
'(for backwards compatibility)')
parser.add_option("-e", "--extract", action="store_true", dest="extract",
help='Extract binary files from the container file '
'and dump cmdline as well')
parser.add_option("--info", action="store_true", dest="info",
help='Show information about the container file')
parser.add_option("--modify", action="store_true", dest="modify",
help='Modify the container file')
parser.add_option('--crc32', action='store_true', dest='crc32',
help='Count crc32 checksum for a file')
parser.add_option('--diff', action='store_true', dest='diff',
help='Show differences between two firmware files')
# parameters
parser.add_option("-o", "--output", action="store", type="string",
dest="output", help='Name of output file')
# FW IEs, only use long style of option names!
parser.add_option("--m3", action="store", type="string",
dest="m3",
help='Name of m3.bin file')
parser.add_option("--amss", action="store", type="string",
dest="amss",
help='Name of amss.bin file')
parser.add_option("--timestamp", action="store",
type="string", dest="timestamp",
help='Timestamp to be used (seconds)')
parser.add_option("--features", action="store",
type="string", dest="features",
help='feature bits to be enabled: %s' %
list(feature_map.keys()))
parser.add_option("--set-fw-api", action="store",
type="string", dest="fw_api",
help='Set firmware API used in creating the name for '
'output file (Default: %s)' %
DEFAULT_FW_API_VERSION)
# debug etc
parser.add_option('--show-timestamp', action='store_true',
dest='show_timestamp',
help='Show timestamp in --dump-cmdline action. '
'It is not shown by default so that the timestamp would be correct')
parser.add_option('-d', '--debug', action='store_true', dest='debug',
help='Enable debug messages')
(options, args) = parser.parse_args()
if options.debug:
logger.setLevel(logging.DEBUG)
if options.create:
try:
return create(options)
except FWEncoderError as e:
print('Create failed: %s' % e)
sys.exit(2)
except Exception as e:
print('Create failed: %s' % e)
traceback.print_exc()
sys.exit(3)
elif options.dump:
return dump(options, args)
elif options.extract:
return extract(options, args)
elif options.info:
return info(options, args)
elif options.modify:
return modify(options, args)
elif options.crc32:
return cmd_crc32(options, args)
elif options.diff:
return cmd_diff(options, args)
else:
print('Action command missing')
return 1
if __name__ == "__main__":
main()

View file

@ -0,0 +1,862 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2017 Qualcomm Atheros, Inc.
# Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Run 'ath12k-bdencoder --help' to see the instructions
#
import struct
import ctypes
import os.path
import argparse
import json
import binascii
import hashlib
import tempfile
import subprocess
import logging
import sys
import shutil
MAX_BUF_LEN = 3000000
# the signature length also includes null byte and padding
ATH12K_BOARD_SIGNATURE = b"QCA-ATH12K-BOARD"
ATH12K_BOARD_SIGNATURE_LEN = 20
PADDING_MAGIC = 0x6d
DEFAULT_BD_API = 2
DEFAULT_BOARD_FILE = 'board-%d.bin' % DEFAULT_BD_API
DEFAULT_JSON_FILE = 'board-%d.json' % DEFAULT_BD_API
TYPE_LENGTH_SIZE = 8
ATH12K_BD_IE_BOARD = 0
ATH12K_BD_IE_REGDB = 1
ATH12K_BD_IE_BOARD_NAME = 0
ATH12K_BD_IE_BOARD_DATA = 1
ATH12K_BD_IE_REGDB_NAME = 0
ATH12K_BD_IE_REGDB_DATA = 1
def padding_needed(len):
if len % 4 != 0:
return 4 - len % 4
return 0
def add_ie(buf, offset, id, value):
length = len(value)
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, PADDING_MAGIC)
fmt = '<2i%ds%ds' % (len(value), padding_len)
struct.pack_into(fmt, buf, offset, id, len(value), value, padding.raw)
offset = offset + TYPE_LENGTH_SIZE + len(value) + padding_len
return offset
# to workaround annoying python feature of returning negative hex values
def hex32(val):
return val & 0xffffffff
# match with kernel crc32_le(0, buf, buf_len) implementation
def _crc32(buf):
return hex32(~(hex32(binascii.crc32(buf, 0xffffffff))))
def pretty_array_str(array):
return '\',\''.join(array)
class RegdbName():
@staticmethod
def parse_ie(buf, offset, length):
self = RegdbName()
fmt = '<%ds' % length
(name, ) = struct.unpack_from(fmt, buf, offset)
self.name = name.decode()
logging.debug('RegdbName.parse_ie(): offset %d length %d self %s' %
(offset, length, self))
return self
def add_to_buf(self, buf, offset):
return add_ie(buf, offset, ATH12K_BD_IE_REGDB_NAME, self.name.encode())
def __eq__(self, other):
return self.name == other.name
def __repr__(self):
return self.__str__()
def __str__(self):
return 'RegdbName(%s)' % self.name
def __init__(self, name=None):
self.name = name
class RegdbData():
@staticmethod
def parse_ie(buf, offset, length):
self = RegdbData()
fmt = '<%ds' % length
(self.data, ) = struct.unpack_from(fmt, buf, offset)
logging.debug('RegdbData.parse_ie(): offset %d length %d self %s' %
(offset, length, self))
return self
def add_to_buf(self, buf, offset):
return add_ie(buf, offset, ATH12K_BD_IE_REGDB_DATA, self.data)
def __repr__(self):
return self.__str__()
def __str__(self):
if self.data is not None:
s = '%d B' % (len(self.data))
else:
s = 'n/a'
return 'RegdbData(%s)' % (s)
def __init__(self, data=None):
self.data = data
class Regdb():
@staticmethod
def parse_ie(buf, offset, length):
logging.debug('Regdb.parse_ie(): offset %d length %d' % (offset, length))
self = Regdb()
# looping regdb IEs
while length > 0:
(ie_id, ie_len) = struct.unpack_from('<2i', buf, offset)
logging.debug('Regdb.parse_ie(): found ie_id %d ie_len %d offset %d length %d' %
(ie_id, ie_len, offset, length))
if TYPE_LENGTH_SIZE + ie_len > length:
raise Exception('Error: ie_len too big (%d > %d)' % (ie_len,
length))
offset += TYPE_LENGTH_SIZE
length -= TYPE_LENGTH_SIZE
if ie_id == ATH12K_BD_IE_REGDB_NAME:
self.names.append(RegdbName.parse_ie(buf, offset, ie_len))
elif ie_id == ATH12K_BD_IE_REGDB_DATA:
self.data = RegdbData.parse_ie(buf, offset, ie_len)
offset += ie_len + padding_needed(ie_len)
length -= ie_len + padding_needed(ie_len)
return self
def add_to_buf(self, buf, offset):
# store position ie header of this element
ie_offset = offset
offset += TYPE_LENGTH_SIZE
for name in self.names:
offset = name.add_to_buf(buf, offset)
offset = self.data.add_to_buf(buf, offset)
# write ie header as now we know the full length
ie_len = offset - ie_offset - TYPE_LENGTH_SIZE
struct.pack_into('<2i', buf, ie_offset, ATH12K_BD_IE_REGDB, ie_len)
return offset
def get_names_as_str(self):
names = []
for regdbname in self.names:
names.append(regdbname.name)
return names
def __repr__(self):
return self.__str__()
def __str__(self):
names = []
for regdbname in self.names:
names.append(str(regdbname))
return 'Regdb(%s, %s)' % (','.join(names), self.data)
def __init__(self):
self.data = None
self.names = []
class BoardName():
@staticmethod
def parse_ie(buf, offset, length):
self = BoardName()
fmt = '<%ds' % length
(name, ) = struct.unpack_from(fmt, buf, offset)
self.name = name.decode()
logging.debug('BoardName.parse_ie(): offset %d length %d self %s' %
(offset, length, self))
return self
def add_to_buf(self, buf, offset):
return add_ie(buf, offset, ATH12K_BD_IE_BOARD_NAME, self.name.encode())
def __eq__(self, other):
return self.name == other.name
def __repr__(self):
return self.__str__()
def __str__(self):
return 'BoardName(%s)' % self.name
def __init__(self, name=None):
self.name = name
class BoardData():
@staticmethod
def parse_ie(buf, offset, length):
self = BoardData()
fmt = '<%ds' % length
(self.data, ) = struct.unpack_from(fmt, buf, offset)
logging.debug('BoardData.parse_ie(): offset %d length %d self %s' %
(offset, length, self))
return self
def add_to_buf(self, buf, offset):
return add_ie(buf, offset, ATH12K_BD_IE_BOARD_DATA, self.data)
def __repr__(self):
return self.__str__()
def __str__(self):
if self.data is not None:
s = '%d B' % (len(self.data))
else:
s = 'n/a'
return 'BoardData(%s)' % (s)
def __init__(self, data=None):
self.data = data
class Board():
@staticmethod
def parse_ie(buf, offset, length):
logging.debug('Board.parse_ie(): offset %d length %d' % (offset, length))
self = Board()
# looping board IEs
while length > 0:
(ie_id, ie_len) = struct.unpack_from('<2i', buf, offset)
logging.debug('Board.parse_ie(): found ie_id %d ie_len %d offset %d length %d' %
(ie_id, ie_len, offset, length))
if TYPE_LENGTH_SIZE + ie_len > length:
raise Exception('Error: ie_len too big (%d > %d)' % (ie_len,
length))
offset += TYPE_LENGTH_SIZE
length -= TYPE_LENGTH_SIZE
if ie_id == ATH12K_BD_IE_BOARD_NAME:
self.names.append(BoardName.parse_ie(buf, offset, ie_len))
elif ie_id == ATH12K_BD_IE_BOARD_DATA:
self.data = BoardData.parse_ie(buf, offset, ie_len)
offset += ie_len + padding_needed(ie_len)
length -= ie_len + padding_needed(ie_len)
return self
def add_to_buf(self, buf, offset):
# store position ie header of this element
ie_offset = offset
offset += TYPE_LENGTH_SIZE
for name in self.names:
offset = name.add_to_buf(buf, offset)
offset = self.data.add_to_buf(buf, offset)
# write ie header as now we know the full length
ie_len = offset - ie_offset - TYPE_LENGTH_SIZE
struct.pack_into('<2i', buf, ie_offset, ATH12K_BD_IE_BOARD, ie_len)
return offset
def get_names_as_str(self):
names = []
for boardname in self.names:
names.append(boardname.name)
return names
def __repr__(self):
return self.__str__()
def __str__(self):
names = []
for boardname in self.names:
names.append(str(boardname))
return 'Board(%s, %s)' % (','.join(names), self.data)
def __init__(self):
self.data = None
self.names = []
class BoardContainer:
def add_board(self, data, names):
boardnames = []
for name in names:
boardnames.append(BoardName(name))
board = Board()
board.data = BoardData(data)
board.names = boardnames
self.boards.append(board)
def add_regdb(self, data, names):
regdbnames = []
for name in names:
regdbnames.append(RegdbName(name))
regdb = Regdb()
regdb.data = RegdbData(data)
regdb.names = regdbnames
self.regdbs.append(regdb)
@staticmethod
def open_json(filename):
self = BoardContainer()
if not os.path.exists(filename):
print('mapping file %s not found' % (filename))
return
f = open(filename, 'r')
mapping = json.loads(f.read())
f.close()
if 'board' in mapping[0]:
for b in mapping[0]['board']:
board_filename = b['data']
f = open(board_filename, 'rb')
data = f.read()
f.close()
self.add_board(data, b['names'])
if 'regdb' in mapping[0]:
for b in mapping[0]['regdb']:
regdb_filename = b['data']
f = open(regdb_filename, 'rb')
data = f.read()
f.close()
self.add_regdb(data, b['names'])
return self
def validate(self):
allnames = []
for board in self.boards:
for name in board.names:
if name in allnames:
# TODO: Find a better way to report problems,
# maybe return a list of strings? Or use an
# exception?
print('Warning: duplicate board name: %s' % (name.name))
return
allnames.append(name)
def _add_signature(self, buf, offset):
signature = ATH12K_BOARD_SIGNATURE + b'\0'
length = len(signature)
pad_len = padding_needed(length)
length = length + pad_len
padding = ctypes.create_string_buffer(pad_len)
for i in range(pad_len):
struct.pack_into('<B', padding, i, PADDING_MAGIC)
fmt = '<%ds%ds' % (len(signature), pad_len)
struct.pack_into(fmt, buf, offset, signature, padding.raw)
offset += length
# make sure ATH12K_BOARD_SIGNATURE_LEN is correct
assert ATH12K_BOARD_SIGNATURE_LEN == length
return offset
@staticmethod
def open(name):
self = BoardContainer()
f = open(name, 'rb')
buf = f.read()
f.close()
buf_len = len(buf)
logging.debug('BoardContainer.open(): name %s' % (name))
offset = 0
fmt = '<%dsb' % (len(ATH12K_BOARD_SIGNATURE))
(signature, null) = struct.unpack_from(fmt, buf, offset)
if signature != ATH12K_BOARD_SIGNATURE or null != 0:
print("invalid signature found in %s" % name)
return 1
offset += ATH12K_BOARD_SIGNATURE_LEN
# looping main IEs
while offset < buf_len:
(ie_id, ie_len) = struct.unpack_from('<2i', buf, offset)
logging.debug('BoardContainer.open(): found offset %d ie_id %d ie_len %d' %
(offset, ie_id, ie_len))
offset += TYPE_LENGTH_SIZE
if offset + ie_len > buf_len:
print('Error: Buffer too short (%d + %d > %d)' % (offset,
ie_len,
buf_len))
return 1
if ie_id == ATH12K_BD_IE_BOARD:
self.boards.append(Board.parse_ie(buf, offset, ie_len))
elif ie_id == ATH12K_BD_IE_REGDB:
self.regdbs.append(Regdb.parse_ie(buf, offset, ie_len))
offset += ie_len + padding_needed(ie_len)
self.validate()
return self
def write(self, name):
(buf, buf_len) = self.get_bin()
fd = open(name, 'wb')
fd.write(buf.raw[0:buf_len])
fd.close()
self.validate()
print("board binary file '%s' is created" % name)
def get_bin(self):
buf = ctypes.create_string_buffer(MAX_BUF_LEN)
offset = 0
offset = self._add_signature(buf, offset)
for board in self.boards:
offset = board.add_to_buf(buf, offset)
for regdb in self.regdbs:
offset = regdb.add_to_buf(buf, offset)
# returns buffer and it's length
return buf, offset
def get_summary(self, sort=False):
(buf, buf_len) = self.get_bin()
s = ''
s += 'FileSize: %d\n' % (buf_len)
s += 'FileCRC32: %08x\n' % (_crc32(buf[0:buf_len]))
s += 'FileMD5: %s\n' % (hashlib.md5(buf[0:buf_len]).hexdigest())
boards = self.boards
if sort:
boards = sorted(boards, key=lambda board: board.get_names_as_str())
index = 0
for board in boards:
if not sort:
index_s = '[%d]' % (index)
else:
index_s = ''
s += 'BoardNames%s: \'%s\'\n' % (index_s, pretty_array_str(board.get_names_as_str()))
s += 'BoardLength%s: %d\n' % (index_s, len(board.data.data))
s += 'BoardCRC32%s: %08x\n' % (index_s, _crc32(board.data.data))
s += 'BoardMD5%s: %s\n' % (index_s, hashlib.md5(board.data.data).hexdigest())
index += 1
regdbs = self.regdbs
if sort:
regdbs = sorted(regdbs, key=lambda regdb: regdb.get_names_as_str())
index = 0
for regdb in regdbs:
if not sort:
index_s = '[%d]' % (index)
else:
index_s = ''
s += 'RegdbNames%s: \'%s\'\n' % (index_s, pretty_array_str(regdb.get_names_as_str()))
s += 'RegdbLength%s: %d\n' % (index_s, len(regdb.data.data))
s += 'RegdbCRC32%s: %08x\n' % (index_s, _crc32(regdb.data.data))
s += 'RegdbMD5%s: %s\n' % (index_s, hashlib.md5(regdb.data.data).hexdigest())
index += 1
return s
def __init__(self):
self.boards = []
self.regdbs = []
def cmd_extract(args):
cont = BoardContainer().open(args.extract)
mapping = []
d = {}
mapping.append(d)
mapping_board = []
d['board'] = mapping_board
for board in cont.boards:
filename = board.names[0].name + '.bin'
b = {}
b['names'] = board.get_names_as_str()
b['data'] = filename
mapping_board.append(b)
f = open(filename, 'wb')
f.write(board.data.data)
f.close()
print("%s created size: %d" % (filename, len(board.data.data)))
mapping_regdb = []
d['regdb'] = mapping_regdb
for regdb in cont.regdbs:
filename = regdb.names[0].name + '.regdb'
b = {}
b['names'] = regdb.get_names_as_str()
b['data'] = filename
mapping_regdb.append(b)
f = open(filename, 'wb')
f.write(regdb.data.data)
f.close()
print("%s created size: %d" % (filename, len(regdb.data.data)))
filename = DEFAULT_JSON_FILE
f = open(filename, 'w')
f.write(json.dumps(mapping, indent=4))
f.close()
print("%s created" % (filename))
def cmd_info(args):
filename = args.info
cont = BoardContainer().open(filename)
print(cont.get_summary())
def cmd_diff(args):
if args.diff:
filename1 = args.diff[0]
filename2 = args.diff[1]
else:
filename1 = args.diffstat[0]
filename2 = args.diffstat[1]
print(diff_boardfiles(filename1, filename2, args.diff))
def diff_boardfiles(filename1, filename2, diff):
result = ''
container1 = BoardContainer().open(filename1)
(temp1_fd, temp1_pathname) = tempfile.mkstemp()
os.write(temp1_fd, container1.get_summary(sort=True).encode())
container2 = BoardContainer().open(filename2)
(temp2_fd, temp2_pathname) = tempfile.mkstemp()
os.write(temp2_fd, container2.get_summary(sort=True).encode())
# this function is used both with --diff and --diffstat
if diff:
# '--less-mode' and '--auto-page' would be nice when running on
# terminal but don't know how to get the control character
# through. For terminal detection sys.stdout.isatty() can be used.
cmd = ['wdiff', temp1_pathname, temp2_pathname]
# wdiff is braindead and returns 1 in a succesfull case
try:
output = subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
if e.returncode == 1:
output = e.output
else:
print('Failed to run wdiff: %d\n%s' % (e.returncode, e.output))
return 1
except OSError as e:
print('Failed to run wdiff: %s' % (e))
return 1
result += '%s\n' % (output.decode())
# create simple statistics about changes in board images
new_boards = {}
deleted_boards = {}
changed_boards = {}
for board in container2.boards:
# convert the list to a string
s = pretty_array_str(board.get_names_as_str())
new_boards[s] = board
for board in container1.boards:
# convert the list to a string
names = pretty_array_str(board.get_names_as_str())
if names not in new_boards:
# board image has been deleted
deleted_boards[names] = board
continue
board2 = new_boards[names]
del new_boards[names]
if board.data.data == board2.data.data:
# board image hasn't changed
continue
# board image has changed
changed_boards[names] = board2
result += 'New board:\n%s\n\n' % ('\n'.join(list(new_boards.keys())))
result += 'Changed board:\n%s\n\n' % ('\n'.join(list(changed_boards.keys())))
result += 'Deleted board:\n%s\n' % ('\n'.join(list(deleted_boards.keys())))
result += '%d board image(s) added, %d changed, %d deleted, %d in total\n\n' % (len(new_boards),
len(changed_boards),
len(deleted_boards),
len(container2.boards))
# create simple statistics about changes in regdb images
new_regdbs = {}
deleted_regdbs = {}
changed_regdbs = {}
for regdb in container2.regdbs:
# convert the list to a string
s = pretty_array_str(regdb.get_names_as_str())
new_regdbs[s] = regdb
for regdb in container1.regdbs:
# convert the list to a string
names = pretty_array_str(regdb.get_names_as_str())
if names not in new_regdbs:
# regdb image has been deleted
deleted_regdbs[names] = regdb
continue
regdb2 = new_regdbs[names]
del new_regdbs[names]
if regdb.data.data == regdb2.data.data:
# regdb image hasn't changed
continue
# regdb image has changed
changed_regdbs[names] = regdb2
result += 'New regdb:\n%s\n\n' % ('\n'.join(list(new_regdbs.keys())))
result += 'Changed regdb:\n%s\n\n' % ('\n'.join(list(changed_regdbs.keys())))
result += 'Deleted regdb:\n%s\n' % ('\n'.join(list(deleted_regdbs.keys())))
result += '%d regdb image(s) added, %d changed, %d deleted, %d in total' % (len(new_regdbs),
len(changed_regdbs),
len(deleted_regdbs),
len(container2.regdbs))
os.close(temp1_fd)
os.close(temp2_fd)
return result
def cmd_create(args):
mapping_file = args.create
if args.output:
output = args.output
else:
output = DEFAULT_BOARD_FILE
cont = BoardContainer.open_json(mapping_file)
cont.write(output)
def cmd_add_board(args):
if len(args.add_board) < 3:
print('error: --add-board requires 3 or more arguments, only %d given' % (len(args.add_board)))
sys.exit(1)
board_filename = args.add_board[0]
new_filename = args.add_board[1]
new_names = args.add_board[2:]
f = open(new_filename, 'rb')
new_data = f.read()
f.close()
# copy the original file for diff
(temp_fd, temp_pathname) = tempfile.mkstemp()
shutil.copyfile(board_filename, temp_pathname)
container = BoardContainer.open(board_filename)
container.add_board(new_data, new_names)
container.write(board_filename)
print(diff_boardfiles(temp_pathname, board_filename, False))
os.remove(temp_pathname)
def main():
description = '''ath12k board-N.bin files manegement tool
ath12k-bdencoder is for creating (--create), listing (--info) and
comparing (--diff, --diffstat) ath12k board-N.bin files. The
board-N.bin is a container format which can have unlimited number of
actual board images ("board files"), each image containing one or
names which ath12k uses to find the correct image.
For creating board files you need a mapping file in JSON which
contains the names and filenames for the actual binary:
[
{
"board": [
{"names": ["AAA1", "AAAA2"], "data": "A.bin"},
{"names": ["B"], "data": "B.bin"},
{"names": ["C"], "data": "C.bin"},
],
"regdb": [
{"names": ["A"], "data": "A.regdb"}
]
}
]
In this example the board-N.bin will contain three board files which
are read from files named A.bin (using names AAA1 and AAAA2 in the
board-N.bin file), B.bin (using name B) and C.bin (using name C). The file also contains one regdb (regulatory database) from file A.regdb.
You can use --extract switch to see examples from real board-N.bin
files.
'''
parser = argparse.ArgumentParser(description=description,
formatter_class=argparse.RawTextHelpFormatter)
cmd_group = parser.add_mutually_exclusive_group(required=True)
cmd_group.add_argument("-c", "--create", metavar='JSON_FILE',
help='create board-N.bin from a mapping file in JSON format')
cmd_group.add_argument("-e", "--extract", metavar='BOARD_FILE',
help='extract board-N.bin file to a JSON mapping file and individual board files, compatible with the format used with --create command')
cmd_group.add_argument("-i", "--info", metavar='BOARD_FILE',
help='show all details about a board-N.bin file')
cmd_group.add_argument('-d', '--diff', metavar='BOARD_FILE', nargs=2,
help='show differences between two board-N.bin files')
cmd_group.add_argument('-D', '--diffstat', metavar='BOARD_FILE', nargs=2,
help='show a summary of differences between two board-N.bin files')
cmd_group.add_argument('-a', '--add-board', metavar='NAME', nargs='+',
help='add a board file to an existing board-N.bin, first argument is the filename of board-N.bin to add to, second is the filename board file (board.bin) to add and then followed by one or more arguments are names used in board-N.bin')
parser.add_argument('-v', '--verbose', action='store_true',
help='enable verbose (debug) messages')
parser.add_argument("-o", "--output", metavar="BOARD_FILE",
help='name of the output file, otherwise the default is: %s' %
(DEFAULT_BOARD_FILE))
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
if args.create:
return cmd_create(args)
elif args.extract:
return cmd_extract(args)
elif args.info:
return cmd_info(args)
elif args.diff:
return cmd_diff(args)
elif args.diffstat:
return cmd_diff(args)
elif args.add_board:
return cmd_add_board(args)
if __name__ == "__main__":
main()

614
tools/scripts/ath12k/ath12k-check Executable file
View file

@ -0,0 +1,614 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2017 Qualcomm Atheros, Inc.
# Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Run 'ath12k-check --help' to see the instructions
#
import subprocess
import os
import logging
import sys
import argparse
import re
import tempfile
import queue
import threading
import string
import hashlib
import shutil
CHECKPATCH_COMMIT = '99b70ece33d87500ef7bee8e32cb99772c45ce14'
CHECKPATCH_MD5SUM = 'b3c97930952745672f3408dabc244843'
GIT_URL = 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/scripts/checkpatch.pl?id=%s'
DRIVER_DIR = 'drivers/net/wireless/ath/ath12k/'
FILTER_REGEXP = r'/ath'
# Example: CONFIG_CC_VERSION_TEXT="x86_64-linux-gcc (GCC) 13.2.0"
CONFIG_CC_REGEXP = r'^CONFIG_CC_VERSION_TEXT="(.*)"$'
IGNORE_FILES = []
CHECKPATCH_IGNORE = [
# some find extra parentheses helpful so ignore the warnings
'UNNECESSARY_PARENTHESES',
]
CHECKPATCH_OPTS = ['--strict', '-q', '--terse', '--no-summary',
'--max-line-length=90', '--show-types']
checkpatch_filter = [
('ath12k_wifi7_dp_mon_hal_rx_parse_eht_non_mumimo_user', 'LONG_LINE'),
('ath12k_wifi7_dp_mon_hal_rx_parse_eht_sig_ndp', 'LONG_LINE'),
('ath12k_wifi7_dp_mon_hal_rx_parse_eht_sig_non_ofdma', 'LONG_LINE'),
('ath12k_wifi7_dp_mon_hal_rx_parse_non_ofdma_users', 'LONG_LINE'),
('ath12k_wifi7_dp_mon_hal_rx_parse_user_info', 'LONG_LINE'),
('ath12k_wifi7_dp_mon_hal_rx_parse_usig_overflow', 'LONG_LINE'),
('ath12k_wifi7_dp_mon_parse_he_sig_b1_mu', 'LONG_LINE'),
('ath12k_wifi7_dp_mon_parse_he_sig_b2_mu', 'LONG_LINE'),
('ath12k_wifi7_dp_mon_parse_he_sig_mu', 'LONG_LINE'),
('ath12k_wifi7_dp_mon_rx_handle_ofdma_info', 'LONG_LINE'),
('ath12k_wifi7_dp_mon_rx_populate_mu_user_info', 'LONG_LINE'),
('qmi_wlanfw_respond_mem_req_msg_v01', 'LONG_LINE'),
('qmi_wlanfw_host_cap_req_msg_v01', 'LONG_LINE'),
('qmi_wlfw_qdss_trace_config_download_req_msg_v01_ei', 'LONG_LINE'),
('qmi_wlanfw_qdss_trace_config_download_resp_msg_v01_ei', 'LONG_LINE'),
# workaround for long lines in
# qmi_wlfw_qdss_trace_config_download_req_msg_v01_ei, for some
# reason gtags claim they are part of
# ATH12K_QMI_MAX_CHUNK_SIZE
('ATH12K_QMI_MAX_CHUNK_SIZE', 'LONG_LINE'),
# allow long line copyrights
# note gtags returns None so search for the literal string
('Copyright (c)', 'LONG_LINE_COMMENT'),
# trace.h has warnings which don't make sense to fix
('TRACE_SYSTEM', 'OPEN_ENDED_LINE'),
# couldn't figure out how to make checkpatch happy with these macros
('SVC', 'COMPLEX_MACRO'),
('C2S', 'COMPLEX_MACRO'),
('C2S', 'MACRO_WITH_FLOW_CONTROL'),
# this use of volatile should be ok
('ath12k_hal_srng_access_begin', 'VOLATILE'),
('ath12k_hal_srng_access_end', 'VOLATILE'),
('hal_srng', 'VOLATILE'),
# __ath12k_dbg has to use dev_printk() so that debug_mask always work
('__ath12k_dbg', 'PREFER_DEV_LEVEL'),
('__ath12k_dbg', 'PREFER_PR_LEVEL'),
# couldn't figure a way to avoid the reuse warning
('for_each_ar', 'MACRO_ARG_REUSE'),
]
sparse_filter = [
# sparse doesn't correctly handle guard()
r'warning: context imbalance in .* - wrong count at exit',
]
# global variables
logger = logging.getLogger('ath12k-check')
threads = 1
class CPWarning():
def __str__(self):
return 'CPWarning(%s, %s, %s, %s, %s)' % (self.path, self.lineno,
self.tag, self.type,
self.msg)
def __init__(self):
self.path = ''
self.lineno = ''
self.type = ''
self.msg = ''
self.tag = ''
def run_gcc(args):
# to disable utf-8 from gcc, easier to paste that way
os.environ['LC_CTYPE'] = 'C'
cmd = 'find %s -name "*.o" -type f -delete' % (DRIVER_DIR)
logger.debug('%s' % cmd)
subprocess.call(cmd, shell=True, universal_newlines=True)
cmd = ['make', '-k', '-j', str(threads)]
if not args.no_extra:
cmd.append('W=1')
cmd.append(DRIVER_DIR)
env = os.environ.copy()
# disable ccache in case it's in use, it's useless as we are
# compiling only few files and it also breaks GCC's
# -Wimplicit-fallthrough check
env['CCACHE_DISABLE'] = '1'
logger.debug('%s' % cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=env, universal_newlines=True)
(stdout, stderr) = p.communicate()
stderr = stderr.strip()
if len(stderr) > 0:
for line in stderr.splitlines():
match = re.search(FILTER_REGEXP, line)
if not args.no_filter and not match:
logger.debug('FILTERED: %s' % line)
continue
print(line.strip())
return p.returncode
def run_sparse(args):
cmd = ['make', '-k', '-j',
str(threads), DRIVER_DIR, 'C=2', 'CF="-D__CHECK_ENDIAN__"']
logger.debug('%s' % cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
(stdout, stderr) = p.communicate()
stderr = stderr.strip()
if len(stderr) > 0:
for line in stderr.splitlines():
match = re.search(FILTER_REGEXP, line)
if not args.no_filter and not match:
logger.debug('FILTERED: %s' % line)
continue
drop = False
for f in sparse_filter:
match = re.search(f, line)
if not args.no_filter and match:
logger.debug('sparse_filter: %s' % line)
drop = True
break
if not drop:
print(line.strip())
return p.returncode
def find_tagname(tag_map, filename, lineno):
if filename.find('Kconfig') != -1:
return None
if filename not in tag_map:
return None
# we need the tags sorted per linenumber
sorted_tags = sorted(tag_map[filename], key=lambda tup: tup[0])
lineno = int(lineno)
prev = None
# find the tag which is in lineno
for (l, tag) in sorted_tags:
if l > lineno:
return prev
prev = tag
return None
def parse_checkpatch_warning(line):
m = re.match(r'(.*?):(\d+): .*?:(.*?): (.*)', line, re.M | re.I)
result = CPWarning()
result.path = m.group(1)
result.lineno = m.group(2)
result.type = m.group(3)
result.msg = m.group(4)
return result
def is_filtered(cpwarning):
for (tag, type) in checkpatch_filter:
if cpwarning.tag is not None:
# the global tool was able to find a tag name for this
# line so use it directly
matchobj = re.match(tag, cpwarning.tag)
if matchobj is None:
continue
if cpwarning.type == type:
return True
else:
# the global tool was not able to find a tag name for this
# line so instead check the actual line in the file
f = open(cpwarning.path)
buf = f.read()
f.close()
lineno = int(cpwarning.lineno) - 1
lines = buf.splitlines()
line = lines[lineno]
logger.debug('file %r tag %r line %r' % (cpwarning.path, tag, line))
if tag in line:
return True
return False
def get_checkpatch_md5sum():
path = shutil.which('checkpatch.pl')
f = open(path, 'rb')
md5sum = hashlib.md5(f.read()).hexdigest()
f.close()
return md5sum
def get_checkpatch_cmdline():
return ['checkpatch.pl'] + CHECKPATCH_OPTS + \
['--ignore', ",".join(CHECKPATCH_IGNORE)]
def run_checkpatch_cmd(args, q, tag_map):
checkpatch_cmd = get_checkpatch_cmdline() + ['-f']
while True:
try:
f = q.get_nowait()
except queue.Empty:
# no more files to check
break
cmd = checkpatch_cmd + [f]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
(stdoutdata, stderrdata) = p.communicate()
if stdoutdata is None:
continue
lines = stdoutdata.splitlines()
for line in lines:
w = parse_checkpatch_warning(line)
w.tag = find_tagname(tag_map, f, w.lineno)
if not args.no_filter and is_filtered(w):
logger.debug('FILTERED: %s' % w)
continue
logger.debug(w)
print('%s:%s: %s' % (w.path, w.lineno, w.msg))
q.task_done()
# get all driver files which are commited to git, includes Kconfig, Makefile etc
def get_commited_files():
cmd = ['git', 'ls-tree', '-r', '--name-only', 'HEAD', DRIVER_DIR]
output = subprocess.check_output(cmd, universal_newlines=True)
return output.splitlines()
def run_checkpatch(args):
md5sum = get_checkpatch_md5sum()
if md5sum != CHECKPATCH_MD5SUM:
print('WARNING: checkpatch.pl md5sum %s does not match with %s' %
(md5sum, CHECKPATCH_MD5SUM))
driver_files = get_commited_files()
# drop files we need to ignore
for name in IGNORE_FILES:
full_name = '%s%s' % (DRIVER_DIR, name)
if full_name in driver_files:
driver_files.remove(full_name)
logger.debug('driver_files: %s' % (driver_files))
# create global index file
(fd, tmpfilename) = tempfile.mkstemp()
f = os.fdopen(fd, 'w')
f.write('\n'.join(driver_files))
f.close()
# FIXME: do we need to call os.close(fd) still?
cmd = 'gtags -f %s' % (tmpfilename)
logger.debug('%s' % (cmd))
output = subprocess.check_output(cmd, shell=True, universal_newlines=True)
os.remove(tmpfilename)
# tag_map[FILENAME] = [(start line, tagname)]
tag_map = {}
# create tag mapping
for f in driver_files:
# global gives an error from Kconfig and Makefile
if f.endswith('Kconfig') or f.endswith('Makefile'):
continue
cmd = 'global -f %s' % (f)
output = subprocess.check_output(cmd, shell=True, universal_newlines=True)
lines = output.splitlines()
for l in lines:
columns = l.split()
tagname = columns[0]
line = int(columns[1])
if f not in tag_map:
tag_map[f] = []
tag_map[f].append((line, tagname))
q = queue.Queue()
for f in driver_files:
q.put(f)
# run checkpatch for all files
for i in range(threads):
t = threading.Thread(
target=run_checkpatch_cmd, args=(args, q, tag_map))
t.daemon = True
t.start()
q.join()
return 0
def run_kdoc(args):
p = subprocess.run(['scripts/kernel-doc', '-Werror', '-none'] +
get_commited_files())
return p.returncode
def show_version(args):
host_gcc_version = 'not found'
config_cc_version = 'not found'
sparse_version = 'not found'
checkpatch_version = 'not found'
checkpatch_md5sum = 'N/A'
gtags_version = 'not found'
run = subprocess.check_output
f = open(sys.argv[0], 'rb')
ath12kcheck_md5sum = hashlib.md5(f.read()).hexdigest()
f.close()
try:
host_gcc_version = run(['gcc', '--version'],
universal_newlines=True).splitlines()[0]
except:
pass
try:
f = open('.config')
m = re.search(CONFIG_CC_REGEXP, f.read(), re.MULTILINE)
if m is not None:
config_cc_version = m.group(1)
f.close()
except:
pass
try:
sparse_version = run(['sparse', '--version'],
universal_newlines=True).splitlines()[0]
except:
pass
try:
checkpatch_version = run(['checkpatch.pl', '--version'],
universal_newlines=True).splitlines()[1]
checkpatch_md5sum = get_checkpatch_md5sum()
except:
pass
try:
gtags_version = run(['gtags', '--version'],
universal_newlines=True).splitlines()[0]
except:
pass
print('ath12k-check (md5sum %s)' % (ath12kcheck_md5sum))
print()
print('python:\t\t%s' % (sys.version))
print('host gcc:\t%s' % (host_gcc_version))
print('config cc:\t%s' % (config_cc_version))
print('sparse:\t\t%s' % (sparse_version))
print('checkpatch.pl:\t%s (md5sum %s)' % (checkpatch_version, checkpatch_md5sum))
print('gtags:\t\t%s' % (gtags_version))
sys.exit(0)
def main():
global threads
checkpatch_url = GIT_URL % (CHECKPATCH_COMMIT)
description = '''ath12k source code checker
Runs various tests (gcc, sparse and checkpatch) with filtering
unnecessary warnings away, the goal is to have empty output from the
script.
Run this from the main kernel source directory which is preconfigured
with ath12k enabled. gcc recompilation of ath12k is forced every time,
irrespective if there are any changes in source or not. So this can be
run multiple times and every time the same warnings will appear.
Requirements (all available in $PATH):
* gcc
* sparse
* checkpatch.pl
* gtags (from package global)
'''
s = '''Installation:
It is assumed below that ~/bin is part of user's $$PATH. If it's not,
replace ~/bin with a suitable directory.
To install or update to the latest version of ath12k-check:
wget https://github.com/qca/qca-swiss-army-knife/raw/master/tools/scripts/ath12k/ath12k-check
cp ath12k-check ~/bin/
It's strongly recommend to use the latest GCC version from crosstool:
https://mirrors.edge.kernel.org/pub/tools/crosstool/
Unpack the compiler for example to /opt/cross/ and in the Linux kernel
sources create a new file called GNUmakefile with contents:
ARCH=x86
CROSS_COMPILE=/opt/cross/gcc-13.2.0-nolibc/x86_64-linux/bin/x86_64-linux-
export ARCH
export CROSS_COMPILE
Now the kernel will be compiled with the compiler from /opt/cross.
Latest development version of sparse is needed, install it manually
from the git repository:
git clone https://git.kernel.org/pub/scm/devel/sparse/sparse.git/
cd sparse
make
cp sparse ~/bin/
As checkpatch is evolving and new tests are added, it's important that
a correct version of checkpatch is used. If a wrong version is used
ath12k-check will warn about that. To download the correct checkpatch
version and install it to ~/bin:
wget -O checkpatch.pl $CHECKPATCH_URL
cp checkpatch.pl ~/bin/
Note that the URL in above wget command is dynamically created and
will change everytime ath12k-check is updated to use a new version of
checkpatch.pl
For gtags program you need to install package named global, for
example in Debian/Ubuntu you can do that using apt:
apt install global
Alternatively (but not recommended!) if you want manually run
checkpatch with the same settings as ath12k-check uses here's the
command line:
$CHECKPATCH_CMDLINE
'''
checkpatch_cmdline = '%s foo.patch' % ' '.join(get_checkpatch_cmdline())
epilog = string.Template(s).substitute(CHECKPATCH_URL=checkpatch_url,
CHECKPATCH_CMDLINE=checkpatch_cmdline)
parser = argparse.ArgumentParser(description=description, epilog=epilog,
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-d', '--debug', action='store_true',
help='enable debug messages')
parser.add_argument('--fast', action='store_true',
help='run only tests which finish in few seconds')
parser.add_argument('--no-extra', action='store_true',
help='Do not run extra checks like W=1')
parser.add_argument('--no-filter', action='store_true',
help='Don\'t filter output with regexp: %r' % (FILTER_REGEXP))
parser.add_argument('--version', action='store_true',
help='Show version information about dependencies')
args = parser.parse_args()
timefmt = ''
if args.debug:
logger.setLevel(logging.DEBUG)
timefmt = '%(asctime)s '
logfmt = '%s%%(levelname)s: %%(message)s' % (timefmt)
logging.basicConfig(format=logfmt)
if args.version:
show_version(args)
if args.fast:
gcc = True
sparse = True
checkpatch = False
else:
gcc = True
sparse = True
checkpatch = True
try:
cores = subprocess.check_output(['nproc'], universal_newlines=True)
except OSError as xxx_todo_changeme:
subprocess.CalledProcessError = xxx_todo_changeme
cores = '4'
logger.warning('Failed to run nproc, assuming %s cores' % (cores))
threads = int(cores) + 2
logger.debug('threads %d' % (threads))
if gcc:
ret = run_gcc(args)
if ret != 0:
logger.debug('gcc failed: %d', ret)
sys.exit(1)
if sparse:
ret = run_sparse(args)
if ret != 0:
logger.debug('sparse failed: %d', ret)
sys.exit(2)
if checkpatch:
ret = run_checkpatch(args)
if ret != 0:
logger.debug('checkpatch failed: %d', ret)
sys.exit(3)
ret = run_kdoc(args)
if ret != 0:
logger.debug('kernel-doc failed: %d', ret)
sys.exit(4)
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,724 @@
#!/usr/bin/python3
#
# Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
# Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
# Copyright (c) 2015-2017 Qualcomm Atheros, Inc.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import ctypes
import struct
import optparse
import time
import math
import logging
import sys
import os.path
import traceback
import binascii
import tempfile
import subprocess
import hashlib
DEFAULT_FW_API_VERSION = 2
ATH12K_SIGNATURE = b'QCOM-ATH12K-FW'
MAX_LEN = 50000000
ATH12K_FW_IE_TIMESTAMP = 0
ATH12K_FW_IE_FEATURES = 1
ATH12K_FW_IE_AMSS_IMAGE = 2
ATH12K_FW_IE_M3_IMAGE = 3
ATH12K_FW_IE_AMSS_DUALMAC_IMAGE = 4
# enum ath12k_fw_features from ath12k/fw.h
ATH12K_FW_FEATURE_MULTI_QRTR_ID = 0
ATH12K_FW_FEATURE_MLO = 1
ATH12K_FW_FEATURE_MAX = 2
feature_map = {
'multi-qrtr-id': ATH12K_FW_FEATURE_MULTI_QRTR_ID,
'mlo': ATH12K_FW_FEATURE_MLO,
}
# global variables
logger = None
class FWEncoderError(Exception):
pass
def get_output_name(fw_api=None):
if fw_api is not None:
api = fw_api
else:
api = DEFAULT_FW_API_VERSION
return 'firmware-%s.bin' % api
class FirmwareContainer:
def add_element(self, type_id, value):
length = len(value)
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, 0x77)
logger.debug('adding id %d len(value) %d'
'padding_len %d' % (type_id,
len(value),
padding_len))
fmt = '<ii%ds%ds' % (len(value), padding_len)
struct.pack_into(fmt, self.buf, self.buf_len, type_id, len(value),
value, padding.raw)
self.buf_len = self.buf_len + 4 + 4 + len(value) + padding_len
def add_u32(self, type_id, value):
if not type(value) is int:
raise FWEncoderError('u32 IE %d is not int: %s' %
(type_id, str(value)))
buf = ctypes.create_string_buffer(4)
struct.pack_into("<i", buf, 0, value)
self.add_element(type_id, buf.raw)
def read_u32(self, type_id):
(val,) = struct.unpack_from("<i", self.elements[type_id])
return val
def add_bitmap(self, ie, enabled, maximum):
if (max(enabled) >= maximum):
logger.error("bitmap %d out of maximum (%d >= %d)" %
(ie, max(enabled), maximum))
return
bytes = [0] * maximum
for i in range(maximum):
if i not in enabled:
continue
max_set = i
index = int(i / 8)
bit = i % 8
bytes[index] = bytes[index] | (1 << bit)
# remove trailing null bits away, that changing only
# maximum doesn't affect created binary size
length = int(math.ceil((max_set + 1) / float(8)))
bytes = bytes[:length]
buf = ctypes.create_string_buffer(length)
for index in range(length):
struct.pack_into('<B', buf, index, bytes[index])
self.add_element(ie, buf.raw)
def read_bitmap(self, ie):
buf = self.elements[ie]
length = len(buf)
bits = []
for index in range(length):
val = struct.unpack_from('<B', buf, index)[0]
for bit in range(8):
if val & 0x1:
bits.append(index * 8 + bit)
val = val >> 1
return bits
def set_signature(self, signature):
self.signature = signature
self.signature_len = len(signature)
# include the null byte
length = len(signature) + 1
padding_len = padding_needed(length)
length = length + padding_len
padding = ctypes.create_string_buffer(padding_len)
for i in range(padding_len):
struct.pack_into('<B', padding, i, 0x77)
fmt = '<%dsb%ds' % (len(signature), padding_len)
struct.pack_into(fmt, self.buf, 0, signature, 0, padding.raw)
self.buf_len = length
def write(self, name):
f = open(name, 'wb')
f.write(self.buf.raw[:self.buf_len])
f.close()
return self.buf_len
def open(self, name):
f = open(name, 'rb')
self.buf = f.read()
self.buf_len = len(self.buf)
f.close()
offset = 0
fmt = '<%dsb' % (self.signature_len)
(signature, null) = struct.unpack_from(fmt, self.buf, offset)
offset = offset + self.signature_len + 1
if signature != self.signature or null != 0:
logger.error("Invalid signature!")
return False
offset = self.signature_len + 1
offset = offset + padding_needed(offset)
self.elements = {}
while offset + 4 + 4 < self.buf_len:
(type_id, length) = struct.unpack_from("<ii", self.buf, offset)
offset = offset + 4 + 4
if offset + length > self.buf_len:
logger.error("Buffer too short")
return
fmt = '<%ds' % length
(payload,) = struct.unpack_from(fmt, self.buf, offset)
offset = offset + length
offset = offset + padding_needed(offset)
self.elements[type_id] = payload
return True
def __init__(self, signature):
self.buf = ctypes.create_string_buffer(MAX_LEN)
self.buf_len = 0
self.set_signature(signature)
class Ath12kFirmwareContainer(object):
def _load_file(self, name):
if os.path.getsize(name) > MAX_LEN:
raise FWEncoderError('file %s is too large, maximum size is %d' %
(name, MAX_LEN))
f = open(name, 'rb')
buf = f.read()
f.close()
return buf
def set_features(self, features):
self.features = features.split(',')
enabled = []
for capa in self.features:
if capa not in feature_map:
print("Error: '%s' not found from the feature map" % capa)
return 1
enabled.append(feature_map[capa])
self.features_bitmap = enabled
def get_features(self):
s = ""
if self.features_bitmap is None:
return None
for capa in self.features_bitmap:
# find value from the dict
try:
name = [key for key, value in feature_map.items()
if value == capa][0]
except IndexError:
name = str(capa)
s = s + name + ","
# strip last comma
if len(s) > 0:
s = s[:-1]
return s
def set_amss_image(self, amss_image_name):
self.amss_image = self._load_file(amss_image_name)
def get_amss_image(self):
return self.amss_image
def set_amss_dualmac_image(self, amss_dualmac_image_name):
self.amss_dualmac_image = self._load_file(amss_dualmac_image_name)
def get_amss_dualmac_image(self):
return self.amss_dualmac_image
def set_m3_image(self, m3_image_name):
self.m3_image = self._load_file(m3_image_name)
def get_m3_image(self):
return self.m3_image
def set_timestamp(self, timestamp):
self.timestamp = int(timestamp)
def get_timestamp(self):
return self.timestamp
def get_timestamp_as_iso8601(self):
if self.timestamp is None:
return None
return time.strftime('%Y-%m-%d %H:%M:%S',
time.gmtime(self.timestamp))
def get_summary(self):
s = ''
s = s + 'FileSize: %s\n' % (len(self.file))
s = s + 'FileCRC32: %08x\n' % (_crc32(self.file))
s = s + 'FileMD5: %s\n' % (hashlib.md5(self.file).hexdigest())
if self.get_timestamp():
s = s + 'Timestamp: %s\n' % (self.get_timestamp_as_iso8601())
if self.get_features():
s = s + 'Features: %s\n' % (self.get_features())
if self.get_amss_image():
s = s + 'AMSSImageSize: %s\n' % (len(self.get_amss_image()))
s = s + 'AMSSImageCRC32: %08x\n' % (_crc32(self.get_amss_image()))
if self.get_amss_dualmac_image():
s = s + 'AMSSDualMacImageSize: %s\n' % (len(self.get_amss_dualmac_image()))
s = s + 'AMSSDualMacImageCRC32: %08x\n' % (_crc32(self.get_amss_dualmac_image()))
if self.get_m3_image():
s = s + 'M3ImageSize: %s\n' % (len(self.get_m3_image()))
s = s + 'M3ImageCRC32: %08x\n' % (_crc32(self.get_m3_image()))
return s.strip()
def load(self, filename):
c = FirmwareContainer(ATH12K_SIGNATURE)
c.open(filename)
self.file = c.buf
for e in c.elements:
if e == ATH12K_FW_IE_TIMESTAMP:
self.timestamp = c.read_u32(e)
elif e == ATH12K_FW_IE_M3_IMAGE:
self.m3_image = c.elements[e]
elif e == ATH12K_FW_IE_AMSS_IMAGE:
self.amss_image = c.elements[e]
elif e == ATH12K_FW_IE_AMSS_DUALMAC_IMAGE:
self.amss_dualmac_image = c.elements[e]
elif e == ATH12K_FW_IE_FEATURES:
self.features_bitmap = c.read_bitmap(ATH12K_FW_IE_FEATURES)
else:
print("Unknown IE: ", e)
def save(self, filename):
self.container = FirmwareContainer(ATH12K_SIGNATURE)
if self.timestamp:
self.container.add_u32(ATH12K_FW_IE_TIMESTAMP, self.timestamp)
# FIXME: m3 should be after amss_image but that breaks the
# current tests
if self.m3_image:
self.container.add_element(ATH12K_FW_IE_M3_IMAGE, self.m3_image)
if self.amss_image:
self.container.add_element(ATH12K_FW_IE_AMSS_IMAGE, self.amss_image)
if self.amss_dualmac_image:
self.container.add_element(ATH12K_FW_IE_AMSS_DUALMAC_IMAGE, self.amss_dualmac_image)
# FIXME: features should be before amss_image but that breaks
# the current tests
if self.features_bitmap:
self.container.add_bitmap(ATH12K_FW_IE_FEATURES,
self.features_bitmap,
ATH12K_FW_FEATURE_MAX)
return self.container.write(filename)
def __init__(self):
self.timestamp = None
self.features = None
self.features_bitmap = None
self.amss_image = None
self.m3_image = None
self.amss_dualmac_image = None
# to workaround annoying python feature of returning negative hex values
def hex32(val):
return val & 0xffffffff
# match with kernel crc32_le(0, buf, buf_len) implementation
def _crc32(buf):
return hex32(~(hex32(binascii.crc32(buf, 0xffffffff))))
def padding_needed(length):
if length % 4 != 0:
return 4 - length % 4
return 0
def is_int(val):
try:
int(val)
return True
except ValueError:
return False
def write_file(filename, buf):
f = open(filename, 'wb')
f.write(buf)
f.close
def info(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath12kFirmwareContainer()
c.load(filename)
print(c.get_summary())
def dump(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath12kFirmwareContainer()
c.load(filename)
print("ath12k-fwencoder --create \\")
if c.get_timestamp() and options.show_timestamp:
print("--timestamp=%u \\" % c.get_timestamp())
if c.get_features():
print("--features=%s \\" % c.get_features())
if c.get_amss_image():
name = "amss.bin"
print("--amss=%s \\" % name)
if c.get_amss_dualmac_image():
name = "amss_dualmac.bin"
print("--amss_dualmac=%s \\" % name)
if c.get_m3_image():
name = "m3.bin"
print("--m3=%s \\" % name)
print()
def extract(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath12kFirmwareContainer()
c.load(filename)
if c.get_amss_image():
name = "amss.bin"
write_file(name, c.get_amss_image())
print('%s extracted: %d B' % (name, len(c.get_amss_image())))
if c.get_amss_dualmac_image():
name = "amss_dualmac.bin"
write_file(name, c.get_amss_dualmac_image())
print('%s extracted: %d B' % (name, len(c.get_amss_dualmac_image())))
if c.get_m3_image():
name = "m3.bin"
write_file(name, c.get_m3_image())
print('%s extracted: %d B' % (name, len(c.get_m3_image())))
print()
def modify(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
c = Ath12kFirmwareContainer()
c.load(filename)
if options.timestamp:
stamp = str(int(options.timestamp))
else:
# if no timestamp provided use the current time so that the
# timestamp shows the time of last modication
stamp = int(time.time())
c.set_timestamp(stamp)
if options.m3:
c.set_m3_image(options.m3)
if options.amss:
c.set_amss_image(options.amss)
if options.amss_dualmac:
c.set_amss_dualmac_image(options.amss_dualmac)
if options.features:
c.set_features(options.features)
file_len = c.save(filename)
print('%s modified: %d B' % (filename, file_len))
def create(options):
output = get_output_name(options.fw_api)
if options.output:
output = options.output
c = Ath12kFirmwareContainer()
# always add a timestamp
if options.timestamp:
stamp = int(options.timestamp)
else:
stamp = int(time.time())
c.set_timestamp(stamp)
if options.m3:
c.set_m3_image(options.m3)
if options.amss:
c.set_amss_image(options.amss)
if options.amss_dualmac:
c.set_amss_dualmac_image(options.amss_dualmac)
if options.features:
c.set_features(options.features)
file_len = c.save(output)
print('%s created: %d B' % (output, file_len))
def cmd_crc32(options, args):
if len(args) != 1:
print('Filename missing')
return 1
filename = args[0]
f = open(filename, 'rb')
buf = f.read()
print('%08x' % (_crc32(buf)))
f.close()
def cmd_diff(options, args):
if len(args) != 2:
print('Usage: ath12k-fwencoder --diff FILE FILE')
return 1
filename1 = args[0]
filename2 = args[1]
c1 = Ath12kFirmwareContainer()
c1.load(filename1)
(temp1_fd, temp1_pathname) = tempfile.mkstemp(text=True)
# for some reason text=True is not working with mkstemp() so open
# the file manually
f = open(temp1_pathname, 'w')
f.write(c1.get_summary())
f.close()
c2 = Ath12kFirmwareContainer()
c2.load(filename2)
(temp2_fd, temp2_pathname) = tempfile.mkstemp(text=True)
# for some reason text=True is not working with mkstemp() so open
# the file manually
f = open(temp2_pathname, 'w')
f.write(c2.get_summary())
f.close()
# '--less-mode' and '--auto-page' would be nice when running on
# terminal but don't know how to get the control character
# through. For terminal detection sys.stdout.isatty() can be used.
cmd = ['wdiff', temp1_pathname, temp2_pathname]
# wdiff is braindead and returns 1 in a succesfull case
try:
output = subprocess.check_output(cmd, universal_newlines=True)
except subprocess.CalledProcessError as e:
if e.returncode == 1:
output = e.output
else:
logger.error('Failed to run wdiff: %d\n%s' % (e.returncode, e.output))
return 1
except OSError as e:
logger.error('Failed to run wdiff: %s' % (e))
return 1
print(output)
os.close(temp1_fd)
os.close(temp2_fd)
def main():
global logger
logger = logging.getLogger('ath12k-fwencoder')
logging.basicConfig(format='%(levelname)s: %(message)s')
parser = optparse.OptionParser()
# actions
parser.add_option("-c", "--create", action="store_true", dest="create",
help='Create container file '
'for ath12k (%s)' % get_output_name())
parser.add_option("-D", "--dump-cmdline", action="store_true", dest="dump",
help='Show the cmdline used to create '
'this container file')
parser.add_option('--dump', action='store_true', dest='dump',
help='Same as --dump-cmdline '
'(for backwards compatibility)')
parser.add_option("-e", "--extract", action="store_true", dest="extract",
help='Extract binary files from the container file '
'and dump cmdline as well')
parser.add_option("--info", action="store_true", dest="info",
help='Show information about the container file')
parser.add_option("--modify", action="store_true", dest="modify",
help='Modify the container file')
parser.add_option('--crc32', action='store_true', dest='crc32',
help='Count crc32 checksum for a file')
parser.add_option('--diff', action='store_true', dest='diff',
help='Show differences between two firmware files')
# parameters
parser.add_option("-o", "--output", action="store", type="string",
dest="output", help='Name of output file')
# FW IEs, only use long style of option names!
parser.add_option("--m3", action="store", type="string",
dest="m3",
help='Name of m3.bin file')
parser.add_option("--amss", action="store", type="string",
dest="amss",
help='Name of amss.bin file')
parser.add_option("--amss_dualmac", action="store", type="string",
dest="amss_dualmac",
help='Name of amss_dualmac.bin file')
parser.add_option("--timestamp", action="store",
type="string", dest="timestamp",
help='Timestamp to be used (seconds)')
parser.add_option("--features", action="store",
type="string", dest="features",
help='feature bits to be enabled: %s' %
list(feature_map.keys()))
parser.add_option("--set-fw-api", action="store",
type="string", dest="fw_api",
help='Set firmware API used in creating the name for '
'output file (Default: %s)' %
DEFAULT_FW_API_VERSION)
# debug etc
parser.add_option('--show-timestamp', action='store_true',
dest='show_timestamp',
help='Show timestamp in --dump-cmdline action. '
'It is not shown by default so that the timestamp would be correct')
parser.add_option('-d', '--debug', action='store_true', dest='debug',
help='Enable debug messages')
(options, args) = parser.parse_args()
if options.debug:
logger.setLevel(logging.DEBUG)
if options.create:
try:
return create(options)
except FWEncoderError as e:
print('Create failed: %s' % e)
sys.exit(2)
except Exception as e:
print('Create failed: %s' % e)
traceback.print_exc()
sys.exit(3)
elif options.dump:
return dump(options, args)
elif options.extract:
return extract(options, args)
elif options.info:
return info(options, args)
elif options.modify:
return modify(options, args)
elif options.crc32:
return cmd_crc32(options, args)
elif options.diff:
return cmd_diff(options, args)
else:
print('Action command missing')
return 1
if __name__ == "__main__":
main()

View file

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
#
# Copyright (c) 2010 Atheros Communications Inc.
#
@ -117,7 +117,7 @@ def powertx_rate1 (val):
ofdm_rates["12"] = (val >> 16) & 0xff
ofdm_rates["18"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 1", val)
print("%010s: 0x%08x" % ("Rate 1", val))
def powertx_rate2 (val):
ofdm_rates["24"] = (val >> 0) & 0xff;
@ -125,7 +125,7 @@ def powertx_rate2 (val):
ofdm_rates["48"] = (val >> 16) & 0xff
ofdm_rates["54"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 2", val)
print("%010s: 0x%08x" % ("Rate 2", val))
def powertx_rate3 (val):
cck_rates["1L"] = (val >> 0) & 0xff;
@ -134,7 +134,7 @@ def powertx_rate3 (val):
cck_rates["2L"] = (val >> 16) & 0xff;
cck_rates["2S"] = (val >> 24) & 0xff;
print "%010s: 0x%08x" % ("Rate 3", val)
print("%010s: 0x%08x" % ("Rate 3", val))
def powertx_rate4 (val):
cck_rates["5.5L"] = (val >> 0) & 0xff;
@ -142,7 +142,7 @@ def powertx_rate4 (val):
cck_rates["11L"] = (val >> 16) & 0xff
cck_rates["11S"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 4", val)
print("%010s: 0x%08x" % ("Rate 4", val))
def powertx_rate5 (val):
mcs_rates_ht20["0"] = (val >> 0) & 0xff;
@ -165,7 +165,7 @@ def powertx_rate5 (val):
mcs_rates_ht20["5"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 5", val)
print("%010s: 0x%08x" % ("Rate 5", val))
def powertx_rate6 (val):
mcs_rates_ht20["6"] = (val >> 0) & 0xff;
@ -173,7 +173,7 @@ def powertx_rate6 (val):
mcs_rates_ht20["12"] = (val >> 16) & 0xff
mcs_rates_ht20["13"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 6", val)
print("%010s: 0x%08x" % ("Rate 6", val))
def powertx_rate7 (val):
mcs_rates_ht40["0"] = (val >> 0) & 0xff;
@ -196,7 +196,7 @@ def powertx_rate7 (val):
mcs_rates_ht40["5"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 7", val)
print("%010s: 0x%08x" % ("Rate 7", val))
def powertx_rate8 (val):
mcs_rates_ht40["6"] = (val >> 0) & 0xff;
@ -204,7 +204,7 @@ def powertx_rate8 (val):
mcs_rates_ht40["12"] = (val >> 16) & 0xff
mcs_rates_ht40["13"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 8", val)
print("%010s: 0x%08x" % ("Rate 8", val))
# What is 40 dup CCK, 40 dup OFDM, 20 ext cck, 20 ext ODFM ?
def powertx_rate9 (val):
@ -213,7 +213,7 @@ def powertx_rate9 (val):
ext_dup_rates["20 ext CCK"] = (val >> 16) & 0xff
ext_dup_rates["20 ext OFDM"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 9", val)
print("%010s: 0x%08x" % ("Rate 9", val))
def powertx_rate10 (val):
mcs_rates_ht20["14"] = (val >> 0) & 0xff;
@ -221,7 +221,7 @@ def powertx_rate10 (val):
mcs_rates_ht20["20"] = (val >> 16) & 0xff
mcs_rates_ht20["21"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 10", val)
print("%010s: 0x%08x" % ("Rate 10", val))
def powertx_rate11 (val):
mcs_rates_ht20["22"] = (val >> 0) & 0xff;
@ -230,7 +230,7 @@ def powertx_rate11 (val):
mcs_rates_ht40["22"] = (val >> 16) & 0xff
mcs_rates_ht40["23"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 11", val)
print("%010s: 0x%08x" % ("Rate 11", val))
def powertx_rate12 (val):
mcs_rates_ht40["14"] = (val >> 0) & 0xff;
@ -238,7 +238,7 @@ def powertx_rate12 (val):
mcs_rates_ht40["20"] = (val >> 16) & 0xff
mcs_rates_ht40["21"] = (val >> 24) & 0xff
print "%010s: 0x%08x" % ("Rate 12", val)
print("%010s: 0x%08x" % ("Rate 12", val))
registers = {
"0x00a3c0" : powertx_rate1,
@ -256,43 +256,43 @@ registers = {
}
def process_cck_rates():
print "CCK Rates"
print "======================"
for rate, double_dbm in cck_rates.iteritems():
print("CCK Rates")
print("======================")
for rate, double_dbm in cck_rates.items():
dbm = "%.2f dBm" % (double_dbm / 2)
print "%010s %010s" % (rate + " Mbps", dbm)
print("%010s %010s" % (rate + " Mbps", dbm))
def process_ofdm_rates():
print "OFDM Rates"
print "======================"
for rate, double_dbm in sorted(map(lambda (k,v): (int(k,0), v), ofdm_rates.iteritems())):
print("OFDM Rates")
print("======================")
for rate, double_dbm in sorted(ofdm_rates.items(), key=lambda i: int(i[0], 0)):
rate_s = "%s" % rate
dbm = "%.02f dBm" % (double_dbm / 2)
print "%010s %010s" % (rate_s + " Mbps", dbm)
print("%010s %010s" % (rate_s + " Mbps", dbm))
def process_mcs_ht20_rates():
print "MCS20 Rates"
print "======================"
for rate, double_dbm in sorted(map(lambda (k,v): (int(k,0), v), mcs_rates_ht20.iteritems())):
print("MCS20 Rates")
print("======================")
for rate, double_dbm in sorted(mcs_rates_ht20.items(), key=lambda i: int(i[0], 0)):
rate_s = "%s" % rate
dbm = "%.02f dBm" % (double_dbm / 2)
print "%010s %010s" % ("MCS" + rate_s, dbm)
print("%010s %010s" % ("MCS" + rate_s, dbm))
def process_mcs_ht40_rates():
print "MCS40 Rates"
print "======================"
for rate, double_dbm in sorted(map(lambda (k,v): (int(k,0), v), mcs_rates_ht40.iteritems())):
print("MCS40 Rates")
print("======================")
for rate, double_dbm in sorted(mcs_rates_ht40.items(), key=lambda i: int(i[0], 0)):
rate_s = "%s" % rate
dbm = "%.2f dBm" % (double_dbm / 2)
print "%010s %010s" % ("MCS" + rate_s, dbm)
print("%010s %010s" % ("MCS" + rate_s, dbm))
def process_ext_dup_rates():
print "EXT-DUP Rates"
print "=========================="
for rate, double_dbm in ext_dup_rates.iteritems():
print("EXT-DUP Rates")
print("==========================")
for rate, double_dbm in ext_dup_rates.items():
dbm = "%.2f dBm" % (double_dbm / 2)
print "%015s %010s" % (rate, dbm)
print("%015s %010s" % (rate, dbm))
def print_power_reg (reg, val):
if not reg in map(lambda x: int(x, 0), registers.keys()):
@ -300,12 +300,12 @@ def print_power_reg (reg, val):
registers.get("0x%06x" % reg)(val)
try:
print "Power register"
print "======================"
print("Power register")
print("======================")
for line in sys.stdin.readlines():
reg, val = map(lambda x: int(x, 0), string.split(line))
reg, val = map(lambda x: int(x, 0), line.split())
print_power_reg(reg, val)
print "-------------------------------------"
print("-------------------------------------")
process_cck_rates()
process_ofdm_rates()

1109
tracing/plugins/ath10k.py Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,471 @@
#
# Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# trace-cmd pktlog plugin for ath10k, QCA Linux wireless driver
#
# TODO:
#
# o create class for struct ieee80211_hdr each packet headers with
# pack() and unpack() methods
import struct
import binascii
DEBUG = 1
CUR_PKTLOG_VER = 10010
PKTLOG_MAGIC_NUM = 7735225
IEEE80211_FCTL_TODS = 0x0100
IEEE80211_FCTL_FROMDS = 0x0200
TARGET_NUM_MSDU_DESC = (1024 + 400)
MAX_PKT_INFO_MSDU_ID = 192
MAX_10_4_PKT_INFO_MSDU_ID = 1
PKTLOG_MAX_TXCTL_WORDS = 57
# must match with enum ath10k_hw_rev from ath10k and existing values
# should not change
ATH10K_PKTLOG_HW_QCA988X = 0
ATH10K_PKTLOG_HW_QCA6174 = 1
ATH10K_PKTLOG_HW_QCA99X0 = 2
ATH10K_PKTLOG_HW_QCA9888 = 3
ATH10K_PKTLOG_HW_QCA9984 = 4
ATH10K_PKTLOG_HW_QCA9377 = 5
ATH10K_PKTLOG_HW_QCA40XX = 6
ATH10K_PKTLOG_HW_QCA9887 = 7
ATH10K_PKTLOG_TYPE_TX_CTRL = 1
ATH10K_PKTLOG_TYPE_TX_STAT = 2
ATH10K_PKTLOG_TYPE_TX_MSDU_ID = 3
ATH10K_PKTLOG_TYPE_TX_FRM_HDR = 4
ATH10K_PKTLOG_TYPE_RX_STAT = 5
ATH10K_PKTLOG_TYPE_RC_FIND = 6
ATH10K_PKTLOG_TYPE_RC_UPDATE = 7
ATH10K_PKTLOG_TYPE_TX_VIRT_ADDR = 8
ATH10K_PKTLOG_TYPE_DBG_PRINT = 9
ATH10K_PKTLOG_FLG_TYPE_LOCAL_S = 0
ATH10K_PKTLOG_FLG_TYPE_REMOTE_S = 1
ATH10K_PKTLOG_FLG_TYPE_CLONE_S = 2
ATH10K_PKTLOG_FLG_TYPE_UNKNOWN_S = 3
# sizeof(ath10k_pktlog_txctl) = 12 + 4 * 57
ATH10K_PKTLOG_TXCTL_LEN = 240
ATH10K_PKTLOG_MAX_TXCTL_WORDS = 57
# sizeof(ath10k_pktlog_10_4_txctl)2 = 16 + 4 * 153
ATH10K_PKTLOG_10_4_TXCTL_LEN = 624
ATH10K_PKTLOG_10_4_MAX_TXCTL_WORDS = 153
msdu_len_tbl = {}
output_file = None
frm_hdr = None
def dbg(msg):
if DEBUG == 0:
return
print(msg)
def hexdump(buf, prefix=None):
s = binascii.b2a_hex(buf)
s_len = len(s)
result = ""
if prefix is None:
prefix = ""
for i in range(s_len / 2):
if i % 16 == 0:
result = result + ("%s%04x: " % (prefix, i))
result = result + (s[2 * i] + s[2 * i + 1] + " ")
if (i + 1) % 16 == 0:
result = result + "\n"
# FIXME: if len(s) % 16 == 0 there's an extra \n in the end
return result
# struct ath10k_pktlog_hdr {
# unsigned short flags;
# unsigned short missed_cnt;
# unsigned short log_type;
# unsigned short size;
# unsigned int timestamp;
# unsigned char payload[0];
# } __attribute__((__packed__));
class Ath10kPktlogHdr:
# 2 + 2 + 2 + 2 + 4 = 12
hdr_len = 12
struct_fmt = '<HHHHI'
def unpack(self, buf, offset=0):
(self.flags, self.missed_cnt, self.log_type,
self.size, self.timestamp) = struct.unpack_from(self.struct_fmt, buf, 0)
payload_len = len(buf) - self.hdr_len
if payload_len < self.size:
raise Exception('Payload length invalid: %d != %d' %
(payload_len, self.size))
self.payload = buf[self.hdr_len:]
# excludes payload, you have to write that separately!
def pack(self):
return struct.pack(self.struct_fmt,
self.flags,
self.missed_cnt,
self.log_type,
self.size,
self.timestamp)
def __str__(self):
return 'flags %04x miss %d log_type %d size %d timestamp %d\n' % \
(self.flags, self.missed_cnt,
self.log_type, self.size, self.timestamp)
def __init__(self):
self.flags = 0
self.missed_cnt = 0
self.log_type = 0
self.size = 0
self.timestamp = 0
self.payload = []
# struct ath10k_pktlog_10_4_hdr {
# unsigned short flags;
# unsigned short missed_cnt;
# unsigned short log_type;
# unsigned short size;
# unsigned int timestamp;
# unsigned int type_specific_data;
# unsigned char payload[0];
# } __attribute__((__packed__));
class Ath10kPktlog_10_4_Hdr:
# 2 + 2 + 2 + 2 + 4 + 4 = 16
hdr_len = 16
struct_fmt = '<HHHHII'
def unpack(self, buf, offset=0):
(self.flags, self.missed_cnt, self.log_type,
self.size, self.timestamp, self.type_specific_data) = struct.unpack_from(self.struct_fmt, buf, 0)
payload_len = len(buf) - self.hdr_len
if payload_len != self.size:
raise Exception('Payload length invalid: %d != %d' %
(payload_len, self.size))
self.payload = buf[self.hdr_len:]
# excludes payload, you have to write that separately!
def pack(self):
return struct.pack(self.struct_fmt,
self.flags,
self.missed_cnt,
self.log_type,
self.size,
self.timestamp,
self.type_specific_data)
def __str__(self):
return 'flags %04x miss %d log_type %d size %d timestamp %d type_specific_data %d\n' % \
(self.flags, self.missed_cnt, self.log_type,
self.size, self.timestamp, self.type_specific_data)
def __init__(self):
self.flags = 0
self.missed_cnt = 0
self.log_type = 0
self.size = 0
self.timestamp = 0
self.type_specific_data = 0
self.payload = []
def output_open():
global output_file
# apparently no way to close the file as the python plugin doesn't
# have unregister() callback
output_file = open('pktlog.dat', 'wb')
buf = struct.pack('II', PKTLOG_MAGIC_NUM, CUR_PKTLOG_VER)
output_write(buf)
def output_write(buf):
global output_file
output_file.write(buf)
def pktlog_tx_frm_hdr(frame):
global frm_hdr
try:
# struct ieee80211_hdr
(frame_control, duration_id, addr1a, addr1b, addr1c, addr2a, addr2b, addr2c,
addr3a, addr3b, addr3c, seq_ctrl) = struct.unpack_from('<HHI2BI2BI2BH', frame, 0)
except struct.error as e:
dbg('failed to parse struct ieee80211_hdr: %s' % (e))
return
if frame_control & IEEE80211_FCTL_TODS:
bssid_tail = (addr1b << 8) | addr1c
sa_tail = (addr2b << 8) | addr2c
da_tail = (addr3b << 8) | addr3c
elif frame_control & IEEE80211_FCTL_FROMDS:
bssid_tail = (addr2b << 8) | addr2c
sa_tail = (addr3b << 8) | addr3c
da_tail = (addr1b << 8) | addr1c
else:
bssid_tail = (addr3b << 8) | addr3c
sa_tail = (addr2b << 8) | addr2c
da_tail = (addr1b << 8) | addr1c
resvd = 0
frm_hdr = struct.pack('HHHHHH', frame_control, seq_ctrl, bssid_tail,
sa_tail, da_tail, resvd)
dbg('frm_hdr %d B' % len(frm_hdr))
def pktlog_tx_ctrl(buf, hw_type):
global frm_hdr
if hw_type == ATH10K_PKTLOG_HW_QCA988X:
hdr = Ath10kPktlogHdr()
hdr.unpack(buf)
hdr.size = ATH10K_PKTLOG_TXCTL_LEN
num_txctls = ATH10K_PKTLOG_MAX_TXCTL_WORDS
elif hw_type in [ATH10K_PKTLOG_HW_QCA99X0, ATH10K_PKTLOG_HW_QCA40XX,
ATH10K_PKTLOG_HW_QCA9888, ATH10K_PKTLOG_HW_QCA9984]:
hdr = Ath10kPktlog_10_4_Hdr()
hdr.unpack(buf)
hdr.size = ATH10K_PKTLOG_10_4_TXCTL_LEN
num_txctls = ATH10K_PKTLOG_10_4_MAX_TXCTL_WORDS
output_write(hdr.pack())
# write struct ath10k_pktlog_frame
if frm_hdr:
output_write(frm_hdr)
else:
tmp = struct.pack('HHHHHH', 0, 0, 0, 0, 0, 0)
output_write(tmp)
txdesc_ctl = hdr.payload[0:]
for i in range(num_txctls):
if len(txdesc_ctl) >= 4:
txctl, = struct.unpack_from('<I', txdesc_ctl)
txdesc_ctl = txdesc_ctl[4:]
else:
txctl = 0
output_write(struct.pack('I', txctl))
def pktlog_tx_msdu_id(buf, hw_type):
global msdu_len_tbl
if hw_type == ATH10K_PKTLOG_HW_QCA988X:
hdr = Ath10kPktlogHdr()
hdr.unpack(buf)
hdr.size = 4 + (192 / 8) + 2 * 192
# write struct ath10k_pktlog_hdr
output_write(hdr.pack())
# parse struct msdu_id_info
# hdr (12) + num_msdu (4) + bound_bmap (24) = 40
msdu_info = hdr.payload[0:28]
id = hdr.payload[28:]
num_msdu, = struct.unpack_from('I', msdu_info)
output_write(msdu_info)
max_pkt_info_msdu_id = MAX_PKT_INFO_MSDU_ID
elif hw_type in [ATH10K_PKTLOG_HW_QCA99X0, ATH10K_PKTLOG_HW_QCA40XX,
ATH10K_PKTLOG_HW_QCA9888, ATH10K_PKTLOG_HW_QCA9984]:
hdr = Ath10kPktlog_10_4_Hdr()
hdr.unpack(buf)
# write struct ath10k_pktlog_10_4_hdr
output_write(hdr.pack())
# parse struct msdu_id_info
# hdr (16) + num_msdu (4) + bound_bmap (1) = 21
msdu_info = hdr.payload[0:5]
id = hdr.payload[5:]
num_msdu, = struct.unpack_from('I', msdu_info)
output_write(msdu_info)
max_pkt_info_msdu_id = MAX_10_4_PKT_INFO_MSDU_ID
for i in range(max_pkt_info_msdu_id):
if num_msdu > 0:
num_msdu = num_msdu - 1
msdu_id, = struct.unpack_from('<H', id)
id = id[2:]
if msdu_id not in msdu_len_tbl:
dbg('msdu_id %d not found from msdu_len_tbl' % (msdu_id))
msdu_len = 0
else:
msdu_len = msdu_len_tbl[msdu_id]
else:
msdu_len = 0
output_write(struct.pack('H', msdu_len))
def ath10k_htt_pktlog_handler(pevent, trace_seq, event):
hw_type = int(event.get('hw_type', ATH10K_PKTLOG_HW_QCA988X))
buf = event['pktlog'].data
offset = 0
if hw_type == ATH10K_PKTLOG_HW_QCA988X:
hdr = Ath10kPktlogHdr()
elif hw_type in [ATH10K_PKTLOG_HW_QCA99X0, ATH10K_PKTLOG_HW_QCA40XX,
ATH10K_PKTLOG_HW_QCA9888, ATH10K_PKTLOG_HW_QCA9984]:
hdr = Ath10kPktlog_10_4_Hdr()
hdr.unpack(buf, offset)
offset = offset + hdr.hdr_len
trace_seq.puts('%s\n' % (hdr))
if hdr.log_type == ATH10K_PKTLOG_TYPE_TX_FRM_HDR:
pktlog_tx_frm_hdr(buf[hdr.hdr_len:])
elif hdr.log_type == ATH10K_PKTLOG_TYPE_TX_CTRL:
pktlog_tx_ctrl(buf, hw_type)
elif hdr.log_type == ATH10K_PKTLOG_TYPE_TX_MSDU_ID:
pktlog_tx_msdu_id(buf, hw_type)
elif hdr.log_type == ATH10K_PKTLOG_TYPE_TX_STAT or \
hdr.log_type == ATH10K_PKTLOG_TYPE_RX_STAT or \
hdr.log_type == ATH10K_PKTLOG_TYPE_RC_FIND or \
hdr.log_type == ATH10K_PKTLOG_TYPE_RC_UPDATE:
output_write(buf[0: offset + hdr.size])
else:
pass
def ath10k_htt_rx_desc_handler(pevent, trace_seq, event):
hw_type = int(event.get('hw_type', ATH10K_PKTLOG_HW_QCA988X))
rxdesc = event['rxdesc'].data
trace_seq.puts('len %d\n' % (len(rxdesc)))
if hw_type == ATH10K_PKTLOG_HW_QCA988X:
hdr = Ath10kPktlogHdr()
hdr.flags = (1 << ATH10K_PKTLOG_FLG_TYPE_REMOTE_S)
hdr.missed_cnt = 0
hdr.log_type = ATH10K_PKTLOG_TYPE_RX_STAT
# rx_desc size for QCA988x chipsets is 248
hdr.size = 248
output_write(hdr.pack())
output_write(rxdesc[0: 32])
output_write(rxdesc[36: 56])
output_write(rxdesc[76: 208])
output_write(rxdesc[228:])
elif hw_type in [ATH10K_PKTLOG_HW_QCA99X0, ATH10K_PKTLOG_HW_QCA40XX]:
hdr = Ath10kPktlog_10_4_Hdr()
hdr.flags = (1 << ATH10K_PKTLOG_FLG_TYPE_REMOTE_S)
hdr.missed_cnt = 0
hdr.log_type = ATH10K_PKTLOG_TYPE_RX_STAT
hdr.type_specific_data = 0
hdr.size = len(rxdesc)
output_write(hdr.pack())
output_write(rxdesc)
elif hw_type in [ATH10K_PKTLOG_HW_QCA9888, ATH10K_PKTLOG_HW_QCA9984]:
hdr = Ath10kPktlog_10_4_Hdr()
hdr.flags = (1 << ATH10K_PKTLOG_FLG_TYPE_REMOTE_S)
hdr.missed_cnt = 0
hdr.log_type = ATH10K_PKTLOG_TYPE_RX_STAT
hdr.type_specific_data = 0
# rx_desc size for QCA9984 and QCA9889 chipsets is 296
hdr.size = 296
output_write(hdr.pack())
output_write(rxdesc[0: 4])
output_write(rxdesc[4: 8])
output_write(rxdesc[12: 24])
output_write(rxdesc[24: 40])
output_write(rxdesc[44: 84])
output_write(rxdesc[100: 104])
output_write(rxdesc[104: 144])
output_write(rxdesc[144: 256])
output_write(rxdesc[292:])
def ath10k_htt_tx_handler(pevent, trace_seq, event):
global msdu_len_tbl
msdu_id = int(event['msdu_id'])
msdu_len = int(event['msdu_len'])
trace_seq.puts('msdu_id %d msdu_len %d\n' % (msdu_id, msdu_len))
if msdu_id > TARGET_NUM_MSDU_DESC:
dbg('Invalid msdu_id in tx: %d' % (msdu_id))
return
msdu_len_tbl[msdu_id] = msdu_len
def ath10k_txrx_tx_unref_handler(pevent, trace_seq, event):
global msdu_len_tbl
msdu_id = int(event['msdu_id'])
trace_seq.puts('msdu_id %d\n' % (msdu_id))
if msdu_id > TARGET_NUM_MSDU_DESC:
dbg('Invalid msdu_id from unref: %d' % (msdu_id))
return
msdu_len_tbl[msdu_id] = 0
def ath10k_tx_hdr_handler(pevent, trace_seq, event):
buf = event['data'].data
pktlog_tx_frm_hdr(buf[0:])
def register(pevent):
output_open()
pevent.register_event_handler("ath10k", "ath10k_htt_pktlog",
lambda *args:
ath10k_htt_pktlog_handler(pevent, *args))
pevent.register_event_handler("ath10k", "ath10k_htt_rx_desc",
lambda *args:
ath10k_htt_rx_desc_handler(pevent, *args))
pevent.register_event_handler("ath10k", "ath10k_htt_tx",
lambda *args:
ath10k_htt_tx_handler(pevent, *args))
pevent.register_event_handler("ath10k", "ath10k_txrx_tx_unref",
lambda *args:
ath10k_txrx_tx_unref_handler(pevent, *args))
pevent.register_event_handler("ath10k", "ath10k_tx_hdr",
lambda *args:
ath10k_tx_hdr_handler(pevent, *args))

251
tracing/plugins/ath6kl.py Normal file
View file

@ -0,0 +1,251 @@
#
# Copyright (c) 2012 Qualcomm Atheros, Inc.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# To install the plugin:
#
# cp ath6kl.py ~/.trace-cmd/plugins/
#
# When making changes to the plugin use -V to see all python errors/warnings:
#
# trace-cmd report -V trace.dat
import tracecmd
import struct
import binascii
def hexdump(buf, prefix=None):
s = binascii.b2a_hex(buf)
s_len = len(s)
result = ""
if prefix == None:
prefix = ""
for i in range(s_len / 2):
if i % 16 == 0:
result = result + ("%s%04x: " % (prefix, i))
result = result + (s[2*i] + s[2*i+1] + " ")
if (i + 1) % 16 == 0:
result = result + "\n"
# FIXME: if len(s) % 16 == 0 there's an extra \n in the end
return result
def wmi_event_bssinfo(pevent, trace_seq, event, buf):
hdr = struct.unpack("<HBB6BH", buf[0:12])
channel = hdr[0]
frame_type = hdr[1]
snr = hdr[2]
bssid = hdr[3]
ie_mask = hdr[4]
trace_seq.puts("\t\t\tWMI_BSSINFO_EVENTID channel %d frame_type 0x%x snr %d ie_mask 0x%x\n" %
(channel, frame_type, snr, ie_mask))
wmi_event_handlers = [
[0x1004, wmi_event_bssinfo ],
]
def wmi_cmd_set_bss_filter_handler(pevent, trace_seq, event, buf):
hdr = struct.unpack("<BBHI", buf[0:8])
bss_filter = hdr[0]
ie_mask = hdr[3]
trace_seq.puts("\t\t\tWMI_SET_BSS_FILTER_CMDID bss_filter 0x%x ie_mask 0x%08x\n" %
(bss_filter, ie_mask))
def wmi_cmd_set_probed_ssid_handler(pevent, trace_seq, event, buf):
hdr = struct.unpack("<BBB", buf[0:3])
entry_index = hdr[0]
flag = hdr[1]
ssid_len = hdr[2]
# fmt = "<" + ssid_len + "s"
# hdr = struct.unpack(fmt, buf[3:3 + ssid_len])
trace_seq.puts("\t\t\tWMI_SET_PROBED_SSID_CMDID entry_index 0x%x flag 0x%08x ssid_len %d\n" %
(entry_index, flag, ssid_len))
# FIXME: print SSID
# for c in hdr[0]:
# print ascii(c)
wmi_cmd_handlers = [
[9, wmi_cmd_set_bss_filter_handler ],
[10, wmi_cmd_set_probed_ssid_handler ],
]
WMI_CMD_HDR_IF_ID_MASK = 0xf
def ath6kl_wmi_cmd_handler(pevent, trace_seq, event):
buf_len = long(event['buf_len'])
buf = event['buf'].data
hdr = struct.unpack("<HHH", buf[0:6])
cmd_id = hdr[0]
if_idx = hdr[1] & WMI_CMD_HDR_IF_ID_MASK
trace_seq.puts("id 0x%x len %d if_idx %d\n" % (cmd_id, buf_len, if_idx))
for (wmi_id, handler) in wmi_cmd_handlers:
if wmi_id == cmd_id:
handler(pevent, trace_seq, event, buf[6:])
break
def ath6kl_wmi_event_handler(pevent, trace_seq, event):
buf_len = long(event['buf_len'])
buf = event['buf'].data
hdr = struct.unpack("<HHH", buf[0:6])
cmd_id = hdr[0]
if_idx = hdr[1] & WMI_CMD_HDR_IF_ID_MASK
trace_seq.puts("id 0x%x len %d if_idx %d\n" % (cmd_id, buf_len, if_idx))
for (wmi_id, handler) in wmi_event_handlers:
if wmi_id == cmd_id:
handler(pevent, trace_seq, event, buf[6:])
break
def ath6kl_htc_tx_handler(pevent, trace_seq, event):
buf_len = long(event['buf_len'])
buf = event['buf'].data
hdr = struct.unpack("<BBHBB", buf[0:6])
endpoint = hdr[0]
flags = hdr[1]
payload_len = hdr[2]
ctrl0 = hdr[3]
ctrl1 = hdr[4]
seqno = ctrl1
trace_seq.puts("seqno %d endpoint %d payload_len %d flags 0x%x\n" %
(seqno, endpoint, payload_len, flags))
if flags != 0:
trace_seq.puts("\t\t\t\t\t\t")
if flags & 0x1:
trace_seq.puts(" NEED_CREDIT_UPDATE")
if flags & 0x2:
trace_seq.puts(" SEND_BUNDLE")
if flags & 0x4:
trace_seq.puts(" FIXUP_NETBUF")
if flags != 0:
trace_seq.puts("\n")
def ath6kl_htc_rx_handler(pevent, trace_seq, event):
buf_len = long(event['buf_len'])
buf = event['buf'].data
hdr = struct.unpack("<BBHBB", buf[0:6])
endpoint = hdr[0]
flags = hdr[1]
payload_len = hdr[2]
ctrl0 = hdr[3]
ctrl1 = hdr[4]
seqno = ctrl1
bundle_count = (flags & 0xf0) >> 4
trace_seq.puts("seqno %d endpoint %d payload_len %d flags 0x%x bundle_count %d\n" %
(seqno, endpoint, payload_len, flags, bundle_count))
if (flags & 0xf) != 0:
trace_seq.puts("\t\t\t\t\t\t")
if flags & 0x1:
trace_seq.puts(" UNUSED")
if flags & 0x2:
trace_seq.puts(" TRAILER")
if (flags & 0xf) != 0:
trace_seq.puts("\n")
def ath6kl_sdio_handler(pevent, trace_seq, event):
tx = long(event['tx'])
addr = event['addr']
flags = event['flags']
buf_len = long(event['buf_len'])
buf = event['buf'].data
if tx == 1:
direction = "tx"
else:
direction = "rx"
trace_seq.puts("%s addr 0x%x flags 0x%x buf_len %d\n" %
(direction, addr, flags, buf_len))
trace_seq.puts("%s\n" % hexdump(buf))
def ath6kl_sdio_scat_handler(pevent, trace_seq, event):
tx = long(event['tx'])
addr = long(event['addr'])
flags = long(event['flags'])
entries = long(event['entries'])
total_len = long(event['total_len'])
len_array_data = event['len_array'].data
data = event['data'].data
if tx == 1:
direction = "tx"
else:
direction = "rx"
trace_seq.puts("%s addr 0x%x flags 0x%x entries %d total_len %d\n" %
(direction, addr, flags, entries, total_len))
offset = 0
len_array = struct.unpack("<%dI" % entries, len_array_data[0:8])
for i in range(entries):
length = len_array[i]
start = offset
end = start + length
trace_seq.puts("%s\n" % hexdump(data[start:end]))
offset = offset + length
def register(pevent):
pevent.register_event_handler("ath6kl", "ath6kl_wmi_cmd",
lambda *args:
ath6kl_wmi_cmd_handler(pevent, *args))
pevent.register_event_handler("ath6kl", "ath6kl_wmi_event",
lambda *args:
ath6kl_wmi_event_handler(pevent, *args))
pevent.register_event_handler("ath6kl", "ath6kl_htc_tx",
lambda *args:
ath6kl_htc_tx_handler(pevent, *args))
pevent.register_event_handler("ath6kl", "ath6kl_htc_rx",
lambda *args:
ath6kl_htc_rx_handler(pevent, *args))
pevent.register_event_handler("ath6kl", "ath6kl_sdio",
lambda *args:
ath6kl_sdio_handler(pevent, *args))
pevent.register_event_handler("ath6kl", "ath6kl_sdio_scat",
lambda *args:
ath6kl_sdio_scat_handler(pevent, *args))