From d6a9376028870754d7d3de3f626c1deb6df81092 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Fri, 6 Feb 2015 05:11:18 +0000 Subject: [PATCH 01/75] Vendor import of xz-5.2.0 (stripped) --- ChangeLog | 2887 +++++++++++++++-- THANKS | 13 + TODO | 58 +- src/common/mythread.h | 505 ++- src/common/sysdefs.h | 10 + src/common/tuklib_cpucores.c | 15 +- src/common/tuklib_physmem.c | 7 + src/liblzma/api/lzma.h | 2 +- src/liblzma/api/lzma/base.h | 81 +- src/liblzma/api/lzma/block.h | 74 +- src/liblzma/api/lzma/container.h | 201 +- src/liblzma/api/lzma/filter.h | 13 +- src/liblzma/api/lzma/hardware.h | 14 + src/liblzma/api/lzma/index.h | 16 +- src/liblzma/api/lzma/index_hash.h | 4 +- src/liblzma/api/lzma/{lzma.h => lzma12.h} | 2 +- src/liblzma/api/lzma/version.h | 4 +- src/liblzma/check/check.h | 83 +- src/liblzma/check/sha256.c | 62 +- src/liblzma/common/alone_decoder.c | 6 +- src/liblzma/common/alone_decoder.h | 2 +- src/liblzma/common/alone_encoder.c | 8 +- src/liblzma/common/auto_decoder.c | 6 +- src/liblzma/common/block_buffer_decoder.c | 2 +- src/liblzma/common/block_buffer_encoder.c | 98 +- src/liblzma/common/block_buffer_encoder.h | 24 + src/liblzma/common/block_decoder.c | 24 +- src/liblzma/common/block_decoder.h | 2 +- src/liblzma/common/block_encoder.c | 10 +- src/liblzma/common/block_encoder.h | 2 +- src/liblzma/common/block_header_decoder.c | 16 +- src/liblzma/common/block_header_encoder.c | 2 +- src/liblzma/common/block_util.c | 2 +- src/liblzma/common/common.c | 79 +- src/liblzma/common/common.h | 54 +- src/liblzma/common/easy_buffer_encoder.c | 4 +- src/liblzma/common/easy_encoder.c | 1 - src/liblzma/common/filter_buffer_decoder.c | 3 +- src/liblzma/common/filter_buffer_encoder.c | 7 +- src/liblzma/common/filter_common.c | 4 +- src/liblzma/common/filter_common.h | 2 +- src/liblzma/common/filter_decoder.c | 7 +- src/liblzma/common/filter_decoder.h | 2 +- src/liblzma/common/filter_encoder.c | 48 +- src/liblzma/common/filter_encoder.h | 6 +- src/liblzma/common/filter_flags_decoder.c | 2 +- ...stream_encoder.h => hardware_cputhreads.c} | 17 +- src/liblzma/common/index.c | 26 +- src/liblzma/common/index_decoder.c | 12 +- src/liblzma/common/index_encoder.c | 6 +- src/liblzma/common/index_encoder.h | 2 +- src/liblzma/common/index_hash.c | 6 +- src/liblzma/common/memcmplen.h | 170 + src/liblzma/common/outqueue.c | 184 ++ src/liblzma/common/outqueue.h | 156 + src/liblzma/common/stream_buffer_decoder.c | 2 +- src/liblzma/common/stream_buffer_encoder.c | 3 +- src/liblzma/common/stream_decoder.c | 23 +- src/liblzma/common/stream_decoder.h | 5 +- src/liblzma/common/stream_encoder.c | 25 +- src/liblzma/common/stream_encoder_mt.c | 1131 +++++++ src/liblzma/delta/delta_common.c | 4 +- src/liblzma/delta/delta_decoder.c | 6 +- src/liblzma/delta/delta_decoder.h | 5 +- src/liblzma/delta/delta_encoder.c | 6 +- src/liblzma/delta/delta_encoder.h | 3 +- src/liblzma/delta/delta_private.h | 2 +- src/liblzma/liblzma.map | 108 + src/liblzma/liblzma.pc.in | 2 +- src/liblzma/lz/lz_decoder.c | 8 +- src/liblzma/lz/lz_decoder.h | 7 +- src/liblzma/lz/lz_encoder.c | 118 +- src/liblzma/lz/lz_encoder.h | 8 +- src/liblzma/lz/lz_encoder_mf.c | 71 +- src/liblzma/lzma/fastpos.h | 55 +- src/liblzma/lzma/lzma2_decoder.c | 8 +- src/liblzma/lzma/lzma2_decoder.h | 5 +- src/liblzma/lzma/lzma2_encoder.c | 18 +- src/liblzma/lzma/lzma2_encoder.h | 4 +- src/liblzma/lzma/lzma_common.h | 45 +- src/liblzma/lzma/lzma_decoder.c | 74 +- src/liblzma/lzma/lzma_decoder.h | 7 +- src/liblzma/lzma/lzma_encoder.c | 59 +- src/liblzma/lzma/lzma_encoder.h | 5 +- src/liblzma/lzma/lzma_encoder_optimum_fast.c | 26 +- .../lzma/lzma_encoder_optimum_normal.c | 148 +- src/liblzma/lzma/lzma_encoder_private.h | 16 +- src/liblzma/rangecoder/range_decoder.h | 12 +- src/liblzma/simple/arm.c | 8 +- src/liblzma/simple/armthumb.c | 8 +- src/liblzma/simple/ia64.c | 8 +- src/liblzma/simple/powerpc.c | 8 +- src/liblzma/simple/simple_coder.c | 10 +- src/liblzma/simple/simple_coder.h | 36 +- src/liblzma/simple/simple_decoder.c | 2 +- src/liblzma/simple/simple_decoder.h | 2 +- src/liblzma/simple/simple_private.h | 3 +- src/liblzma/simple/sparc.c | 8 +- src/liblzma/simple/x86.c | 8 +- src/liblzma/validate_map.sh | 68 + src/xz/args.c | 110 +- src/xz/args.h | 2 + src/xz/coder.c | 430 ++- src/xz/coder.h | 15 + src/xz/file_io.c | 355 +- src/xz/file_io.h | 21 + src/xz/hardware.c | 32 +- src/xz/hardware.h | 9 +- src/xz/list.c | 63 +- src/xz/main.c | 5 + src/xz/message.c | 105 +- src/xz/mytime.c | 89 + src/xz/mytime.h | 47 + src/xz/options.c | 4 +- src/xz/private.h | 2 + src/xz/signals.c | 5 + src/xz/suffix.c | 176 +- src/xz/xz.1 | 211 +- 118 files changed, 7689 insertions(+), 1233 deletions(-) rename src/liblzma/api/lzma/{lzma.h => lzma12.h} (99%) create mode 100644 src/liblzma/common/block_buffer_encoder.h rename src/liblzma/common/{stream_encoder.h => hardware_cputhreads.c} (53%) create mode 100644 src/liblzma/common/memcmplen.h create mode 100644 src/liblzma/common/outqueue.c create mode 100644 src/liblzma/common/outqueue.h create mode 100644 src/liblzma/common/stream_encoder_mt.c create mode 100644 src/liblzma/liblzma.map create mode 100755 src/liblzma/validate_map.sh create mode 100644 src/xz/mytime.c create mode 100644 src/xz/mytime.h diff --git a/ChangeLog b/ChangeLog index 2c7cb51620e0..b84727b2fc8a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,32 +1,596 @@ -commit 495aaf3a5b7200a5d2bf449bbbcc0e18834607af +commit a0cd05ee71d330b79ead6eb9222e1b24e1559d3a Author: Lasse Collin -Date: 2014-09-20 20:44:32 +0300 +Date: 2014-12-21 20:48:37 +0200 - Bump version and soname for 5.0.7. + DOS: Update Makefile. + + dos/Makefile | 1 + + 1 file changed, 1 insertion(+) + +commit b85ee0905ec4ab7656d22e63519fdd3bedb21f2e +Author: Lasse Collin +Date: 2014-12-21 19:50:38 +0200 + + Windows: Fix bin_i486 to bin_i686 in build.bash. + + windows/build.bash | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit cbafa710918195dbba3db02c3fab4f0538235206 +Author: Lasse Collin +Date: 2014-12-21 18:58:44 +0200 + + Docs: Use lzma_cputhreads() in 04_compress_easy_mt.c. + + doc/examples/04_compress_easy_mt.c | 30 ++++++++++++++++++++++++++---- + 1 file changed, 26 insertions(+), 4 deletions(-) + +commit 8dbb57238d372c7263cfeb3e7f7fd9a73173156a +Author: Lasse Collin +Date: 2014-12-21 18:56:44 +0200 + + Docs: Update docs/examples/00_README.txt. + + doc/examples/00_README.txt | 4 ++++ + 1 file changed, 4 insertions(+) + +commit 6060f7dc76fd6c2a8a1f8e85d0e4d86bb78273e6 +Author: Lasse Collin +Date: 2014-12-21 18:11:17 +0200 + + Bump version and soname for 5.2.0. + + I know that soname != app version, but I skip AGE=1 + in -version-info to make the soname match the liblzma + version anyway. It doesn't hurt anything as long as + it doesn't conflict with library versioning rules. src/liblzma/Makefile.am | 2 +- - src/liblzma/api/lzma/version.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) + src/liblzma/api/lzma/version.h | 6 +++--- + src/liblzma/liblzma.map | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) -commit ac6c8921d1d8d2d749d5c97f9a0b0594cc863cea +commit 3e8bd1d15e417f2d588e9be50ce027ee3d48b2da Author: Lasse Collin -Date: 2014-09-20 20:43:29 +0300 +Date: 2014-12-21 18:05:03 +0200 + + Avoid variable-length arrays in the debug programs. + + debug/full_flush.c | 3 ++- + debug/sync_flush.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +commit 72f7307cfdceb941aeb2bf30d424cc0d13621786 +Author: Lasse Collin +Date: 2014-12-21 18:01:45 +0200 + + Build: Include 04_compress_easy_mt.c in the tarball. + + Makefile.am | 1 + + 1 file changed, 1 insertion(+) + +commit 2cb82ff21c62def11f3683a8bb0aaf363102aaa0 +Author: Lasse Collin +Date: 2014-12-21 18:00:38 +0200 + + Fix build when --disable-threads is used. + + src/common/mythread.h | 2 ++ + 1 file changed, 2 insertions(+) + +commit 9b9e3536e458ef958f66b0e8982efc9d36de4d17 +Author: Adrien Nader +Date: 2014-12-21 15:56:15 +0100 + + po/fr: improve wording for help for --lzma1/--lzma2. + + po/fr.po | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit a8b6b569e7fadbf5b5b9139d53bc764015c15027 +Author: Adrien Nader +Date: 2014-12-21 15:55:48 +0100 + + po/fr: missing line in translation of --extreme. + + po/fr.po | 1 + + 1 file changed, 1 insertion(+) + +commit f168a6fd1a888cf4f0caaddcafcb21dadc6ab6e9 +Author: Lasse Collin +Date: 2014-12-21 14:32:33 +0200 + + Update NEWS for 5.2.0. + + NEWS | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 65 insertions(+) + +commit cec2ee863b3a88f4bf039cb00f73c4a4fc93a429 +Author: Lasse Collin +Date: 2014-12-21 14:32:22 +0200 + + Update NEWS for 5.0.8. + + NEWS | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +commit 42e97a32649bf53ce43be2258b902a417c6e7fa1 +Author: Lasse Collin +Date: 2014-12-21 14:07:54 +0200 + + xz: Fix a comment. + + src/xz/options.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit 29b95d5d6665cedffa6a9d6d3d914f981e852182 +Author: Lasse Collin +Date: 2014-12-20 20:43:14 +0200 + + Update INSTALL about the dependencies of the scripts. + + INSTALL | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +commit 3af91040bb42c21afbb81f5568c3313125e61192 +Author: Lasse Collin +Date: 2014-12-20 20:42:33 +0200 + + Windows: Update build instructions. + + INSTALL | 15 +++++++++------ + windows/INSTALL-Windows.txt | 44 +++++++++++++++++++++----------------------- + 2 files changed, 30 insertions(+), 29 deletions(-) + +commit 0152f72bf6289d744823dc6c849538f3a139ad70 +Author: Lasse Collin +Date: 2014-12-20 20:41:48 +0200 + + Windows: Update the build script and README-Windows.txt. + + The 32-bit build is now for i686 or newer because the + prebuilt MinGW-w64 toolchains include i686 code in the + executables even if one uses -march=i486. + + The build script builds 32-bit SSE2 enabled version too. + Run-time detection of SSE2 support would be nice (on any OS) + but it's not implemented in XZ Utils yet. + + windows/README-Windows.txt | 30 ++++++++++++++++-------------- + windows/build.bash | 23 ++++++++++++++--------- + 2 files changed, 30 insertions(+), 23 deletions(-) + +commit 4a1f6133ee5533cee8d91e06fcc22443e5f1881a +Author: Lasse Collin +Date: 2014-12-19 15:51:50 +0200 + + Windows: Define TUKLIB_SYMBOL_PREFIX in config.h. + + It is to keep all symbols in the lzma_ namespace. + + windows/config.h | 3 +++ + 1 file changed, 3 insertions(+) + +commit 7f7d093de79eee0c7dbfd7433647e46302f19f82 +Author: Lasse Collin +Date: 2014-12-16 21:00:09 +0200 + + xz: Update the man page about --threads. + + src/xz/xz.1 | 5 ----- + 1 file changed, 5 deletions(-) + +commit 009823448b82aa5f465668878a544c5842885407 +Author: Lasse Collin +Date: 2014-12-16 20:57:43 +0200 + + xz: Update the man page about --block-size. + + src/xz/xz.1 | 41 +++++++++++++++++++++++++++++++++-------- + 1 file changed, 33 insertions(+), 8 deletions(-) + +commit 7dddfbeb499e528940bc12047355c184644aafe9 +Author: Adrien Nader +Date: 2014-12-10 22:26:57 +0100 + + po/fr: several more translation updates: reword and handle --ignore-check. + + po/fr.po | 50 ++++++++++++++++++++++++++------------------------ + 1 file changed, 26 insertions(+), 24 deletions(-) + +commit 6eca5be40e04ddc4b738d493e4e56835956d8b69 +Author: Adrien Nader +Date: 2014-12-10 22:23:01 +0100 + + po/fr: yet another place where my email address had to be updated. + + po/fr.po | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit d1003673e92ba47edd6aeeb3dbea05c18269d0e7 +Author: Adrien Nader +Date: 2014-12-10 22:22:20 +0100 + + po/fr: fix several typos that have been around since the beginning. + + po/fr.po | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +commit 4c5aa911a0df027e46171e368debc543d2fa72b2 +Author: Adrien Nader +Date: 2014-12-03 20:02:31 +0100 + + po/fr: last batch of new translations for now. + + Four new error messages. + + po/fr.po | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +commit 3e3099e36d27059499e7996fb38a62e8ab01d356 +Author: Adrien Nader +Date: 2014-12-03 20:01:32 +0100 + + po/fr: translations for --threads, --block-size and --block-list. + + po/fr.po | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +commit e7d96a5933eec4e9d4a62569ee88df0ebb0f1d53 +Author: Adrien Nader +Date: 2014-12-03 20:00:53 +0100 + + po/fr: remove fuzzy marker for error messages that will be kept in English. + + The following is a copy of a comment inside fr.po: + + Note from translator on "file status flags". + The following entry is kept un-translated on purpose. It is difficult to + translate and should only happen in exceptional circumstances which means + that translating would: + - lose some of the meaning + - make it more difficult to look up in search engines; it might happen one + in + a million times, if we dilute the error message in 20 languages, it will be + almost impossible to find an explanation and support for the error. + + po/fr.po | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +commit 46cbb9033af8a21fafe543302d6919746e0d72af +Author: Adrien Nader +Date: 2014-12-03 19:58:25 +0100 + + po/fr: several minor updates and better wording. + + Meaning doesn't change at all: it's only for better wording and/or + formatting of a few strings. + + po/fr.po | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +commit 7ce49d444f04e73145f79c832eb4d510594b074a +Author: Adrien Nader +Date: 2014-12-03 19:56:12 +0100 + + po/fr: update my email address and copyright years. + + po/fr.po | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit 214c553ebc3047cd720da1ce5c80cf7c38118d3c +Author: Adrien Nader +Date: 2014-11-26 10:08:26 +0100 + + fr.po: commit file after only "update-po" so actual is readable. + + po/fr.po | 311 ++++++++++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 199 insertions(+), 112 deletions(-) + +commit 1190c641af09cde85f8bd0fbe5c4906f4a29431b +Author: Lasse Collin +Date: 2014-12-02 20:04:07 +0200 + + liblzma: Document how lzma_mt.block_size affects memory usage. + + src/liblzma/api/lzma/container.h | 4 ++++ + 1 file changed, 4 insertions(+) + +commit e4fc1d2f9571fba79ce383595be2ea2a9257def0 +Author: Lasse Collin +Date: 2014-11-28 20:07:18 +0200 + + Update INSTALL about a "make check" failure in test_scripts.sh. + + INSTALL | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +commit 34f9e40a0a0c3bd2c2730cdb9cd550bbb8a3f2fe +Author: Lasse Collin +Date: 2014-11-26 20:12:27 +0200 + + Remove LZMA_UNSTABLE macro. + + src/liblzma/api/lzma/container.h | 4 ---- + src/liblzma/common/common.h | 2 -- + src/xz/private.h | 1 - + 3 files changed, 7 deletions(-) + +commit 6d9c0ce9f2677b159e32b224aba5b535b304a705 +Author: Lasse Collin +Date: 2014-11-26 20:10:33 +0200 + + liblzma: Update lzma_stream_encoder_mt() API docs. + + src/liblzma/api/lzma/container.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +commit 2301f3f05dd9742f42cda8f0f318864f5dc39ab3 +Author: Lasse Collin +Date: 2014-11-25 12:32:05 +0200 + + liblzma: Verify the filter chain in threaded encoder initialization. + + This way an invalid filter chain is detected at the Stream + encoder initialization instead of delaying it to the first + call to lzma_code() which triggers the initialization of + the actual filter encoder(s). + + src/liblzma/common/stream_encoder_mt.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +commit 107a263d5bb63cd3593fd6a5c938706539f84523 +Author: Lasse Collin +Date: 2014-11-17 19:11:49 +0200 + + Build: Update m4/ax_pthread.m4 from Autoconf Archive. + + m4/ax_pthread.m4 | 71 +++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 47 insertions(+), 24 deletions(-) + +commit b13a781833399ff5726cfc997f3cb2f0acbdbf31 +Author: Lasse Collin +Date: 2014-11-17 18:52:21 +0200 + + Build: Replace obsolete AC_HELP_STRING with AS_HELP_STRING. + + configure.ac | 36 ++++++++++++++++++------------------ + m4/tuklib_integer.m4 | 2 +- + 2 files changed, 19 insertions(+), 19 deletions(-) + +commit 542cac122ed3550148a2af0033af22b757491378 +Author: Lasse Collin +Date: 2014-11-17 18:43:19 +0200 + + Build: Fix Autoconf warnings about escaped backquotes. + + Thanks to Daniel Richard G. for pointing out that it's + good to sometimes run autoreconf -fi with -Wall. + + configure.ac | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +commit 7b03a15cea8cd4f19ed680b51c4bcbae3ce4142f +Author: Lasse Collin +Date: 2014-11-10 18:54:40 +0200 + + xzdiff: Use mkdir if mktemp isn't available. + + src/scripts/xzdiff.in | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +commit f8c13e5e3609581d5dd9f8777985ca07f2390ad7 +Author: Lasse Collin +Date: 2014-11-10 18:45:01 +0200 + + xzdiff: Create a temporary directory to hold a temporary file. + + This avoids the possibility of "File name too long" when + creating a temp file when the input file name is very long. + + This also means that other users on the system can no longer + see the input file names in /tmp (or whatever $TMPDIR is) + since the temporary directory will have a generic name. This + usually doesn't matter since on many systems one can see + the arguments given to all processes anyway. + + The number X chars to mktemp where increased from 6 to 10. + + Note that with some shells temp files or dirs won't be used at all. + + src/scripts/xzdiff.in | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +commit 7716dcf9df7f457500cb657314e7a9aea5fedb06 +Author: Lasse Collin +Date: 2014-11-10 15:38:47 +0200 + + liblzma: Fix lzma_mt.preset in lzma_stream_encoder_mt_memusage(). + + It read the filter chain from a wrong variable. This is a similar + bug that was fixed in 9494fb6d0ff41c585326f00aa8f7fe58f8106a5e. + + src/liblzma/common/stream_encoder_mt.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +commit 230fa4a605542c84b4178a57381695a0af4e779b +Author: Lasse Collin +Date: 2014-11-10 14:49:55 +0200 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit 4e4ae08bc7c1711e399c9f2d26eb375d39d08101 +Author: Lasse Collin +Date: 2014-10-29 21:28:25 +0200 + + Update .gitignore files. + + .gitignore | 2 ++ + m4/.gitignore | 3 +++ + 2 files changed, 5 insertions(+) + +commit c923b140b27d1a055db6284e10fd546ad1a7fcdb +Author: Lasse Collin +Date: 2014-10-29 21:15:35 +0200 + + Build: Prepare to support Automake's subdir-objects. + + Due to a bug in Automake, subdir-objects won't be enabled + for now. + + http://debbugs.gnu.org/cgi/bugreport.cgi?bug=17354 + + Thanks to Daniel Richard G. for the original patches. + + configure.ac | 7 ++++++- + src/Makefile.am | 22 +++++++++++++++++++++- + src/liblzma/Makefile.am | 4 ++-- + src/lzmainfo/Makefile.am | 4 ++-- + src/xz/Makefile.am | 10 +++++----- + src/xzdec/Makefile.am | 8 ++++---- + 6 files changed, 40 insertions(+), 15 deletions(-) + +commit 08c2aa16bea0df82828f665d51fba2e0a5e8997f +Author: Lasse Collin +Date: 2014-10-24 20:09:29 +0300 + + Translations: Update the Italian translation. + + Thanks to Milo Casagrande. + + po/it.po | 452 ++++++++++++++++++++++++++++++++++++++------------------------- + 1 file changed, 275 insertions(+), 177 deletions(-) + +commit 2f9f61aa83539c54ff6c118a2693890f0519b3dd +Author: Lasse Collin +Date: 2014-10-18 18:51:45 +0300 + + Translations: Update the Polish translation. + + Thanks to Jakub Bogusz. + + po/pl.po | 332 ++++++++++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 214 insertions(+), 118 deletions(-) + +commit 4f9d233f67aea25e532824d11b7642cf7dee7a76 +Author: Andre Noll +Date: 2014-10-14 17:30:30 +0200 + + l10n: de.po: Change translator email address. + + Although the old address is still working, the new one should + be preferred. So this commit changes all three places in de.po + accordingly. + + Signed-off-by: Andre Noll + + po/de.po | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +commit 00502b2bedad43f0cc167ac17ae0608837ee196b +Author: Andre Noll +Date: 2014-10-14 17:30:29 +0200 + + l10n: de.po: Update German translation + + Signed-off-by: Andre Noll + + po/de.po | 531 +++++++++++++++++++++++++++++++++------------------------------ + 1 file changed, 281 insertions(+), 250 deletions(-) + +commit 706b0496753fb609e69f1570ec603f11162189d1 +Author: Andre Noll +Date: 2014-10-14 17:30:28 +0200 + + l10n: de.po: Fix typo: Schießen -> Schließen. + + That's a funny one since "schießen" means to shoot :) + + Signed-off-by: Andre Noll + + po/de.po | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 7c32e6a935c3d7ee366abad1679bd5f322f0c7d4 +Author: Lasse Collin +Date: 2014-10-09 19:42:26 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit 076258cc458f1e705041ac7a729b15ffe8c5214a +Author: Lasse Collin +Date: 2014-10-09 19:41:51 +0300 + + Add support for AmigaOS/AROS to tuklib_physmem(). + + Thanks to Fredrik Wikstrom. + + m4/tuklib_physmem.m4 | 3 ++- + src/common/tuklib_physmem.c | 7 +++++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +commit efa7b0a210e1baa8e128fc98c5443a944c39ad24 +Author: Lasse Collin +Date: 2014-10-09 18:42:14 +0300 + + xzgrep: Avoid passing both -q and -l to grep. + + The behavior of grep -ql varies: + - GNU grep behaves like grep -q. + - OpenBSD grep behaves like grep -l. + + POSIX doesn't make it 100 % clear what behavior is expected. + Anyway, using both -q and -l at the same time makes no sense + so both options simply should never be used at the same time. + + Thanks to Christian Weisgerber. + + src/scripts/xzgrep.in | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +commit 9c5f76098c9986b48d2fc574a0b764f4cde0c538 +Author: Trần Ngọc Quân +Date: 2014-09-25 09:22:45 +0700 + + l10n: vi.po: Update Vietnamese translation + + Signed-off-by: Trần Ngọc Quân + + po/vi.po | 136 +++++++++++++++++++++++++++++++++++++++------------------------ + 1 file changed, 84 insertions(+), 52 deletions(-) + +commit c4911f2db36d811896c73c008b4218d8fa9a4730 +Author: Lasse Collin +Date: 2014-09-25 18:38:48 +0300 + + Build: Detect supported compiler warning flags better. + + Clang and nowadays also GCC accept any -Wfoobar option + but then may give a warning that an unknown warning option + was specified. To avoid adding unsupported warning options, + the options are now tested with -Werror. + + Thanks to Charles Diza. + + configure.ac | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +commit 76e75522ed6f5c228d55587dee5a997893f6e474 +Author: Lasse Collin +Date: 2014-09-20 21:01:21 +0300 Update NEWS for 5.0.7. NEWS | 11 +++++++++++ 1 file changed, 11 insertions(+) -commit d1b0276aafd441a3d4db9dfd5dd9880e9f834d49 -Author: Lasse Collin -Date: 2014-09-20 20:21:18 +0300 - - liblzma: Fix invalid Libs.private value in liblzma.pc. - - src/liblzma/Makefile.am | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -commit cac72956b1e56788182ac14bfb25519636afd503 +commit d62028b4c1174fc67b6929f126f5eb24c018c700 Author: Lasse Collin Date: 2014-09-20 19:42:56 +0300 @@ -41,26 +605,319 @@ Date: 2014-09-20 19:42:56 +0300 src/liblzma/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 2cdf0875dedca3e89b02ad5ac8aa1109f902ae11 +commit c35de31d4283edad3e57d37ffe939406542cb7bb Author: Lasse Collin -Date: 2014-09-14 19:35:45 +0300 +Date: 2014-09-14 21:54:09 +0300 - Bump version and soname for 5.0.6. + Bump the version number to 5.1.4beta. - src/liblzma/Makefile.am | 2 +- - src/liblzma/api/lzma/version.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) + src/liblzma/api/lzma/version.h | 4 ++-- + src/liblzma/liblzma.map | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) -commit 0168b6c8fbc88cae61b1f5fb41d6c33c9e127967 +commit e9e097e22cacdaa23e5414fea7913535449cb340 Author: Lasse Collin -Date: 2014-09-14 19:33:46 +0300 +Date: 2014-09-14 21:50:13 +0300 - Update NEWS for 5.0.6. + Update NEWS for 5.0.6 and 5.1.4beta. - NEWS | 7 +++++++ - 1 file changed, 7 insertions(+) + NEWS | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) -commit 13337714e89d002af7af48d6853f977de985d7de +commit 642f856bb8562ab66704b1e01ac7bc08b6d0a663 +Author: Lasse Collin +Date: 2014-09-14 21:02:41 +0300 + + Update TODO. + + TODO | 38 ++++++++++++++++++++++++++++++++++---- + 1 file changed, 34 insertions(+), 4 deletions(-) + +commit 6b5e3b9eff5b8cedb2aac5f524d4d60fc8a48124 +Author: Lasse Collin +Date: 2014-08-05 22:32:36 +0300 + + xz: Add --ignore-check. + + src/xz/args.c | 7 +++++++ + src/xz/args.h | 1 + + src/xz/coder.c | 10 +++++++++- + src/xz/message.c | 2 ++ + src/xz/xz.1 | 19 +++++++++++++++++++ + 5 files changed, 38 insertions(+), 1 deletion(-) + +commit 9adbc2ff373f979c917cdfd3679ce0ebd59f1040 +Author: Lasse Collin +Date: 2014-08-05 22:15:07 +0300 + + liblzma: Add support for LZMA_IGNORE_CHECK. + + src/liblzma/api/lzma/container.h | 24 ++++++++++++++++++++++++ + src/liblzma/common/common.h | 1 + + src/liblzma/common/stream_decoder.c | 14 ++++++++++++-- + 3 files changed, 37 insertions(+), 2 deletions(-) + +commit 0e0f34b8e4f1c60ecaec15c2105982381cc9c3e6 +Author: Lasse Collin +Date: 2014-08-05 22:03:30 +0300 + + liblzma: Add support for lzma_block.ignore_check. + + Note that this slightly changes how lzma_block_header_decode() + has been documented. Earlier it said that the .version is set + to the lowest required value, but now it says that the .version + field is kept unchanged if possible. In practice this doesn't + affect any old code, because before this commit the only + possible .version was 0. + + src/liblzma/api/lzma/block.h | 50 ++++++++++++++++++++++++------- + src/liblzma/common/block_buffer_encoder.c | 2 +- + src/liblzma/common/block_decoder.c | 18 ++++++++--- + src/liblzma/common/block_encoder.c | 2 +- + src/liblzma/common/block_header_decoder.c | 12 ++++++-- + src/liblzma/common/block_header_encoder.c | 2 +- + src/liblzma/common/block_util.c | 2 +- + 7 files changed, 68 insertions(+), 20 deletions(-) + +commit 71e1437ab585b46f7a25f5a131557d3d1c0cbaa2 +Author: Lasse Collin +Date: 2014-08-04 19:25:58 +0300 + + liblzma: Use lzma_memcmplen() in the BT3 match finder. + + I had missed this when writing the commit + 5db75054e900fa06ef5ade5f2c21dffdd5d16141. + + Thanks to Jun I Jin. + + src/liblzma/lz/lz_encoder_mf.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +commit 41dc9ea06e1414ebe8ef52afc8fc15b6e3282b04 +Author: Lasse Collin +Date: 2014-08-04 00:25:44 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit 5dcffdbcc23a68abc3ac3539b30be71bc9b5af84 +Author: Lasse Collin +Date: 2014-08-03 21:32:25 +0300 + + liblzma: SHA-256: Optimize the Maj macro slightly. + + The Maj macro is used where multiple things are added + together, so making Maj a sum of two expressions allows + some extra freedom for the compiler to schedule the + instructions. + + I learned this trick from + . + + src/liblzma/check/sha256.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit a9477d1e0c6fd0e47e637d051e7b9e2a5d9af517 +Author: Lasse Collin +Date: 2014-08-03 21:08:12 +0300 + + liblzma: SHA-256: Optimize the way rotations are done. + + This looks weird because the rotations become sequential, + but it helps quite a bit on both 32-bit and 64-bit x86: + + - It requires fewer instructions on two-operand + instruction sets like x86. + + - It requires one register less which matters especially + on 32-bit x86. + + I hope this doesn't hurt other archs. + + I didn't invent this idea myself, but I don't remember where + I saw it first. + + src/liblzma/check/sha256.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +commit 5a76c7c8ee9a0afbeedb1c211db9224260404347 +Author: Lasse Collin +Date: 2014-08-03 20:38:13 +0300 + + liblzma: SHA-256: Remove the GCC #pragma that became unneeded. + + The unrolling in the previous commit should avoid the + situation where a compiler may think that an uninitialized + variable might be accessed. + + src/liblzma/check/sha256.c | 5 ----- + 1 file changed, 5 deletions(-) + +commit 9a096f8e57509775c331950b8351bbca77bdcfa8 +Author: Lasse Collin +Date: 2014-08-03 20:33:38 +0300 + + liblzma: SHA-256: Unroll a little more. + + This way a branch isn't needed for each operation + to choose between blk0 and blk2, and still the code + doesn't grow as much as it would with full unrolling. + + src/liblzma/check/sha256.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +commit bc7650d87bf27f85f1a2a806dc2db1780e09e6a5 +Author: Lasse Collin +Date: 2014-08-03 19:56:43 +0300 + + liblzma: SHA-256: Do the byteswapping without a temporary buffer. + + src/liblzma/check/sha256.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +commit 544aaa3d13554e8640f9caf7db717a96360ec0f6 +Author: Lasse Collin +Date: 2014-07-25 22:38:28 +0300 + + liblzma: Use lzma_memcmplen() in normal mode of LZMA. + + Two locations were not changed yet because the simplest change + assumes that the initial "len" may be greater than "limit". + + src/liblzma/lzma/lzma_encoder_optimum_normal.c | 20 +++++--------------- + 1 file changed, 5 insertions(+), 15 deletions(-) + +commit f48fce093b07aeda95c18850f5e086d9f2383380 +Author: Lasse Collin +Date: 2014-07-25 22:30:38 +0300 + + liblzma: Simplify LZMA fast mode code by using memcmp(). + + src/liblzma/lzma/lzma_encoder_optimum_fast.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +commit 6bf5308e34e23dede5b301b1b9b4f131dacd9218 +Author: Lasse Collin +Date: 2014-07-25 22:29:49 +0300 + + liblzma: Use lzma_memcmplen() in fast mode of LZMA. + + src/liblzma/lzma/lzma_encoder_optimum_fast.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +commit 353212137e51e45b105a3a3fc2e6879f1cf0d492 +Author: Lasse Collin +Date: 2014-07-25 21:16:23 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit 5db75054e900fa06ef5ade5f2c21dffdd5d16141 +Author: Lasse Collin +Date: 2014-07-25 21:15:07 +0300 + + liblzma: Use lzma_memcmplen() in the match finders. + + This doesn't change the match finder output. + + src/liblzma/lz/lz_encoder.c | 13 ++++++++++++- + src/liblzma/lz/lz_encoder_mf.c | 33 +++++++++++---------------------- + 2 files changed, 23 insertions(+), 23 deletions(-) + +commit e1c8f1d01f4a4e2136173edab2dc63c71ef038f4 +Author: Lasse Collin +Date: 2014-07-25 20:57:20 +0300 + + liblzma: Add lzma_memcmplen() for fast memory comparison. + + This commit just adds the function. Its uses will be in + separate commits. + + This hasn't been tested much yet and it's perhaps a bit early + to commit it but if there are bugs they should get found quite + quickly. + + Thanks to Jun I Jin from Intel for help and for pointing out + that string comparison needs to be optimized in liblzma. + + configure.ac | 13 +++ + src/liblzma/common/Makefile.inc | 1 + + src/liblzma/common/memcmplen.h | 170 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 184 insertions(+) + +commit 765735cf52e5123586e74a51b9c073b5257f631f +Author: Lasse Collin +Date: 2014-07-12 21:10:09 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit 59da01785ef66c7e62f36e70ca808fd2824bb995 +Author: Lasse Collin +Date: 2014-07-12 20:06:08 +0300 + + Translations: Add Vietnamese translation. + + Thanks to Trần Ngọc Quân. + + po/LINGUAS | 1 + + po/vi.po | 1007 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 1008 insertions(+) + +commit 17215f751c354852700e7f8592ccf319570a0721 +Author: Lasse Collin +Date: 2014-06-29 20:54:14 +0300 + + xz: Update the help message of a few options. + + Updated: --threads, --block-size, and --block-list + Added: --flush-timeout + + src/xz/message.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +commit 96864a6ddf91ad693d102ea165f3d7918744d582 +Author: Lasse Collin +Date: 2014-06-18 22:07:06 +0300 + + xz: Use lzma_cputhreads() instead of own copy of tuklib_cpucores(). + + src/xz/Makefile.am | 1 - + src/xz/hardware.c | 12 +++++++++--- + 2 files changed, 9 insertions(+), 4 deletions(-) + +commit a115cc3748482e277f42a968baa3cd266f031dba +Author: Lasse Collin +Date: 2014-06-18 22:04:24 +0300 + + liblzma: Add lzma_cputhreads(). + + src/liblzma/Makefile.am | 8 +++++++- + src/liblzma/api/lzma/hardware.h | 14 ++++++++++++++ + src/liblzma/common/Makefile.inc | 1 + + src/liblzma/common/hardware_cputhreads.c | 22 ++++++++++++++++++++++ + src/liblzma/liblzma.map | 1 + + 5 files changed, 45 insertions(+), 1 deletion(-) + +commit 3ce3e7976904fbab4e6482bafa442856f77a51fa +Author: Lasse Collin +Date: 2014-06-18 19:11:52 +0300 + + xz: Check for filter chain compatibility for --flush-timeout. + + This avoids LZMA_PROG_ERROR from lzma_code() with filter chains + that don't support LZMA_SYNC_FLUSH. + + src/xz/coder.c | 30 +++++++++++++++++++++--------- + 1 file changed, 21 insertions(+), 9 deletions(-) + +commit 381ac14ed79e5d38809f251705be8b3193bba417 Author: Lasse Collin Date: 2014-06-13 19:21:54 +0300 @@ -69,7 +926,7 @@ Date: 2014-06-13 19:21:54 +0300 tests/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) -commit ccc728d8290c0464c7af62790b1c5528eceaae35 +commit 4244b65b06d5ecaf6f9dd0387ac7e3166bd2364e Author: Lasse Collin Date: 2014-06-13 18:58:22 +0300 @@ -83,7 +940,7 @@ Date: 2014-06-13 18:58:22 +0300 tests/xzgrep_expected_output | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 11 deletions(-) -commit 948f5865fe65061e215baa8ed63be570bae152ea +commit 1e60f2c0a0ee6c18b02943ce56214799a70aac26 Author: Lasse Collin Date: 2014-06-11 21:03:25 +0300 @@ -95,7 +952,7 @@ Date: 2014-06-11 21:03:25 +0300 tests/test_scripts.sh | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) -commit 64228d0d5cd75af31e5c330cc3a792016413fabf +commit ceca37901783988204caaf40dff4623d535cc789 Author: Lasse Collin Date: 2014-06-11 20:43:28 +0300 @@ -112,7 +969,91 @@ Date: 2014-06-11 20:43:28 +0300 src/scripts/xzgrep.in | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) -commit 98d3368ef4bff0face78d6932f2156730c8cb658 +commit 8c19216baccb92d011694590df8a1262da2e980c +Author: Lasse Collin +Date: 2014-06-09 21:21:24 +0300 + + xz: Force single-threaded mode when --flush-timeout is used. + + src/xz/coder.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +commit 87f1a24810805187d7bbc8ac5512e7eec307ddf5 +Author: Lasse Collin +Date: 2014-05-25 22:05:39 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit da1718f266fcfc091e7bf08aae1bc986d0e6cc6b +Author: Lasse Collin +Date: 2014-05-25 21:45:56 +0300 + + liblzma: Use lzma_alloc_zero() in LZ encoder initialization. + + This avoids a memzero() call for a newly-allocated memory, + which can be expensive when encoding small streams with + an over-sized dictionary. + + To avoid using lzma_alloc_zero() for memory that doesn't + need to be zeroed, lzma_mf.son is now allocated separately, + which requires handling it separately in normalize() too. + + Thanks to Vincenzo Innocente for reporting the problem. + + src/liblzma/lz/lz_encoder.c | 84 ++++++++++++++++++++++-------------------- + src/liblzma/lz/lz_encoder.h | 2 +- + src/liblzma/lz/lz_encoder_mf.c | 31 +++++++++------- + 3 files changed, 62 insertions(+), 55 deletions(-) + +commit 28af24e9cf2eb259997c85dce13d4c97b3daa47a +Author: Lasse Collin +Date: 2014-05-25 19:25:57 +0300 + + liblzma: Add the internal function lzma_alloc_zero(). + + src/liblzma/common/common.c | 21 +++++++++++++++++++++ + src/liblzma/common/common.h | 6 ++++++ + 2 files changed, 27 insertions(+) + +commit ed9ac85822c490e34b68c259afa0b385d21d1c40 +Author: Lasse Collin +Date: 2014-05-08 18:03:09 +0300 + + xz: Fix uint64_t vs. size_t which broke 32-bit build. + + Thanks to Christian Hesse. + + src/xz/coder.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit d716acdae3fa7996f9e68a7bac012e6d8d13dd02 +Author: Lasse Collin +Date: 2014-05-04 11:09:11 +0300 + + Docs: Update comments to refer to lzma/lzma12.h in example programs. + + doc/examples/03_compress_custom.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +commit 4d5b7b3fda31241ca86ed35e08e73f776ee916e0 +Author: Lasse Collin +Date: 2014-05-04 11:07:17 +0300 + + liblzma: Rename the private API header lzma/lzma.h to lzma/lzma12.h. + + It can be confusing that two header files have the same name. + The public API file is still lzma.h. + + src/liblzma/api/Makefile.am | 2 +- + src/liblzma/api/lzma.h | 2 +- + src/liblzma/api/lzma/lzma.h | 420 ------------------------------------------ + src/liblzma/api/lzma/lzma12.h | 420 ++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 422 insertions(+), 422 deletions(-) + +commit 1555a9c5664afc7893a2b75e9970105437f01ef1 Author: Lasse Collin Date: 2014-04-25 17:53:42 +0300 @@ -127,7 +1068,7 @@ Date: 2014-04-25 17:53:42 +0300 src/xzdec/Makefile.am | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) -commit ba3b5dd082db2cb5973e877a74221d739c663fb4 +commit 56056571df3377eaa6ae6233b3ccc5d72e81d43d Author: Lasse Collin Date: 2014-04-25 17:44:26 +0300 @@ -138,7 +1079,7 @@ Date: 2014-04-25 17:44:26 +0300 configure.ac | 6 ++++++ 3 files changed, 14 insertions(+) -commit 3d4575f2367fe8f1f2dcacba014e6c0aef388535 +commit 6de61d8721097a6214810841aa85b08e303ac538 Author: Lasse Collin Date: 2014-04-24 18:06:24 +0300 @@ -156,7 +1097,7 @@ Date: 2014-04-24 18:06:24 +0300 INSTALL | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) -commit b9f0584e3eff421eadbb6604de0b0b40bf87e129 +commit 54df428799a8d853639b753d0e6784694d73eb3e Author: Lasse Collin Date: 2014-04-09 17:26:10 +0300 @@ -172,16 +1113,82 @@ Date: 2014-04-09 17:26:10 +0300 src/xz/signals.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) -commit cc41bcaf77c9c27ec09ef033fb3300e994e828e6 +commit 5876ca27daa1429676b1160007d9688266907f00 Author: Lasse Collin -Date: 2014-04-26 08:45:49 +0300 +Date: 2014-01-29 20:19:41 +0200 + + Docs: Add example program for threaded encoding. + + I didn't add -DLZMA_UNSTABLE to Makefile so one has to + specify it manually as long as LZMA_UNSTABLE is needed. + + doc/examples/04_compress_easy_mt.c | 184 +++++++++++++++++++++++++++++++++++++ + doc/examples/Makefile | 3 +- + 2 files changed, 186 insertions(+), 1 deletion(-) + +commit 9494fb6d0ff41c585326f00aa8f7fe58f8106a5e +Author: Lasse Collin +Date: 2014-01-29 20:13:51 +0200 + + liblzma: Fix lzma_mt.preset not working with lzma_stream_encoder_mt(). + + It read the filter chain from a wrong variable. + + src/liblzma/common/stream_encoder_mt.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit 673a4cb53de3a715685cb1b836da57a3c7dcd43c +Author: Lasse Collin +Date: 2014-01-20 11:20:40 +0200 + + liblzma: Fix typo in a comment. + + src/liblzma/api/lzma/block.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit ad96a871a1470eb76d6233d3890ce9338047b7a3 +Author: Lasse Collin +Date: 2014-01-12 19:38:43 +0200 + + Windows: Add config.h for building liblzma with MSVC 2013. + + This is for building liblzma. Building xz tool too requires + a little more work. Maybe it will be supported, but for most + MSVC users it's enough to be able to build liblzma. + + C99 support in MSVC 2013 is almost usable which is a big + improvement over earlier versions. It's "almost" because + there's a dumb bug that breaks mixed declarations after + an "if" statements unless the "if" statement uses braces: + + https://connect.microsoft.com/VisualStudio/feedback/details/808650/visual-studio-2013-c99-compiler-bug + https://connect.microsoft.com/VisualStudio/feedback/details/808472/c99-support-of-mixed-declarations-and-statements-fails-with-certain-types-and-constructs + + Hopefully it will get fixed. Then liblzma should be + compilable with MSVC 2013 without patching. + + windows/config.h | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 139 insertions(+) + +commit 3d5c090872fab4212b57c290e8ed4d02c78c1737 +Author: Lasse Collin +Date: 2014-01-12 17:41:14 +0200 xz: Fix a comment. src/xz/coder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) -commit e34025d666852839388f997d076e3577847dd10f +commit 69fd4e1c932c7975476a0143c86e45d81b60d3f9 +Author: Lasse Collin +Date: 2014-01-12 17:04:33 +0200 + + Windows: Add MSVC defines for inline and restrict keywords. + + src/common/sysdefs.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +commit a19d9e8575ee6647cd9154cf1f20203f1330485f Author: Lasse Collin Date: 2014-01-12 16:44:52 +0200 @@ -193,7 +1200,7 @@ Date: 2014-01-12 16:44:52 +0200 src/liblzma/lzma/lzma_encoder_presets.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) -commit 0b6168974f1fac3a06157039235b66e4161b9b42 +commit e28528f1c867b2ed4ac91195ad08efb9bb8a6263 Author: Lasse Collin Date: 2014-01-12 12:50:30 +0200 @@ -204,7 +1211,7 @@ Date: 2014-01-12 12:50:30 +0200 src/liblzma/check/sha256.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 41e436076cfdcccc7e853de73b0d56b3d6d42053 +commit 5ad1effc45adfb7dabc9a98e79736077e6b7e2d5 Author: Lasse Collin Date: 2014-01-12 12:17:08 +0200 @@ -217,16 +1224,17 @@ Date: 2014-01-12 12:17:08 +0200 src/xz/suffix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit c33efefd4ef0931e5795e13725d4bd2203571ce0 +commit 3e62c68d75b5a3fdd46dbb34bb335d73289860d5 Author: Lasse Collin -Date: 2014-04-26 08:37:00 +0300 +Date: 2014-01-12 12:11:36 +0200 Fix typos in comments. + src/common/mythread.h | 2 +- src/liblzma/check/crc32_fast.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) + 2 files changed, 2 insertions(+), 2 deletions(-) -commit e560c82f1f5693d88db9dc71f656436135f17595 +commit e90ea601fb72867ec04adf456cbe4bf9520fd412 Author: Lasse Collin Date: 2013-11-26 18:20:16 +0200 @@ -235,7 +1243,7 @@ Date: 2013-11-26 18:20:16 +0200 THANKS | 1 + 1 file changed, 1 insertion(+) -commit 05192b32e553eac5dfbd646b6102d10187f29a05 +commit b22e94d8d15764416354e04729382a7371ae2c30 Author: Lasse Collin Date: 2013-11-26 18:20:09 +0200 @@ -246,7 +1254,60 @@ Date: 2013-11-26 18:20:09 +0200 src/liblzma/api/lzma/block.h | 3 +++ 1 file changed, 3 insertions(+) -commit 0f35eafe51db7b1eb0711bc8cc829ea6896b34f4 +commit d1cd8b1cb824b72421d1ee370e628024d2fcbec4 +Author: Lasse Collin +Date: 2013-11-12 16:38:57 +0200 + + xz: Update the man page about --block-size and --block-list. + + src/xz/xz.1 | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +commit 76be7c612e6bcc38724488ccc3b8bcb1cfec9f0a +Author: Lasse Collin +Date: 2013-11-12 16:30:53 +0200 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit dd750acbe2259d75444ef0f8da2d4bacc90d7afc +Author: Lasse Collin +Date: 2013-11-12 16:29:48 +0200 + + xz: Make --block-list and --block-size work together in single-threaded. + + Previously, --block-list and --block-size only worked together + in threaded mode. Boundaries are specified by --block-list, but + --block-size specifies the maximum size for a Block. Now this + works in single-threaded mode too. + + Thanks to James M Leddy for the original patch. + + src/xz/coder.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 75 insertions(+), 15 deletions(-) + +commit ae222fe9805d0161d022d75ba8485dab8bf6d7d5 +Author: Lasse Collin +Date: 2013-10-26 13:26:14 +0300 + + Bump the version number to 5.1.3alpha. + + src/liblzma/api/lzma/version.h | 2 +- + src/liblzma/liblzma.map | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +commit 2193837a6a597cd3bf4e9ddf49421a5697d8e155 +Author: Lasse Collin +Date: 2013-10-26 13:25:02 +0300 + + Update NEWS for 5.1.3alpha. + + NEWS | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +commit ed48e75e2763876173aef8902da407a8eb28854b Author: Lasse Collin Date: 2013-10-26 12:47:04 +0300 @@ -255,7 +1316,120 @@ Date: 2013-10-26 12:47:04 +0300 TODO | 4 ---- 1 file changed, 4 deletions(-) -commit fc9eaf81d718488b052e5c65f9d6f08acc858873 +commit 841da0352d79a56a44796a4c39163429c9f039a3 +Author: Lasse Collin +Date: 2013-10-25 22:41:28 +0300 + + xz: Document behavior of --block-list with threads. + + This needs to be updated before 5.2.0. + + src/xz/xz.1 | 24 +++++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +commit 56feb8665b78c1032aabd53c619c62af51defe64 +Author: Lasse Collin +Date: 2013-10-22 20:03:12 +0300 + + xz: Document --flush-timeout=TIMEOUT on the man page. + + src/xz/xz.1 | 37 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 36 insertions(+), 1 deletion(-) + +commit ba413da1d5bb3324287cf3174922acd921165971 +Author: Lasse Collin +Date: 2013-10-22 19:51:55 +0300 + + xz: Take advantage of LZMA_FULL_BARRIER with --block-list. + + Now if --block-list is used in threaded mode, the encoder + won't need to flush at each Block boundary specified via + --block-list. This improves performance a lot, making + threading helpful with --block-list. + + The flush timer was reset after LZMA_FULL_FLUSH but since + LZMA_FULL_BARRIER doesn't flush, resetting the timer is + no longer done. + + src/xz/coder.c | 32 +++++++++++++++----------------- + 1 file changed, 15 insertions(+), 17 deletions(-) + +commit 0cd45fc2bc5537de287a0bc005e2d67467a92148 +Author: Lasse Collin +Date: 2013-10-02 20:05:23 +0300 + + liblzma: Support LZMA_FULL_FLUSH and _BARRIER in threaded encoder. + + Now --block-list=SIZES works with in the threaded mode too, + although the performance is still bad due to the use of + LZMA_FULL_FLUSH instead of the new LZMA_FULL_BARRIER. + + src/liblzma/common/stream_encoder_mt.c | 55 ++++++++++++++++++++++++---------- + 1 file changed, 39 insertions(+), 16 deletions(-) + +commit 97bb38712f414fabecca908af2e38a12570293fd +Author: Lasse Collin +Date: 2013-10-02 12:55:11 +0300 + + liblzma: Add LZMA_FULL_BARRIER support to single-threaded encoder. + + In the single-threaded encoder LZMA_FULL_BARRIER is simply + an alias for LZMA_FULL_FLUSH. + + src/liblzma/api/lzma/base.h | 37 ++++++++++++++++++++++++++++++------- + src/liblzma/common/common.c | 17 +++++++++++++++-- + src/liblzma/common/common.h | 7 ++++++- + src/liblzma/common/stream_encoder.c | 4 +++- + 4 files changed, 54 insertions(+), 11 deletions(-) + +commit fef0c6b410c08e581c9178700a4e7599f0895ff9 +Author: Lasse Collin +Date: 2013-09-17 11:57:51 +0300 + + liblzma: Add block_buffer_encoder.h into Makefile.inc. + + This should have been in b465da5988dd59ad98fda10c2e4ea13d0b9c73bc. + + src/liblzma/common/Makefile.inc | 1 + + 1 file changed, 1 insertion(+) + +commit 8083e03291b6d21c0f538163e187b4e8cd5594e4 +Author: Lasse Collin +Date: 2013-09-17 11:55:38 +0300 + + xz: Add a missing test for TUKLIB_DOSLIKE. + + src/xz/file_io.c | 2 ++ + 1 file changed, 2 insertions(+) + +commit 6b44b4a775fe29ecc7bcb7996e086e3bc09e5fd0 +Author: Lasse Collin +Date: 2013-09-17 11:52:28 +0300 + + Add native threading support on Windows. + + Now liblzma only uses "mythread" functions and types + which are defined in mythread.h matching the desired + threading method. + + Before Windows Vista, there is no direct equivalent to + pthread condition variables. Since this package doesn't + use pthread_cond_broadcast(), pre-Vista threading can + still be kept quite simple. The pre-Vista code doesn't + use anything that wasn't already available in Windows 95, + so the binaries should run even on Windows 95 if someone + happens to care. + + INSTALL | 41 ++- + configure.ac | 118 ++++++-- + src/common/mythread.h | 513 ++++++++++++++++++++++++++------- + src/liblzma/common/stream_encoder_mt.c | 83 +++--- + src/xz/coder.c | 8 +- + windows/README-Windows.txt | 2 +- + windows/build.bash | 23 +- + 7 files changed, 573 insertions(+), 215 deletions(-) + +commit ae0ab74a88d5b9b15845f1d9a24ade4349a54f9f Author: Lasse Collin Date: 2013-09-11 14:40:35 +0300 @@ -267,7 +1441,7 @@ Date: 2013-09-11 14:40:35 +0300 configure.ac | 2 -- 1 file changed, 2 deletions(-) -commit 090c69dda59e00fc86d0792879bd921bb1156029 +commit 72975df6c8c59aaf849138ab3606e8fb6970596a Author: Lasse Collin Date: 2013-09-09 20:37:03 +0300 @@ -291,7 +1465,35 @@ Date: 2013-09-09 20:37:03 +0300 src/liblzma/Makefile.am | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) -commit 1f35331332273de01c46897cafdb37f8e6e285db +commit 1c2b6e7e8382ed390f53e140f160488bb2205ecc +Author: Lasse Collin +Date: 2013-08-04 15:24:09 +0300 + + Fix the previous commit which broke the build. + + Apparently I didn't even compile-test the previous commit. + + Thanks to Christian Hesse. + + src/common/tuklib_cpucores.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 124eb69c7857f618b4807588c51bc9ba21bf8691 +Author: Lasse Collin +Date: 2013-08-03 13:52:58 +0300 + + Windows: Add Windows support to tuklib_cpucores(). + + It is used for Cygwin too. I'm not sure if that is + a good or bad idea. + + Thanks to Vincent Torri. + + m4/tuklib_cpucores.m4 | 19 +++++++++++++++++-- + src/common/tuklib_cpucores.c | 13 ++++++++++++- + 2 files changed, 29 insertions(+), 3 deletions(-) + +commit eada8a875ce3fd521cb42e4ace2624d3d49c5f35 Author: Anders F Bjorklund Date: 2013-08-02 15:59:46 +0200 @@ -300,7 +1502,7 @@ Date: 2013-08-02 15:59:46 +0200 macosx/build.sh | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) -commit 1415f1d94644f28e07d544bc1e06b0636081abee +commit be0100d01ca6a75899d051bee00acf17e6dc0c15 Author: Anders F Bjorklund Date: 2013-08-02 15:58:44 +0200 @@ -309,7 +1511,7 @@ Date: 2013-08-02 15:58:44 +0200 macosx/build.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) -commit 41913949b93414a21ae9fb1a8e9b7cdde8b37f98 +commit 416729e2d743f4b2fe9fd438eedeb98adce033c3 Author: Anders F Bjorklund Date: 2011-08-07 13:13:30 +0200 @@ -318,7 +1520,16 @@ Date: 2011-08-07 13:13:30 +0200 macosx/build.sh | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) -commit 3dffda33f47dc220bb1738564fe02effa9da4c8e +commit 16581080e5f29f9a4e49efece21c5bf572323acc +Author: Lasse Collin +Date: 2013-07-15 14:08:41 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit 3e2b198ba37b624efd9c7caee2a435dc986b46c6 Author: Lasse Collin Date: 2013-07-15 14:08:02 +0300 @@ -329,7 +1540,110 @@ Date: 2013-07-15 14:08:02 +0300 configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit b69900ed0b2f914fc6c0a180dcb522dbe5b80ea7 +commit dee6ad3d5915422bc30a6821efeacaeb8ca8ef00 +Author: Lasse Collin +Date: 2013-07-04 14:18:46 +0300 + + xz: Add preliminary support for --flush-timeout=TIMEOUT. + + When --flush-timeout=TIMEOUT is used, xz will use + LZMA_SYNC_FLUSH if read() would block and at least + TIMEOUT milliseconds has elapsed since the previous flush. + + This can be useful in realtime-like use cases where the + data is simultanously decompressed by another process + (possibly on a different computer). If new uncompressed + input data is produced slowly, without this option xz could + buffer the data for a long time until it would become + decompressible from the output. + + If TIMEOUT is 0, the feature is disabled. This is the default. + + This commit affects the compression side. Using xz for + the decompression side for the above purpose doesn't work + yet so well because there is quite a bit of input and + output buffering when decompressing. + + The --long-help or man page were not updated yet. + The details of this feature may change. + + src/xz/args.c | 7 +++++++ + src/xz/coder.c | 46 +++++++++++++++++++++++++++++++++++----------- + src/xz/file_io.c | 46 ++++++++++++++++++++++++++++++++++++---------- + 3 files changed, 78 insertions(+), 21 deletions(-) + +commit fa381acaf9a29a8114e1c0a97de99bab9adb014e +Author: Lasse Collin +Date: 2013-07-04 13:41:03 +0300 + + xz: Don't set src_eof=true after an I/O error because it's useless. + + src/xz/file_io.c | 3 --- + 1 file changed, 3 deletions(-) + +commit ea00545beace5b950f709ec21e46878e0f448678 +Author: Lasse Collin +Date: 2013-07-04 13:25:11 +0300 + + xz: Fix the test when to read more input. + + Testing for end of file was no longer correct after full flushing + became possible with --block-size=SIZE and --block-list=SIZES. + There was no bug in practice though because xz just made a few + unneeded zero-byte reads. + + src/xz/coder.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +commit 736903c64bef394c06685d79908e397bcb08b88f +Author: Lasse Collin +Date: 2013-07-04 12:51:57 +0300 + + xz: Move some of the timing code into mytime.[hc]. + + This switches units from microseconds to milliseconds. + + New clock_gettime(CLOCK_MONOTONIC) will be used if available. + There is still a fallback to gettimeofday(). + + src/xz/Makefile.am | 2 ++ + src/xz/coder.c | 5 +++ + src/xz/message.c | 54 +++++++++------------------------ + src/xz/mytime.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/xz/mytime.h | 47 ++++++++++++++++++++++++++++ + src/xz/private.h | 1 + + 6 files changed, 158 insertions(+), 40 deletions(-) + +commit 24edf8d807e24ffaa1e793114d94cca3b970027d +Author: Lasse Collin +Date: 2013-07-01 14:35:03 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit c0627b3fceacfa1ed162f5f55235360ea26f569a +Author: Lasse Collin +Date: 2013-07-01 14:34:11 +0300 + + xz: Silence a warning seen with _FORTIFY_SOURCE=2. + + Thanks to Christian Hesse. + + src/xz/file_io.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +commit 1936718bb38ee394bd89836fdd4eabc0beb02443 +Author: Lasse Collin +Date: 2013-06-30 19:40:11 +0300 + + Update NEWS for 5.0.5. + + NEWS | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 52 insertions(+) + +commit a37ae8b5eb6093a530198f109c6f7a538c80ecf0 Author: Lasse Collin Date: 2013-06-30 18:02:27 +0300 @@ -346,26 +1660,24 @@ Date: 2013-06-30 18:02:27 +0300 src/xzdec/xzdec.1 | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) -commit cf4a1e1879d89be314ef3c064bd2656ea452f87e +commit cdba9ddd870ae72fd6219a125662c20ec997f86c Author: Lasse Collin -Date: 2013-06-30 15:55:09 +0300 +Date: 2013-06-29 15:59:13 +0300 - Update NEWS for 5.0.5. + xz: Use non-blocking I/O for the output file. + + Now both reading and writing should be without + race conditions with signals. + + They might still be signal handling issues left. + Signals are blocked during many operations to avoid + EINTR but it may cause problems e.g. if writing to + stderr blocks when trying to display an error message. - NEWS | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 52 insertions(+) + src/xz/file_io.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 49 insertions(+), 8 deletions(-) -commit cb94bb6d1f34e1e93c2d634ea9c3b7dfb3981d05 -Author: Lasse Collin -Date: 2013-06-30 15:54:38 +0300 - - Bump version and soname for 5.0.5. - - src/liblzma/Makefile.am | 2 +- - src/liblzma/api/lzma/version.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -commit b7dee202d5b041ccae028d0c5433b83cecbe9e5d +commit e61a5c95da3fe31281d959e5e842885a8ba2b5bd Author: Lasse Collin Date: 2013-06-28 23:56:17 +0300 @@ -377,7 +1689,36 @@ Date: 2013-06-28 23:56:17 +0300 src/xz/file_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 265e7b44d804b47373f10b7da28350db7611cea6 +commit 9dc319eabb34a826f4945f91c71620f14a60e9e2 +Author: Lasse Collin +Date: 2013-06-28 23:48:05 +0300 + + xz: Use the self-pipe trick to avoid a race condition with signals. + + It is possible that a signal to set user_abort arrives right + before a blocking system call is made. In this case the call + may block until another signal arrives, while the wanted + behavior is to make xz clean up and exit as soon as possible. + + After this commit, the race condition is avoided with the + input side which already uses non-blocking I/O. The output + side still uses blocking I/O and thus has the race condition. + + src/xz/file_io.c | 56 ++++++++++++++++++++++++++++++++++++++++++++------------ + src/xz/file_io.h | 8 ++++++++ + src/xz/signals.c | 5 +++++ + 3 files changed, 57 insertions(+), 12 deletions(-) + +commit 3541bc79d0cfabc0ad155c99bfdad1289f17fec3 +Author: Lasse Collin +Date: 2013-06-28 22:51:02 +0300 + + xz: Use non-blocking I/O for the input file. + + src/xz/file_io.c | 156 +++++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 111 insertions(+), 45 deletions(-) + +commit 78673a08bed5066c81e8a8e90d20e670c28ecfd5 Author: Lasse Collin Date: 2013-06-28 18:46:13 +0300 @@ -388,7 +1729,7 @@ Date: 2013-06-28 18:46:13 +0300 src/xz/file_io.c | 4 ---- 1 file changed, 4 deletions(-) -commit 78c2f8db902195468b8249c432252a6b281db836 +commit a616fdad34b48b2932ef03fb87309dcc8b829527 Author: Lasse Collin Date: 2013-06-28 18:09:47 +0300 @@ -403,7 +1744,7 @@ Date: 2013-06-28 18:09:47 +0300 src/xz/file_io.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) -commit 91750dff8f2c654ff636f12a2acdffe5492374b3 +commit 4a08a6e4c61c65ab763ab314100a6d7a3bb89298 Author: Lasse Collin Date: 2013-06-28 17:36:47 +0300 @@ -424,7 +1765,21 @@ Date: 2013-06-28 17:36:47 +0300 src/xz/file_io.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) -commit e11888a79a4a77a69afde60445880d44f63d01aa +commit b790b435daa3351067f80a5973b647f8d55367a2 +Author: Lasse Collin +Date: 2013-06-28 14:55:37 +0300 + + xz: Fix assertion related to posix_fadvise(). + + Input file can be a FIFO or something else that doesn't + support posix_fadvise() so don't check the return value + even with an assertion. Nothing bad happens if the call + to posix_fadvise() fails. + + src/xz/file_io.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +commit 84d2da6c9dc252f441deb7626c2522202b005d4d Author: Lasse Collin Date: 2013-06-26 13:30:57 +0300 @@ -438,7 +1793,7 @@ Date: 2013-06-26 13:30:57 +0300 src/xz/list.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) -commit f39ddd88f3222219ada88998cf30abfdd3e0e96c +commit 9376f5f8f762296f2173d61af9101112c36f38c0 Author: Lasse Collin Date: 2013-06-26 12:17:00 +0300 @@ -456,7 +1811,31 @@ Date: 2013-06-26 12:17:00 +0300 configure.ac | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) -commit cb84e278027a90e9827a6f4d3bb0b4d4744a2fbb +commit b7e200d7bd0a3c7c171c13ad37d68296d6f73374 +Author: Lasse Collin +Date: 2013-06-23 18:59:13 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit 46540e4c10923e363741ff5aab99e79fc0ce6ee8 +Author: Lasse Collin +Date: 2013-06-23 18:57:23 +0300 + + liblzma: Avoid a warning about a shadowed variable. + + On Mac OS X wait() is declared in that + we include one way or other so don't use "wait" as + a variable name. + + Thanks to Christian Kujau. + + src/liblzma/common/stream_encoder_mt.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +commit ebb501ec73cecc546c67117dd01b5e33c90bfb4a Author: Lasse Collin Date: 2013-06-23 17:36:47 +0300 @@ -471,16 +1850,16 @@ Date: 2013-06-23 17:36:47 +0300 src/xz/list.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) -commit f01780fce454c7489f7dcbf806299b50da5f51b7 +commit c09e91dd236d3cabee0fc48312b3dc8cceae41ab Author: Lasse Collin -Date: 2013-06-26 10:58:58 +0300 +Date: 2013-06-21 22:08:11 +0300 Update THANKS. THANKS | 2 ++ 1 file changed, 2 insertions(+) -commit d98ede7d700b892e32d9c2f46563b6ebc566786d +commit eb6ca9854b8eb9fbf72497c1cf608d6b19d2d494 Author: Lasse Collin Date: 2013-06-21 22:04:45 +0300 @@ -491,7 +1870,7 @@ Date: 2013-06-21 22:04:45 +0300 src/xz/xz.1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) -commit 19b447b64b3f520cd5b11429000b092f7c76709b +commit 0c0a1947e6ad90a0a10b7a5c39f6ab99a0aa5c93 Author: Lasse Collin Date: 2013-06-21 21:54:59 +0300 @@ -506,7 +1885,7 @@ Date: 2013-06-21 21:54:59 +0300 src/xz/xz.1 | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) -commit 45edf2966fc9a4d2eae8f84b2fa027fb4fa1df8b +commit 2fcda89939c903106c429e109083d43d894049e0 Author: Lasse Collin Date: 2013-06-21 21:50:26 +0300 @@ -534,17 +1913,7 @@ Date: 2013-06-21 21:50:26 +0300 src/xz/coder.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) -commit b065984e5a9272eb50bc0c6d3731e6199c0ae8a8 -Author: Lasse Collin -Date: 2011-04-08 17:53:05 +0300 - - xz: Change size_t to uint32_t in a few places. - - src/xz/coder.c | 6 +++--- - src/xz/coder.h | 2 +- - 2 files changed, 4 insertions(+), 4 deletions(-) - -commit 32be621f52f2e1686db88baa7b01dc1ae338f426 +commit 97379c5ea758da3f8b0bc444d5f7fa43753ce610 Author: Lasse Collin Date: 2013-04-27 22:07:46 +0300 @@ -558,7 +1927,7 @@ Date: 2013-04-27 22:07:46 +0300 configure.ac | 1 + 1 file changed, 1 insertion(+) -commit efb07cfba65e9e05984c02cd796c1b0338ce04dc +commit 8957c58609d3987c58aa72b96c436cf565cc4917 Author: Lasse Collin Date: 2013-04-15 19:29:09 +0300 @@ -575,7 +1944,7 @@ Date: 2013-04-15 19:29:09 +0300 src/xzdec/xzdec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) -commit e3c8be13699e2813f5e2879d8187444b46d82d89 +commit ed886e1a92534a24401d0e99c11f1dcff3b5220a Author: Lasse Collin Date: 2013-04-05 19:25:40 +0300 @@ -584,7 +1953,7 @@ Date: 2013-04-05 19:25:40 +0300 THANKS | 2 ++ 1 file changed, 2 insertions(+) -commit ad8282efe483612f6b5544f9a0d2e4914fb2532a +commit 5019413a055ce29e660dbbf15e02443cb5a26c59 Author: Jeff Bastian Date: 2013-04-03 13:59:17 +0200 @@ -595,9 +1964,9 @@ Date: 2013-04-03 13:59:17 +0200 src/scripts/xzgrep.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 9271a3eb0e022b23e8712154be851d0afe4c02e4 +commit 5ea900cb5ad862bca81316729f92357c1fc040ce Author: Lasse Collin -Date: 2013-04-05 19:34:09 +0300 +Date: 2013-03-23 22:25:15 +0200 liblzma: Be less picky in lzma_alone_decoder(). @@ -618,17 +1987,56 @@ Date: 2013-04-05 19:34:09 +0300 Reported here: http://sourceforge.net/projects/lzmautils/forums/forum/708858/topic/7068827 - - Conflicts: - src/liblzma/common/alone_decoder.c - src/liblzma/common/alone_decoder.h src/liblzma/common/alone_decoder.c | 22 ++++++++++++++-------- src/liblzma/common/alone_decoder.h | 5 +++-- src/liblzma/common/auto_decoder.c | 2 +- 3 files changed, 18 insertions(+), 11 deletions(-) -commit 211b931cee58626c1d2e021810cb108cb5cbc10f +commit bb117fffa84604b6e3811b068c80db82bf7f7b05 +Author: Lasse Collin +Date: 2013-03-23 21:55:13 +0200 + + liblzma: Use lzma_block_buffer_bound64() in threaded encoder. + + Now it uses lzma_block_uncomp_encode() if the data doesn't + fit into the space calculated by lzma_block_buffer_bound64(). + + src/liblzma/common/stream_encoder_mt.c | 66 +++++++++++++++++++++++++--------- + 1 file changed, 50 insertions(+), 16 deletions(-) + +commit e572e123b55b29527e54ce5f0807f115481d78b9 +Author: Lasse Collin +Date: 2013-03-23 21:51:38 +0200 + + liblzma: Fix another deadlock in the threaded encoder. + + This race condition could cause a deadlock if lzma_end() was + called before finishing the encoding. This can happen with + xz with debugging enabled (non-debugging version doesn't + call lzma_end() before exiting). + + src/liblzma/common/stream_encoder_mt.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +commit b465da5988dd59ad98fda10c2e4ea13d0b9c73bc +Author: Lasse Collin +Date: 2013-03-23 19:17:33 +0200 + + liblzma: Add lzma_block_uncomp_encode(). + + This also adds a new internal function + lzma_block_buffer_bound64() which is similar to + lzma_block_buffer_bound() but uses uint64_t instead + of size_t. + + src/liblzma/api/lzma/block.h | 18 ++++++ + src/liblzma/common/block_buffer_encoder.c | 94 +++++++++++++++++++++---------- + src/liblzma/common/block_buffer_encoder.h | 24 ++++++++ + src/liblzma/liblzma.map | 1 + + 4 files changed, 106 insertions(+), 31 deletions(-) + +commit 9e6dabcf22ef4679f4faaae15ebd5b137ae2fad1 Author: Lasse Collin Date: 2013-03-05 19:14:50 +0200 @@ -643,7 +2051,54 @@ Date: 2013-03-05 19:14:50 +0200 src/scripts/xzless.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) -commit 9f62fd9605eade23b62b07a235d1f02156f7a5c6 +commit e7b424d267a34803db8d92a3515528be2ed45abd +Author: Lasse Collin +Date: 2012-12-14 20:13:32 +0200 + + Make the progress indicator smooth in threaded mode. + + This adds lzma_get_progress() to liblzma and takes advantage + of it in xz. + + lzma_get_progress() collects progress information from + the thread-specific structures so that fairly accurate + progress information is available to applications. Adding + a new function seemed to be a better way than making the + information directly available in lzma_stream (like total_in + and total_out are) because collecting the information requires + locking mutexes. It's waste of time to do it more often than + the up to date information is actually needed by an application. + + src/liblzma/api/lzma/base.h | 22 +++++++++- + src/liblzma/common/common.c | 16 +++++++ + src/liblzma/common/common.h | 6 +++ + src/liblzma/common/stream_encoder_mt.c | 77 +++++++++++++++++++++++++++++++--- + src/liblzma/liblzma.map | 1 + + src/xz/message.c | 20 +++++---- + 6 files changed, 129 insertions(+), 13 deletions(-) + +commit 2ebbb994e367f55f2561aa7c9e7451703c171f2f +Author: Lasse Collin +Date: 2012-12-14 11:01:41 +0200 + + liblzma: Fix mythread_sync for nested locking. + + src/common/mythread.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +commit 4c7e28705f6de418d19cc77324ef301f996e01ff +Author: Lasse Collin +Date: 2012-12-13 21:05:36 +0200 + + xz: Mention --threads in --help. + + Thanks to Olivier Delhomme for pointing out that this + was still missing. + + src/xz/message.c | 4 ++++ + 1 file changed, 4 insertions(+) + +commit db5c1817fabf7cbb9e4087b1576eb26f0747338e Author: Jonathan Nieder Date: 2012-11-19 00:10:10 -0800 @@ -685,7 +2140,7 @@ Date: 2012-11-19 00:10:10 -0800 src/scripts/xzless.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) -commit 1d05980f5b5c2c94d833001daccacce4a466876e +commit 65536214a31ecd33b6b03b68a351fb597d3703d6 Author: Lasse Collin Date: 2012-10-03 15:54:24 +0300 @@ -694,7 +2149,7 @@ Date: 2012-10-03 15:54:24 +0300 src/xz/xz.1 | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) -commit fb68497333598688d309a92838d91fd560f7e9f0 +commit 3d93b6354927247a1569caf22ad27b07e97ee904 Author: Lasse Collin Date: 2012-09-28 20:11:09 +0300 @@ -705,9 +2160,9 @@ Date: 2012-09-28 20:11:09 +0300 src/xz/util.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) -commit 75013db6d4d63c195bd8b8d45729b4be0665a812 +commit ab225620664e235637833be2329935f9d290ba80 Author: Lasse Collin -Date: 2012-12-15 20:01:02 +0200 +Date: 2012-08-24 16:27:31 +0300 A few typo fixes to comments and the xz man page. @@ -718,7 +2173,16 @@ Date: 2012-12-15 20:01:02 +0200 src/xz/xz.1 | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) -commit e44b21839b1dcbac5097be39b87dd2ddb6e114fd +commit f3c1ec69d910175ffd431fd82968dd35cec806ed +Author: Lasse Collin +Date: 2012-08-13 21:40:09 +0300 + + xz: Add a warning to --help about alpha and beta versions. + + src/xz/message.c | 5 +++++ + 1 file changed, 5 insertions(+) + +commit d8eaf9d8278c23c2cf2b7ca5562d4de570d3b5db Author: Lasse Collin Date: 2012-08-02 17:13:30 +0300 @@ -730,7 +2194,102 @@ Date: 2012-08-02 17:13:30 +0300 configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit fd3dbb23ca7e75a7a888d7e897c381dc06308307 +commit 96e08902b09f0f304d4ff80c6e83ef7fff883f34 +Author: Lasse Collin +Date: 2012-07-17 18:29:08 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit 3778db1be53e61ff285c573af5ee468803008456 +Author: Lasse Collin +Date: 2012-07-17 18:19:59 +0300 + + liblzma: Make the use of lzma_allocator const-correct. + + There is a tiny risk of causing breakage: If an application + assigns lzma_stream.allocator to a non-const pointer, such + code won't compile anymore. I don't know why anyone would do + such a thing though, so in practice this shouldn't cause trouble. + + Thanks to Jan Kratochvil for the patch. + + src/liblzma/api/lzma/base.h | 4 +++- + src/liblzma/api/lzma/block.h | 6 ++--- + src/liblzma/api/lzma/container.h | 9 +++++--- + src/liblzma/api/lzma/filter.h | 13 ++++++----- + src/liblzma/api/lzma/index.h | 16 ++++++------- + src/liblzma/api/lzma/index_hash.h | 4 ++-- + src/liblzma/common/alone_decoder.c | 6 ++--- + src/liblzma/common/alone_decoder.h | 2 +- + src/liblzma/common/alone_encoder.c | 8 +++---- + src/liblzma/common/auto_decoder.c | 6 ++--- + src/liblzma/common/block_buffer_decoder.c | 2 +- + src/liblzma/common/block_buffer_encoder.c | 4 ++-- + src/liblzma/common/block_decoder.c | 6 ++--- + src/liblzma/common/block_decoder.h | 2 +- + src/liblzma/common/block_encoder.c | 8 +++---- + src/liblzma/common/block_encoder.h | 2 +- + src/liblzma/common/block_header_decoder.c | 4 ++-- + src/liblzma/common/common.c | 10 ++++----- + src/liblzma/common/common.h | 20 +++++++++-------- + src/liblzma/common/easy_buffer_encoder.c | 4 ++-- + src/liblzma/common/filter_buffer_decoder.c | 3 ++- + src/liblzma/common/filter_buffer_encoder.c | 7 +++--- + src/liblzma/common/filter_common.c | 4 ++-- + src/liblzma/common/filter_common.h | 2 +- + src/liblzma/common/filter_decoder.c | 7 +++--- + src/liblzma/common/filter_decoder.h | 2 +- + src/liblzma/common/filter_encoder.c | 2 +- + src/liblzma/common/filter_encoder.h | 2 +- + src/liblzma/common/filter_flags_decoder.c | 2 +- + src/liblzma/common/index.c | 26 ++++++++++----------- + src/liblzma/common/index_decoder.c | 12 +++++----- + src/liblzma/common/index_encoder.c | 6 ++--- + src/liblzma/common/index_encoder.h | 2 +- + src/liblzma/common/index_hash.c | 6 +++-- + src/liblzma/common/outqueue.c | 4 ++-- + src/liblzma/common/outqueue.h | 5 +++-- + src/liblzma/common/stream_buffer_decoder.c | 2 +- + src/liblzma/common/stream_buffer_encoder.c | 3 ++- + src/liblzma/common/stream_decoder.c | 9 ++++---- + src/liblzma/common/stream_decoder.h | 5 +++-- + src/liblzma/common/stream_encoder.c | 10 ++++----- + src/liblzma/common/stream_encoder_mt.c | 16 ++++++------- + src/liblzma/delta/delta_common.c | 4 ++-- + src/liblzma/delta/delta_decoder.c | 6 ++--- + src/liblzma/delta/delta_decoder.h | 5 +++-- + src/liblzma/delta/delta_encoder.c | 6 ++--- + src/liblzma/delta/delta_encoder.h | 3 ++- + src/liblzma/delta/delta_private.h | 2 +- + src/liblzma/lz/lz_decoder.c | 8 +++---- + src/liblzma/lz/lz_decoder.h | 7 +++--- + src/liblzma/lz/lz_encoder.c | 19 ++++++++-------- + src/liblzma/lz/lz_encoder.h | 6 ++--- + src/liblzma/lzma/lzma2_decoder.c | 8 +++---- + src/liblzma/lzma/lzma2_decoder.h | 5 +++-- + src/liblzma/lzma/lzma2_encoder.c | 6 ++--- + src/liblzma/lzma/lzma2_encoder.h | 2 +- + src/liblzma/lzma/lzma_decoder.c | 8 +++---- + src/liblzma/lzma/lzma_decoder.h | 7 +++--- + src/liblzma/lzma/lzma_encoder.c | 7 +++--- + src/liblzma/lzma/lzma_encoder.h | 5 +++-- + src/liblzma/simple/arm.c | 8 ++++--- + src/liblzma/simple/armthumb.c | 8 ++++--- + src/liblzma/simple/ia64.c | 8 ++++--- + src/liblzma/simple/powerpc.c | 8 ++++--- + src/liblzma/simple/simple_coder.c | 10 ++++----- + src/liblzma/simple/simple_coder.h | 36 ++++++++++++++++++++---------- + src/liblzma/simple/simple_decoder.c | 2 +- + src/liblzma/simple/simple_decoder.h | 2 +- + src/liblzma/simple/simple_private.h | 3 ++- + src/liblzma/simple/sparc.c | 8 ++++--- + src/liblzma/simple/x86.c | 8 ++++--- + 71 files changed, 269 insertions(+), 219 deletions(-) + +commit d625c7cf824fd3b61c6da84f56179e94917ff603 Author: Lasse Collin Date: 2012-07-05 07:36:28 +0300 @@ -739,7 +2298,7 @@ Date: 2012-07-05 07:36:28 +0300 tests/test_block.c | 52 ---------------------------------------------------- 1 file changed, 52 deletions(-) -commit 05a735d279d74af437c31f25f69aded4713c1a3d +commit 0b09d266cce72bc4841933b171e79551e488927c Author: Lasse Collin Date: 2012-07-05 07:33:35 +0300 @@ -752,7 +2311,21 @@ Date: 2012-07-05 07:33:35 +0300 Makefile.am | 1 + 1 file changed, 1 insertion(+) -commit 4e6d62793b5e7b87edcc93c7ded072c1ecd94173 +commit d6e0b23d4613b9f417893dd96cc168c8005ece3d +Author: Lasse Collin +Date: 2012-07-05 07:28:53 +0300 + + Build: Include validate_map.sh in the distribution. + + It's required by "make mydist". + + Fix also the location of EXTRA_DIST+= so that those files + get distributed also if symbol versioning isn't enabled. + + src/liblzma/Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 19de545d86097c3954d69ab5d12820387f6a09bc Author: Lasse Collin Date: 2012-07-05 07:24:45 +0300 @@ -761,7 +2334,7 @@ Date: 2012-07-05 07:24:45 +0300 debug/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit dd95b5e7614baf1f07a1316b5106bd616a9efa79 +commit 672eccf57c31a40dfb956b7662db06d43e18618e Author: Lasse Collin Date: 2012-07-05 07:23:17 +0300 @@ -773,35 +2346,132 @@ Date: 2012-07-05 07:23:17 +0300 debug/Makefile.am | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) -commit 20778053a07eb90c159c1377ca8dc05a90fd530b +commit cafb523adac1caf305e70a04bc37f25602bf990c Author: Lasse Collin -Date: 2012-06-22 14:36:16 +0300 +Date: 2012-07-04 22:31:58 +0300 + + xz: Document --block-list better. + + Thanks to Jonathan Nieder. + + src/xz/xz.1 | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +commit c7ff218528bc8f7c65e7ef73c6515777346c6794 +Author: Lasse Collin +Date: 2012-07-04 20:01:49 +0300 + + Bump the version number to 5.1.2alpha. + + src/liblzma/api/lzma/version.h | 2 +- + src/liblzma/liblzma.map | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +commit 8f3c1d886f93e6478ad509ff52102b2ce7faa999 +Author: Lasse Collin +Date: 2012-07-04 20:01:19 +0300 + + Update NEWS for 5.1.2alpha. + + NEWS | 41 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +commit 0d5fa05466e580fbc458820f87013ae7644e20e5 +Author: Lasse Collin +Date: 2012-07-04 19:58:23 +0300 + + xz: Fix the version number printed by xz -lvv. + + The decoder bug was fixed in 5.0.2 instead of 5.0.3. + + src/xz/list.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +commit df11317985a4165731dde12bb0f0028da0e7b77f +Author: Lasse Collin +Date: 2012-07-04 17:11:31 +0300 + + Build: Add a comment to configure.ac about symbol versioning. + + configure.ac | 4 ++++ + 1 file changed, 4 insertions(+) + +commit bd9cc179e8be3ef515201d3ed9c7dd79ae88869d +Author: Lasse Collin +Date: 2012-07-04 17:06:49 +0300 + + Update TODO. + + TODO | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +commit 4a238dd9b22f462cac5e199828bf1beb0df05884 +Author: Lasse Collin +Date: 2012-07-04 17:05:46 +0300 + + Document --enable-symbol-versions in INSTALL. + + INSTALL | 5 +++++ + 1 file changed, 5 insertions(+) + +commit 88ccf47205d7f3aa314d358c72ef214f10f68b43 +Author: Lasse Collin +Date: 2012-07-03 21:16:39 +0300 + + xz: Add incomplete support for --block-list. + + It's broken with threads and when also --block-size is used. + + src/xz/args.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/xz/args.h | 1 + + src/xz/coder.c | 48 ++++++++++++++++++++++++++++------ + src/xz/coder.h | 4 +++ + src/xz/main.c | 1 + + src/xz/message.c | 6 +++++ + src/xz/xz.1 | 23 +++++++++++++++-- + 7 files changed, 151 insertions(+), 10 deletions(-) + +commit 972179cdcdf5d8949c48ee31737d87d3050b44af +Author: Lasse Collin +Date: 2012-07-01 18:44:33 +0300 + + xz: Update the man page about the new field in --robot -lvv. + + src/xz/xz.1 | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +commit 1403707fc64a70976aebe66f8d9a9bd12f73a2c5 +Author: Lasse Collin +Date: 2012-06-28 10:47:49 +0300 + + liblzma: Check that the first byte of range encoded data is 0x00. + + It is just to be more pedantic and thus perhaps catch broken + files slightly earlier. + + src/liblzma/lzma/lzma_decoder.c | 8 ++++++-- + src/liblzma/rangecoder/range_decoder.h | 12 +++++++++--- + 2 files changed, 15 insertions(+), 5 deletions(-) + +commit eccd8017ffe2c5de473222c4963ec53c62f7fda2 +Author: Lasse Collin +Date: 2012-06-22 19:00:23 +0300 + + Update NEWS from 5.0.4. + + NEWS | 37 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +commit 2e6754eac26a431e8d340c28906f63bcd1e177e8 +Author: Lasse Collin +Date: 2012-06-22 14:34:03 +0300 xz: Update man page date to match the latest update. src/xz/xz.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 2cefa84af676da37d7e9c466d55d46c67ab00c22 -Author: Lasse Collin -Date: 2012-06-22 10:25:43 +0300 - - Bump version and soname for 5.0.4. - - src/liblzma/Makefile.am | 2 +- - src/liblzma/api/lzma/version.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -commit 433fec191a17e45690809e54146ea7a773f54cff -Author: Lasse Collin -Date: 2012-06-22 10:25:09 +0300 - - Update NEWS for 5.0.4. - - NEWS | 25 +++++++++++++++++++------ - 1 file changed, 19 insertions(+), 6 deletions(-) - -commit 711fa680f552a4003df73b37e6dc4d6e00b47bcd +commit b3235a0b1af45d5e1244cbe3191516966c076fa0 Author: Lasse Collin Date: 2012-06-18 21:27:47 +0300 @@ -812,7 +2482,7 @@ Date: 2012-06-18 21:27:47 +0300 doc/examples/01_compress_easy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 3d7ab1dc61a75c560828be5df96598388b771456 +commit f1675f765fe228cb5a5f904f853445a03e33cfe9 Author: Lasse Collin Date: 2012-06-14 20:15:30 +0300 @@ -821,7 +2491,7 @@ Date: 2012-06-14 20:15:30 +0300 Makefile.am | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) -commit ef8b8e5f111469b5bc005975f7abb9abbd372b25 +commit 3a0c5378abefaf86aa39a62a7c9682bdb21568a1 Author: Lasse Collin Date: 2012-06-14 10:52:33 +0300 @@ -838,7 +2508,7 @@ Date: 2012-06-14 10:52:33 +0300 doc/examples/Makefile | 23 +++ 5 files changed, 827 insertions(+) -commit 75c149bc8045a26f8bc719cb8ed20668dab79091 +commit 1bd2c2c553e30c4a73cfb82abc6908efd6be6b8d Author: Lasse Collin Date: 2012-06-14 10:33:27 +0300 @@ -854,7 +2524,7 @@ Date: 2012-06-14 10:33:27 +0300 doc/examples_old/xz_pipe_decomp.c | 123 ++++++++++++++++++++++++++++++++++++ 4 files changed, 250 insertions(+), 250 deletions(-) -commit 456307ebf947a5f50bd995d617b99c1215572308 +commit 905f0ab5b5ce544d4b68a2ed6077df0f3d021292 Author: Lasse Collin Date: 2012-06-14 10:33:01 +0300 @@ -863,29 +2533,29 @@ Date: 2012-06-14 10:33:01 +0300 doc/examples/xz_pipe_decomp.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) -commit 4c310b8a29bc257e6ccbd2310f12f258678f3fef +commit 4bd1a3bd5fdf4870b2f96dd0b8a21657c8a58ad8 Author: Lasse Collin -Date: 2012-05-31 15:53:25 +0300 - - Translations: Update the Italian translation. - - Thanks to Milo Casagrande. - - po/it.po | 311 ++++++++++++++++++++++++++++++--------------------------------- - 1 file changed, 146 insertions(+), 165 deletions(-) - -commit ec32b79366dc47a55ea877589df9e8509ba113a7 -Author: Lasse Collin -Date: 2012-05-30 23:15:07 +0300 +Date: 2012-05-30 23:14:33 +0300 Translations: Update the French translation. Thanks to Adrien Nader. - po/fr.po | 237 +++++++++++++++++++++++++++++++-------------------------------- - 1 file changed, 118 insertions(+), 119 deletions(-) + po/fr.po | 148 ++++++++++++++++++++++++++++++++++----------------------------- + 1 file changed, 79 insertions(+), 69 deletions(-) -commit dd06f40e4dd7649525e4f28d890dc238a3aa37e5 +commit d2e836f2f3a87df6fe6bb0589b037db51205d910 +Author: Lasse Collin +Date: 2012-05-29 23:42:37 +0300 + + Translations: Update the German translation. + + The previous only included the new strings in v5.0. + + po/de.po | 229 +++++++++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 133 insertions(+), 96 deletions(-) + +commit c9a16151577ba459afd6e3528df23bc0ddb95171 Author: Lasse Collin Date: 2012-05-29 22:26:27 +0300 @@ -894,25 +2564,16 @@ Date: 2012-05-29 22:26:27 +0300 po/de.po | 169 ++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 91 insertions(+), 78 deletions(-) -commit c66808d1f55d0149ed57c536cc9b52e9c8b583bc +commit 1530a74fd48f8493372edad137a24541efe24713 Author: Lasse Collin -Date: 2012-05-29 22:12:57 +0300 +Date: 2012-05-29 22:14:21 +0300 Translations: Update Polish translation. - po/pl.po | 150 ++++++++++++++++++++++++++++++++++----------------------------- - 1 file changed, 82 insertions(+), 68 deletions(-) + po/pl.po | 283 +++++++++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 165 insertions(+), 118 deletions(-) -commit 556c22dfed195c1466b298183b850d6c28544900 -Author: Lasse Collin -Date: 2012-05-29 13:10:36 +0300 - - Preliminary NEWS for 5.0.4. - - NEWS | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -commit dd13b66bf582f49d3aec36e3410ff8541b7506da +commit d8db706acb8316f9861abd432cfbe001dd6d0c5c Author: Lasse Collin Date: 2012-05-28 20:42:11 +0300 @@ -947,7 +2608,7 @@ Date: 2012-05-28 20:42:11 +0300 tests/test_bcj_exact_size.c | 112 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 2 deletions(-) -commit a0223bf796fdaad51a11ad02c4195c694849cc78 +commit 3f94b6d87f1b8f1c421ba548f8ebb83dca9c8cda Author: Lasse Collin Date: 2012-05-28 15:38:32 +0300 @@ -956,7 +2617,7 @@ Date: 2012-05-28 15:38:32 +0300 THANKS | 1 + 1 file changed, 1 insertion(+) -commit 86e57e4bfefe3fd8e13615c41604165bb2359501 +commit 7769ea051d739a38a1640fd448cf5eb83cb119c6 Author: Lasse Collin Date: 2012-05-28 15:37:43 +0300 @@ -965,7 +2626,7 @@ Date: 2012-05-28 15:37:43 +0300 src/xz/message.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) -commit 13e44a94da19d1ef14832ff12d3877a6fd2c54c0 +commit ec921105725e4d3ef0a683dd83eee6f24ab60ccd Author: Lasse Collin Date: 2012-05-27 22:30:17 +0300 @@ -978,7 +2639,7 @@ Date: 2012-05-27 22:30:17 +0300 src/xz/xz.1 | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) -commit 2f90345e13ab8fea4de45a4f1caa73ebc63a62e7 +commit 27d24eb0a9f6eed96d6a4594c2b0bf7a91d29f9a Author: Lasse Collin Date: 2012-05-27 21:53:20 +0300 @@ -990,7 +2651,16 @@ Date: 2012-05-27 21:53:20 +0300 src/xz/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 8d4864f53ffae5d862c691a0b334a6b69bc5366e +commit ab25b82a91754d9388c89abddf806424671d9431 +Author: Lasse Collin +Date: 2012-05-24 18:33:54 +0300 + + Build: Upgrade m4/acx_pthread.m4 to the latest version. + + m4/ax_pthread.m4 | 98 +++++++++++++++++++++++++++++++++++--------------------- + 1 file changed, 62 insertions(+), 36 deletions(-) + +commit d05d6d65c41a4bc83f162fa3d67c5d84e8751634 Author: Lasse Collin Date: 2012-05-10 21:15:17 +0300 @@ -999,7 +2669,7 @@ Date: 2012-05-10 21:15:17 +0300 THANKS | 1 + 1 file changed, 1 insertion(+) -commit 35e9c58abb0ce3993da844aaeaa3e7231cd2be8f +commit e077391982f9f28dbfe542bba8800e7c5b916666 Author: Lasse Collin Date: 2012-05-10 21:14:16 +0300 @@ -1009,7 +2679,7 @@ Date: 2012-05-10 21:14:16 +0300 doc/history.txt | 49 +++++++++++++++++++++++++------------------------ 2 files changed, 31 insertions(+), 30 deletions(-) -commit 532b3e4c568a228309b56f95c13435fd078dbe02 +commit fc39849c350225c6a1cd7f6e6adff1020521eabc Author: Benno Schulenberg Date: 2012-03-13 22:04:04 +0100 @@ -1025,7 +2695,7 @@ Date: 2012-03-13 22:04:04 +0100 doc/history.txt | 58 ++++++++++++++++++++++++++++----------------------------- 4 files changed, 65 insertions(+), 65 deletions(-) -commit afb6ce8c82ffef8f2505a3759da72a733c7b0b8f +commit 29fa0566d5df199cb9acb2d17bf7eea61acc7fa1 Author: Lasse Collin Date: 2012-04-29 11:51:25 +0300 @@ -1034,7 +2704,7 @@ Date: 2012-04-29 11:51:25 +0300 windows/README-Windows.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) -commit 7c3ba2ed5c3c878d4a14ca549b46dbff60c6d565 +commit aac1b31ea4e66cf5a7a8c116bdaa15aa45e6c56e Author: Lasse Collin Date: 2012-04-19 15:25:26 +0300 @@ -1044,7 +2714,7 @@ Date: 2012-04-19 15:25:26 +0300 src/liblzma/simple/simple_private.h | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) -commit f55db9c187651094f43881c49db2b2d9ffee6b80 +commit df14a46013bea70c0bd35be7821b0b9108f97de7 Author: Lasse Collin Date: 2012-04-19 14:17:52 +0300 @@ -1056,7 +2726,16 @@ Date: 2012-04-19 14:17:52 +0300 dos/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 203edff4c761dbd7cac76ea66e4eed501c23e7a3 +commit 03ed742a3a4931bb5c821357832083b26f577b13 +Author: Lasse Collin +Date: 2012-04-19 14:02:25 +0300 + + liblzma: Fix Libs.private in liblzma.pc to include -lrt when needed. + + src/liblzma/liblzma.pc.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 8c5b13ad59df70f49429bfdfd6ac120b8f892fda Author: Lasse Collin Date: 2012-04-19 13:58:55 +0300 @@ -1065,7 +2744,7 @@ Date: 2012-04-19 13:58:55 +0300 INSTALL | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) -commit f0a8f95c215628967b7cf9bd9b0a9e4172f50bb4 +commit c7376fc415a1566f38b2de4b516a17013d516a8b Author: Lasse Collin Date: 2012-02-22 14:23:13 +0200 @@ -1074,7 +2753,7 @@ Date: 2012-02-22 14:23:13 +0200 THANKS | 1 + 1 file changed, 1 insertion(+) -commit b7ad23fa78646036c0290cd91eada939c9a31526 +commit cff070aba6281ba743d29a62b8c0c66e5da4b2a6 Author: Lasse Collin Date: 2012-02-22 14:02:34 +0200 @@ -1095,7 +2774,7 @@ Date: 2012-02-22 14:02:34 +0200 src/scripts/xzgrep.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) -commit 4e19fbb04a0035030406482319e264426459eb24 +commit 41cafb2bf9beea915710ee68f05fe929cd17759c Author: Lasse Collin Date: 2012-02-22 12:08:43 +0200 @@ -1104,9 +2783,9 @@ Date: 2012-02-22 12:08:43 +0200 THANKS | 1 + 1 file changed, 1 insertion(+) -commit c6fa03a427e3d1320794102cee3ff4f5ae00eb36 +commit 2dcea03712fa881930d69ec9eff70855c3d126d9 Author: Lasse Collin -Date: 2012-05-24 18:47:52 +0300 +Date: 2012-02-22 12:00:16 +0200 Fix compiling with IBM XL C on AIX. @@ -1114,20 +2793,7 @@ Date: 2012-05-24 18:47:52 +0300 configure.ac | 6 +++++- 2 files changed, 27 insertions(+), 15 deletions(-) -commit 7b6ffc98645e1b3b302b6680be0a901d1ebf7358 -Author: Lasse Collin -Date: 2012-05-24 18:37:08 +0300 - - Build: Upgrade m4/acx_pthread.m4 to the latest version. - - It was renamed to ax_pthread.m4 in Autoconf Archive. - - configure.ac | 2 +- - m4/acx_pthread.m4 | 279 ------------------------------------------------ - m4/ax_pthread.m4 | 309 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 310 insertions(+), 280 deletions(-) - -commit bfac2be5023994fcc53de2844e7dd3af61910dc2 +commit 7db6bdf4abcf524115be2cf5659ed540cef074c5 Author: Lasse Collin Date: 2012-01-10 17:13:03 +0200 @@ -1139,7 +2805,7 @@ Date: 2012-01-10 17:13:03 +0200 tests/create_compress_files.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) -commit df85e156716a4eecb7e2978691f03f729444d998 +commit 694952d545b6cf056547893ced69486eff9ece55 Author: Lasse Collin Date: 2011-12-19 21:21:29 +0200 @@ -1148,7 +2814,18 @@ Date: 2011-12-19 21:21:29 +0200 README | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) -commit d06d32f108c8278c25c24b2e8666bda7b2ec23b5 +commit 418fe668b3c53a9a20020b6cc652aaf25c734b29 +Author: Lasse Collin +Date: 2011-11-07 13:07:52 +0200 + + xz: Show minimum required XZ Utils version in xz -lvv. + + Man page wasn't updated yet. + + src/xz/list.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 57 insertions(+), 6 deletions(-) + +commit 7081d82c37326bac97184e338345fa1c327e3580 Author: Lasse Collin Date: 2011-11-04 17:57:16 +0200 @@ -1159,7 +2836,7 @@ Date: 2011-11-04 17:57:16 +0200 src/xz/args.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 636fdcfbf542f1e84db2c4736004d84be4b12c84 +commit 232fe7cd70ad258d6a37f17e860e0f1b1891eeb5 Author: Lasse Collin Date: 2011-11-03 17:08:02 +0200 @@ -1168,7 +2845,7 @@ Date: 2011-11-03 17:08:02 +0200 THANKS | 1 + 1 file changed, 1 insertion(+) -commit 55fd02f83ecd6cbd6925a3e8a3d43b8d4ef2a17c +commit 74d2bae4d3449c68453b0473dd3430ce91fd90c1 Author: Lasse Collin Date: 2011-11-03 17:07:22 +0200 @@ -1179,7 +2856,42 @@ Date: 2011-11-03 17:07:22 +0200 src/xz/coder.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) -commit 4052f36053b931bad847a36aabf1a07d0034e297 +commit 4ac4923f47cc0ef97dd9ca5cfcc44fc53eeab34a +Author: Lasse Collin +Date: 2011-10-23 17:09:10 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit ab50ae3ef40c81e5bf613905ca3fd636548b75e7 +Author: Lasse Collin +Date: 2011-10-23 17:08:14 +0300 + + liblzma: Fix invalid free() in the threaded encoder. + + It was triggered if initialization failed e.g. due to + running out of memory. + + Thanks to Arkadiusz Miskiewicz. + + src/liblzma/common/outqueue.c | 4 ++++ + 1 file changed, 4 insertions(+) + +commit 6b620a0f0813d28c3c544b4ff8cb595b38a6e908 +Author: Lasse Collin +Date: 2011-10-23 17:05:55 +0300 + + liblzma: Fix a deadlock in the threaded encoder. + + It was triggered when reinitializing the encoder, + e.g. when encoding two files. + + src/liblzma/common/stream_encoder_mt.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +commit bd52cf150ecd51e3ab63a9cc1a3cff6a77500178 Author: Lasse Collin Date: 2011-09-06 12:03:41 +0300 @@ -1189,7 +2901,7 @@ Date: 2011-09-06 12:03:41 +0300 windows/build.bash | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) -commit 0f25758459c74c366a73f35d47ee12b75890bb79 +commit 5c5b2256969ac473001b7d67615ed3bd0a54cc82 Author: Lasse Collin Date: 2011-08-09 21:19:13 +0300 @@ -1198,7 +2910,7 @@ Date: 2011-08-09 21:19:13 +0300 THANKS | 2 ++ 1 file changed, 2 insertions(+) -commit 70f03b51ffcb783646b20de8d97b6986c4280eec +commit 5b1e1f10741af9e4bbe4cfc3261fb7c7b04f7809 Author: Lasse Collin Date: 2011-08-09 21:16:44 +0300 @@ -1207,7 +2919,7 @@ Date: 2011-08-09 21:16:44 +0300 src/common/sysdefs.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) -commit f138bdf76a70029e8360062a0b227936b83b24c9 +commit e9ed88126eee86e2511fa42681a5c7104820cf0a Author: Lasse Collin Date: 2011-08-06 20:37:28 +0300 @@ -1225,7 +2937,7 @@ Date: 2011-08-06 20:37:28 +0300 tests/test_scripts.sh | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) -commit 2c144a0365c84dbf1b6722466746d42f2563a319 +commit 1c673e5681720491a74fc4b2992e075f47302c22 Author: Lasse Collin Date: 2011-07-31 11:01:47 +0300 @@ -1247,16 +2959,7 @@ Date: 2011-07-31 11:01:47 +0300 tests/test_scripts.sh | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) -commit edf339227a966f24aebe1845fcca9429b8f6e318 -Author: Anders F Bjorklund -Date: 2010-11-05 12:56:11 +0100 - - add build script for macosx universal - - macosx/build.sh | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 92 insertions(+) - -commit 7fcc6334ea8923550ba6b5347ff99dc8432234b0 +commit 324cde7a864f4506c32ae7846d688c359a83fe65 Author: Lasse Collin Date: 2011-06-16 12:15:29 +0300 @@ -1265,7 +2968,16 @@ Date: 2011-06-16 12:15:29 +0300 src/liblzma/lz/lz_encoder_hash.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 631f4d3ae6adfda84d1a110781d9402c12e16cfc +commit 492c86345551a51a29bf18e55fe55a5e86f169ce +Author: Lasse Collin +Date: 2011-05-28 19:24:56 +0300 + + Build: Make configure print if symbol versioning is enabled or not. + + configure.ac | 2 ++ + 1 file changed, 2 insertions(+) + +commit fc4d4436969bd4d71b704d400a165875e596034a Author: Lasse Collin Date: 2011-05-28 16:43:26 +0300 @@ -1276,18 +2988,47 @@ Date: 2011-05-28 16:43:26 +0300 src/common/tuklib_open_stdxxx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) -commit c89faf4c9e5970e7f7f8a25521ed9aa62d1a2d9a +commit bd35d903a04c4d388adb4065b0fa271302380895 Author: Lasse Collin -Date: 2011-05-28 09:47:56 +0300 +Date: 2011-05-28 15:55:39 +0300 - Translations: Update Italian translation. + liblzma: Use symbol versioning. + + Symbol versioning is enabled by default on GNU/Linux, + other GNU-based systems, and FreeBSD. + + I'm not sure how stable this is, so it may need + backward-incompatible changes before the next release. + + The idea is that alpha and beta symbols are considered + unstable and require recompiling the applications that + use those symbols. Once a symbol is stable, it may get + extended with new features in ways that don't break + compatibility with older ABI & API. + + The mydist target runs validate_map.sh which should + catch some probable problems in liblzma.map. Otherwise + I would forget to update the map file for new releases. + + Makefile.am | 1 + + configure.ac | 21 +++++++++ + src/liblzma/Makefile.am | 6 +++ + src/liblzma/liblzma.map | 105 ++++++++++++++++++++++++++++++++++++++++++++ + src/liblzma/validate_map.sh | 68 ++++++++++++++++++++++++++++ + 5 files changed, 201 insertions(+) + +commit afbb244362c9426a37ce4eb9d54aab768da3adad +Author: Lasse Collin +Date: 2011-05-28 09:46:46 +0300 + + Translations: Update the Italian translation. Thanks to Milo Casagrande. - po/it.po | 333 +++++++++++++++++++++++++++++++++++---------------------------- - 1 file changed, 184 insertions(+), 149 deletions(-) + po/it.po | 365 +++++++++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 216 insertions(+), 149 deletions(-) -commit 6fe2fc9b6ab5bf6848140823e9536370834f42fb +commit 79bef85e0543c0c3723281c3c817616c6cec343b Author: Lasse Collin Date: 2011-05-28 08:46:04 +0300 @@ -1297,7 +3038,7 @@ Date: 2011-05-28 08:46:04 +0300 tests/files/bad-1-block_header-6.xz | Bin 0 -> 72 bytes 2 files changed, 4 insertions(+) -commit 6c4d4db2bc8d8b682bd927144d37daa2ab21a6d6 +commit c0297445064951807803457dca1611b3c47e7f0f Author: Lasse Collin Date: 2011-05-27 22:25:44 +0300 @@ -1309,7 +3050,7 @@ Date: 2011-05-27 22:25:44 +0300 src/xz/list.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) -commit 844f84fcad9670c543550edf7c7e42630c8f7715 +commit 8bd91918ac50731f00b1a2a48072980572eb2ff9 Author: Lasse Collin Date: 2011-05-27 22:09:49 +0300 @@ -1320,7 +3061,16 @@ Date: 2011-05-27 22:09:49 +0300 src/liblzma/common/index.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) -commit 240e8b9791df597063a3b68d04ffcb3aa4f2de6a +commit fe00f95828ef5627721b57e054f7eb2d42a2c961 +Author: Lasse Collin +Date: 2011-05-24 00:23:46 +0300 + + Build: Fix checking for system-provided SHA-256. + + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 21b45b9bab541f419712cbfd473ccc31802e0397 Author: Lasse Collin Date: 2011-05-23 18:30:30 +0300 @@ -1329,26 +3079,16 @@ Date: 2011-05-23 18:30:30 +0300 Makefile.am | 3 +++ 1 file changed, 3 insertions(+) -commit e32cb264ea72a4459810f30abad70dae5a4fa17d +commit 48053e8a4550233af46359024538bff90c870ab1 Author: Lasse Collin -Date: 2011-05-21 16:59:22 +0300 - - Bump version and soname for 5.0.3. - - src/liblzma/Makefile.am | 2 +- - src/liblzma/api/lzma/version.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -commit 65cff45f8fd1c250491557157cce0f5f38481082 -Author: Lasse Collin -Date: 2011-05-21 16:56:53 +0300 +Date: 2011-05-22 16:42:11 +0300 Update NEWS for 5.0.3. - NEWS | 36 ++++++++++++++++++++++++++++++++++-- - 1 file changed, 34 insertions(+), 2 deletions(-) + NEWS | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) -commit 316c67ffdae1f811ac95e838d5290a013bff4ca7 +commit bba37df2c9e54ad773e15ff00a09d2d6989fb3b2 Author: Lasse Collin Date: 2011-05-21 16:28:44 +0300 @@ -1361,7 +3101,7 @@ Date: 2011-05-21 16:28:44 +0300 po/fr.po | 864 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 865 insertions(+) -commit 1931175eea6d09c0845d6e8e334a7333647f11c0 +commit 4161d7634965a7a287bf208dcd79f6185f448fe8 Author: Lasse Collin Date: 2011-05-21 15:12:10 +0300 @@ -1372,7 +3112,42 @@ Date: 2011-05-21 15:12:10 +0300 src/xz/message.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) -commit 841dc1f891b48b23f84c0f0e0c86c7c4e4bdcdf5 +commit b94aa0c8380cdb18cddb33440d625474c16643cf +Author: Lasse Collin +Date: 2011-05-21 15:08:44 +0300 + + liblzma: Try to use SHA-256 from the operating system. + + If the operating system libc or other base libraries + provide SHA-256, use that instead of our own copy. + Note that this doesn't use OpenSSL or libgcrypt or + such libraries to avoid creating dependencies to + other packages. + + This supports at least FreeBSD, NetBSD, OpenBSD, Solaris, + MINIX, and Darwin. They all provide similar but not + identical SHA-256 APIs; everyone is a little different. + + Thanks to Wim Lewis for the original patch, improvements, + and testing. + + configure.ac | 54 +++++++++++++++++++++++++++ + src/liblzma/check/Makefile.inc | 2 + + src/liblzma/check/check.h | 83 ++++++++++++++++++++++++++++++++++++++---- + 3 files changed, 131 insertions(+), 8 deletions(-) + +commit f004128678d43ea10b4a6401aa184cf83252d6ec +Author: Lasse Collin +Date: 2011-05-17 12:52:18 +0300 + + Don't use clockid_t in mythread.h when clock_gettime() isn't available. + + Thanks to Wim Lewis for the patch. + + src/common/mythread.h | 2 ++ + 1 file changed, 2 insertions(+) + +commit f779516f42ebd2db47a5b7d6143459bf7737cf2f Author: Lasse Collin Date: 2011-05-17 12:26:28 +0300 @@ -1381,7 +3156,7 @@ Date: 2011-05-17 12:26:28 +0300 THANKS | 3 +++ 1 file changed, 3 insertions(+) -commit 0f7e2d36240ebf1159d5fb85d8cd7422337a0d3f +commit 830ba587775bb562f6eaf05cad61bf669d1f8892 Author: Lasse Collin Date: 2011-05-17 12:21:33 +0300 @@ -1390,7 +3165,7 @@ Date: 2011-05-17 12:21:33 +0300 INSTALL | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) -commit 793d857e01e1725f16fc0c8af8172c91a9e38617 +commit ec7106309c8060e9c646dba20c4f15689a0bbb04 Author: Lasse Collin Date: 2011-05-17 12:01:37 +0300 @@ -1404,7 +3179,7 @@ Date: 2011-05-17 12:01:37 +0300 configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit afcff45cee04c5c7d9c333504046ffb63d1418b5 +commit 4c6e146df99696920f12410fb17754412797ef36 Author: Lasse Collin Date: 2011-05-17 11:54:38 +0300 @@ -1437,7 +3212,79 @@ Date: 2011-05-17 11:54:38 +0300 src/xzdec/xzdec.c | 6 +++--- 25 files changed, 49 insertions(+), 47 deletions(-) -commit 22159c6ba2300a006f2e46ce85ae132e2d2f7d57 +commit 7a480e485938884ef3021b48c3b0b9f9699dc9b6 +Author: Lasse Collin +Date: 2011-05-01 12:24:23 +0300 + + xz: Fix input file position when --single-stream is used. + + Now the following works as you would expect: + + echo foo | xz > foo.xz + echo bar | xz >> foo.xz + ( xz -dc --single-stream ; xz -dc --single-stream ) < foo.xz + + Note that it doesn't work if the input is not seekable + or if there is Stream Padding between the concatenated + .xz Streams. + + src/xz/coder.c | 1 + + src/xz/file_io.c | 15 +++++++++++++++ + src/xz/file_io.h | 13 +++++++++++++ + 3 files changed, 29 insertions(+) + +commit c29e6630c1450c630c4e7b783bdd76515db9004c +Author: Lasse Collin +Date: 2011-05-01 12:15:51 +0300 + + xz: Print the maximum number of worker threads in xz -vv. + + src/xz/coder.c | 4 ++++ + 1 file changed, 4 insertions(+) + +commit 0b77c4a75158ccc416b07d6e81df8ee0abaea720 +Author: Lasse Collin +Date: 2011-04-19 10:44:48 +0300 + + Build: Warn if no supported method to detect the number of CPU cores. + + configure.ac | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +commit e4622df9ab4982f8faa53d85b17be66216175a58 +Author: Lasse Collin +Date: 2011-04-19 09:55:06 +0300 + + Update THANKS. + + THANKS | 1 + + 1 file changed, 1 insertion(+) + +commit 9c1b05828a88eff54409760b92162c7cc2c7cff6 +Author: Lasse Collin +Date: 2011-04-19 09:20:44 +0300 + + Fix portability problems in mythread.h. + + Use gettimeofday() if clock_gettime() isn't available + (e.g. Darwin). + + The test for availability of pthread_condattr_setclock() + and CLOCK_MONOTONIC was incorrect. Instead of fixing the + #ifdefs, use an Autoconf test. That way if there exists a + system that supports them but doesn't specify the matching + POSIX #defines, the features will still get detected. + + Don't try to use pthread_sigmask() on OpenVMS. It doesn't + have that function. + + Guard mythread.h against being #included multiple times. + + configure.ac | 7 +++++++ + src/common/mythread.h | 31 +++++++++++++++++++++++++++---- + 2 files changed, 34 insertions(+), 4 deletions(-) + +commit 3de00cc75da7b0e7b65e84c62b5351e231f501e9 Author: Lasse Collin Date: 2011-04-18 19:35:49 +0300 @@ -1446,7 +3293,7 @@ Date: 2011-04-18 19:35:49 +0300 THANKS | 2 ++ 1 file changed, 2 insertions(+) -commit 5e3499059515033d1ce44b6fb0fa49183c7ac633 +commit bd5002f5821e3d1b04f2f56989e4a19318e73633 Author: Martin Väth Date: 2011-04-15 04:54:49 -0400 @@ -1459,7 +3306,31 @@ Date: 2011-04-15 04:54:49 -0400 src/scripts/xzgrep.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) -commit 1125611b9b8d4a209b6a73d2c76e1b39c065972a +commit 6ef4eabc0acc49e1bb9dc68064706e19fa9fcf48 +Author: Lasse Collin +Date: 2011-04-12 12:48:31 +0300 + + Bump the version number to 5.1.1alpha and liblzma soname to 5.0.99. + + src/liblzma/Makefile.am | 2 +- + src/liblzma/api/lzma/version.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +commit 9a4377be0d21e597c66bad6c7452873aebfb3c1c +Author: Lasse Collin +Date: 2011-04-12 12:42:37 +0300 + + Put the unstable APIs behind #ifdef LZMA_UNSTABLE. + + This way people hopefully won't complain if these APIs + change and break code that used an older API. + + src/liblzma/api/lzma/container.h | 4 ++++ + src/liblzma/common/common.h | 2 ++ + src/xz/private.h | 2 ++ + 3 files changed, 8 insertions(+) + +commit 3e321a3acd50002cf6fdfd259e910f56d3389bc3 Author: Lasse Collin Date: 2011-04-12 11:59:49 +0300 @@ -1480,7 +3351,78 @@ Date: 2011-04-12 11:59:49 +0300 windows/INSTALL-Windows.txt | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) -commit 3f8fa53837bae8b44f3addf19923e26401336c3d +commit d91a84b534b012d19474f2fda1fbcaef873e1ba4 +Author: Lasse Collin +Date: 2011-04-12 11:46:01 +0300 + + Update NEWS. + + NEWS | 47 +++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 45 insertions(+), 2 deletions(-) + +commit 14e6ad8cfe0165c1a8beeb5b2a1536558b29b0a1 +Author: Lasse Collin +Date: 2011-04-12 11:45:40 +0300 + + Update TODO. + + TODO | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +commit 70e750f59793f9b5cd306a5adce9b8e427739e04 +Author: Lasse Collin +Date: 2011-04-12 11:08:55 +0300 + + xz: Update the man page about threading. + + src/xz/xz.1 | 34 ++++++++++++++++++++-------------- + 1 file changed, 20 insertions(+), 14 deletions(-) + +commit 24e0406c0fb7494d2037dec033686faf1bf67068 +Author: Lasse Collin +Date: 2011-04-11 22:06:03 +0300 + + xz: Add support for threaded compression. + + src/xz/args.c | 3 +- + src/xz/coder.c | 202 +++++++++++++++++++++++++++++++++++---------------------- + 2 files changed, 125 insertions(+), 80 deletions(-) + +commit de678e0c924aa79a19293a8a6ed82e8cb6572a42 +Author: Lasse Collin +Date: 2011-04-11 22:03:30 +0300 + + liblzma: Add lzma_stream_encoder_mt() for threaded compression. + + This is the simplest method to do threading, which splits + the uncompressed data into blocks and compresses them + independently from each other. There's room for improvement + especially to reduce the memory usage, but nevertheless, + this is a good start. + + configure.ac | 1 + + src/liblzma/api/lzma/container.h | 163 +++++ + src/liblzma/common/Makefile.inc | 7 + + src/liblzma/common/common.c | 9 +- + src/liblzma/common/common.h | 14 + + src/liblzma/common/outqueue.c | 180 ++++++ + src/liblzma/common/outqueue.h | 155 +++++ + src/liblzma/common/stream_encoder_mt.c | 1011 ++++++++++++++++++++++++++++++++ + 8 files changed, 1539 insertions(+), 1 deletion(-) + +commit 25fe729532cdf4b8fed56a4519b73cf31efaec50 +Author: Lasse Collin +Date: 2011-04-11 21:15:07 +0300 + + liblzma: Add the forgotten lzma_lzma2_block_size(). + + This should have been in 5eefc0086d24a65e136352f8c1d19cefb0cbac7a. + + src/liblzma/lzma/lzma2_encoder.c | 10 ++++++++++ + src/liblzma/lzma/lzma2_encoder.h | 2 ++ + 2 files changed, 12 insertions(+) + +commit 91afb785a1dee34862078d9bf844ef12b8cc3e35 Author: Lasse Collin Date: 2011-04-11 21:04:13 +0300 @@ -1489,7 +3431,7 @@ Date: 2011-04-11 21:04:13 +0300 src/liblzma/api/lzma/container.h | 9 +++++++++ 1 file changed, 9 insertions(+) -commit 320d734c20d0776e3eb80f6b5984ddeb494715b5 +commit 4a9905302a9e4a1601ae09d650d3f08ce98ae9ee Author: Lasse Collin Date: 2011-04-11 20:59:07 +0300 @@ -1501,7 +3443,41 @@ Date: 2011-04-11 20:59:07 +0300 src/liblzma/api/lzma/filter.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) -commit 2ee4edeffc8d9734bf68230df31b20ac6a94c9b5 +commit 0badb0b1bd649163322783b0bd9e590b4bc7a93d +Author: Lasse Collin +Date: 2011-04-11 19:28:18 +0300 + + liblzma: Use memzero() to initialize supported_actions[]. + + This is cleaner and makes it simpler to add new members + to lzma_action enumeration. + + src/liblzma/common/common.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +commit a7934c446a58e20268689899d2a39f50e571f251 +Author: Lasse Collin +Date: 2011-04-11 19:26:27 +0300 + + liblzma: API comment about lzma_allocator with threaded coding. + + src/liblzma/api/lzma/base.h | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +commit 5eefc0086d24a65e136352f8c1d19cefb0cbac7a +Author: Lasse Collin +Date: 2011-04-11 19:16:30 +0300 + + liblzma: Add an internal function lzma_mt_block_size(). + + This is based lzma_chunk_size() that was included in some + development version of liblzma. + + src/liblzma/common/filter_encoder.c | 46 ++++++++++++++++++------------------- + src/liblzma/common/filter_encoder.h | 4 ++-- + 2 files changed, 24 insertions(+), 26 deletions(-) + +commit d1199274758049fc523d98c5b860ff814a799eec Author: Lasse Collin Date: 2011-04-11 13:59:50 +0300 @@ -1517,7 +3493,7 @@ Date: 2011-04-11 13:59:50 +0300 src/liblzma/common/stream_buffer_encoder.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) -commit 73f56fb87d54091d0c4fd22d70e6f042902e3b63 +commit 3b22fc2c87ec85fcdd385c163b68fc49c97aa848 Author: Lasse Collin Date: 2011-04-11 13:28:40 +0300 @@ -1530,7 +3506,7 @@ Date: 2011-04-11 13:28:40 +0300 src/liblzma/api/lzma/container.h | 3 +++ 2 files changed, 4 insertions(+) -commit 4ce1cf97a88ae1640a380dd19cbc255d729f966b +commit 71b9380145dccf001f22e66a06b9d508905c25ce Author: Lasse Collin Date: 2011-04-11 13:21:28 +0300 @@ -1548,7 +3524,139 @@ Date: 2011-04-11 13:21:28 +0300 src/liblzma/common/stream_buffer_encoder.c | 3 +++ 3 files changed, 20 insertions(+), 6 deletions(-) -commit 972f05d7a4268dbe42573701f83faa45d03249eb +commit ec7e3dbad704268825fc48f0bdd4577bc46b4f13 +Author: Lasse Collin +Date: 2011-04-11 09:57:30 +0300 + + xz: Move the description of --block-size in --long-help. + + src/xz/message.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +commit cd3086ff443bb282bdf556919c28b3e3cbed8169 +Author: Lasse Collin +Date: 2011-04-11 09:55:35 +0300 + + Docs: Document --single-stream and --block-size. + + src/xz/xz.1 | 38 ++++++++++++++++++++++++++++++++++++-- + 1 file changed, 36 insertions(+), 2 deletions(-) + +commit fb64a4924334e3c440865710990fe08090f2fed0 +Author: Lasse Collin +Date: 2011-04-11 09:27:57 +0300 + + liblzma: Make lzma_stream_encoder_init() static (second try). + + It's an internal function and it's not needed by + anything outside stream_encoder.c. + + src/liblzma/common/Makefile.inc | 1 - + src/liblzma/common/easy_encoder.c | 1 - + src/liblzma/common/stream_encoder.c | 13 ++++++------- + src/liblzma/common/stream_encoder.h | 23 ----------------------- + 4 files changed, 6 insertions(+), 32 deletions(-) + +commit a34730cf6af4d33a4057914e57227b6dfde6567e +Author: Lasse Collin +Date: 2011-04-11 08:31:42 +0300 + + Revert "liblzma: Make lzma_stream_encoder_init() static." + + This reverts commit 352ac82db5d3f64585c07b39e4759388dec0e4d7. + I don't know what I was thinking. + + src/liblzma/common/Makefile.inc | 1 + + src/liblzma/common/stream_encoder.c | 9 +++++---- + src/liblzma/common/stream_encoder.h | 23 +++++++++++++++++++++++ + 3 files changed, 29 insertions(+), 4 deletions(-) + +commit 9f0a806aef7ea79718e3f1f2baf3564295229a27 +Author: Lasse Collin +Date: 2011-04-10 21:23:21 +0300 + + Revise mythread.h. + + This adds: + + - mythread_sync() macro to create synchronized blocks + + - mythread_cond structure and related functions + and macros for condition variables with timed + waiting using a relative timeout + + - mythread_create() to create a thread with all + signals blocked + + Some of these wouldn't need to be inline functions, + but I'll keep them this way for now for simplicity. + + For timed waiting on a condition variable, librt is + now required on some systems to use clock_gettime(). + configure.ac was updated to handle this. + + configure.ac | 1 + + src/common/mythread.h | 200 +++++++++++++++++++++++++++++++++++++++++++++----- + 2 files changed, 181 insertions(+), 20 deletions(-) + +commit 352ac82db5d3f64585c07b39e4759388dec0e4d7 +Author: Lasse Collin +Date: 2011-04-10 20:37:36 +0300 + + liblzma: Make lzma_stream_encoder_init() static. + + It's an internal function and it's not needed by + anything outside stream_encoder.c. + + src/liblzma/common/Makefile.inc | 1 - + src/liblzma/common/stream_encoder.c | 9 ++++----- + src/liblzma/common/stream_encoder.h | 23 ----------------------- + 3 files changed, 4 insertions(+), 29 deletions(-) + +commit 9e807fe3fe79618ac48f58207cf7082ea20a6928 +Author: Lasse Collin +Date: 2011-04-10 14:58:10 +0300 + + DOS: Update the docs and include notes about 8.3 filenames. + + dos/INSTALL.txt | 79 ++++++++++++++++++++++++++++++++++++ + dos/README | 88 ---------------------------------------- + dos/README.txt | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 202 insertions(+), 88 deletions(-) + +commit ebd54dbd6e481d31e80757f900ac8109ad1423c6 +Author: Lasse Collin +Date: 2011-04-10 13:09:42 +0300 + + xz/DOS: Add experimental 8.3 filename support. + + This is incompatible with the 8.3 support patch made by + Juan Manuel Guerrero. I think this one is nicer, but + I need to get feedback from DOS users before saying + that this is the final version of 8.3 filename support. + + src/xz/suffix.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 167 insertions(+), 9 deletions(-) + +commit cd4fe97852bcaeffe674ee51b4613709292a0972 +Author: Lasse Collin +Date: 2011-04-10 12:47:47 +0300 + + xz/DOS: Be more careful with the destination file. + + Try to avoid overwriting the source file if --force is + used and the generated destination filename refers to + the source file. This can happen with 8.3 filenames where + extra characters are ignored. + + If the generated output file refers to a special file + like "con" or "prn", refuse to write to it even if --force + is used. + + src/xz/file_io.c | 35 +++++++++++++++++++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) + +commit 607f9f98ae5ef6d49f4c21c806d462bf6b3d6796 Author: Lasse Collin Date: 2011-04-09 18:29:30 +0300 @@ -1557,7 +3665,7 @@ Date: 2011-04-09 18:29:30 +0300 THANKS | 1 + 1 file changed, 1 insertion(+) -commit 28154eeaf6e3442cd1e174f4e81266d60c4dac60 +commit fca396b37410d272b754843a5dc13847be443a3a Author: Lasse Collin Date: 2011-04-09 18:28:58 +0300 @@ -1571,7 +3679,93 @@ Date: 2011-04-09 18:28:58 +0300 src/liblzma/common/filter_common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) -commit aa95516d3d509c6b7895ee519004afcf500a0759 +commit b03f6cd3ebadd675f2cc9d518cb26fa860269447 +Author: Lasse Collin +Date: 2011-04-09 15:24:59 +0300 + + xz: Avoid unneeded fstat() on DOS-like systems. + + src/xz/file_io.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +commit 335fe260a81f61ec99ff5940df733b4c50aedb7c +Author: Lasse Collin +Date: 2011-04-09 15:11:13 +0300 + + xz: Minor internal changes to handling of --threads. + + Now it always defaults to one thread. Maybe this + will change again if a threading method is added + that doesn't affect memory usage. + + src/xz/args.c | 4 ++-- + src/xz/hardware.c | 24 ++++++++++++------------ + src/xz/hardware.h | 9 ++++----- + 3 files changed, 18 insertions(+), 19 deletions(-) + +commit 9edd6ee895fbe71d245a173f48e511f154a99875 +Author: Lasse Collin +Date: 2011-04-08 17:53:05 +0300 + + xz: Change size_t to uint32_t in a few places. + + src/xz/coder.c | 6 +++--- + src/xz/coder.h | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +commit 411013ea4506a6df24d35a060fcbd73a57b73eb3 +Author: Lasse Collin +Date: 2011-04-08 17:48:41 +0300 + + xz: Fix a typo in a comment. + + src/xz/coder.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit b34c5ce4b22e8d7b81f9895d15054af41d17f805 +Author: Lasse Collin +Date: 2011-04-05 22:41:33 +0300 + + liblzma: Use TUKLIB_GNUC_REQ to check GCC version in sha256.c. + + src/liblzma/check/sha256.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +commit db33117cc85c17e0b897b5312bd5eb43aac41c03 +Author: Lasse Collin +Date: 2011-04-05 17:12:20 +0300 + + Build: Upgrade m4/acx_pthread.m4 to the latest version. + + It was renamed to ax_pthread.m4 in Autoconf Archive. + + configure.ac | 2 +- + m4/acx_pthread.m4 | 279 ----------------------------------------------------- + m4/ax_pthread.m4 | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 284 insertions(+), 280 deletions(-) + +commit 1039bfcfc098b69d56ecb39d198a092552eacf6d +Author: Lasse Collin +Date: 2011-04-05 15:27:26 +0300 + + xz: Use posix_fadvise() if it is available. + + configure.ac | 3 +++ + src/xz/file_io.c | 15 +++++++++++++++ + 2 files changed, 18 insertions(+) + +commit 1ef3cf44a8eb9512480af4482a5232ea08363b14 +Author: Lasse Collin +Date: 2011-04-05 15:13:29 +0300 + + xz: Call lzma_end(&strm) before exiting if debugging is enabled. + + src/xz/coder.c | 10 ++++++++++ + src/xz/coder.h | 5 +++++ + src/xz/main.c | 4 ++++ + 3 files changed, 19 insertions(+) + +commit bd432015d33dcade611d297bc01eb0700088ef6c Author: Lasse Collin Date: 2011-04-02 14:49:56 +0300 @@ -1584,17 +3778,7 @@ Date: 2011-04-02 14:49:56 +0300 src/liblzma/common/stream_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -commit 58f52c72f49562a08042da9a2f4bbdf4dd162d0c -Author: Lasse Collin -Date: 2011-04-01 08:47:46 +0300 - - Bumped version and liblzma soname to 5.0.2. - - src/liblzma/Makefile.am | 2 +- - src/liblzma/api/lzma/version.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -commit 162779682e01d15f0ce386ef7f40d1be05ad0053 +commit 16889013214e7620d204b6e6c1bf9f3103a13655 Author: Lasse Collin Date: 2011-04-01 08:47:20 +0300 @@ -1603,7 +3787,7 @@ Date: 2011-04-01 08:47:20 +0300 NEWS | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) -commit 45553f9b4b0175c292023010dc41520347004852 +commit 85cdf7dd4e97b078e7b929e47f55a7f1da36010f Author: Lasse Collin Date: 2011-03-31 15:06:58 +0300 @@ -1612,7 +3796,7 @@ Date: 2011-03-31 15:06:58 +0300 INSTALL | 4 ++++ 1 file changed, 4 insertions(+) -commit af9d48d5515eadef689b1ce9ffb91e4dbcbc7f35 +commit c3f4995586873d6a4fb7e451010a128571a9a370 Author: Lasse Collin Date: 2011-03-31 12:22:55 +0300 @@ -1622,7 +3806,7 @@ Date: 2011-03-31 12:22:55 +0300 tests/files/good-1-lzma2-5.xz | Bin 0 -> 52 bytes 2 files changed, 4 insertions(+) -commit d099ef9f517b59ab8e3b6f6aa0543c3643983470 +commit 0d21f49a809dc2088da6cc0da7f948404df7ecfa Author: Lasse Collin Date: 2011-03-31 11:54:48 +0300 @@ -1636,7 +3820,7 @@ Date: 2011-03-31 11:54:48 +0300 src/liblzma/lzma/lzma2_decoder.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) -commit df87249b26e79a75fd91041e85512944fc247b57 +commit 40277998cb9bad564ce4827aff152e6e1c904dfa Author: Lasse Collin Date: 2011-03-24 01:42:49 +0200 @@ -1649,7 +3833,7 @@ Date: 2011-03-24 01:42:49 +0200 src/scripts/xzgrep.in | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) -commit 68c453e1c7b09dc9c7d2ef9d994c46f5b367f5d3 +commit 2118733045ad0ca183a3f181a0399baf876983a6 Author: Lasse Collin Date: 2011-03-24 01:22:18 +0200 @@ -1658,7 +3842,7 @@ Date: 2011-03-24 01:22:18 +0200 THANKS | 1 + 1 file changed, 1 insertion(+) -commit b441d39855516ae618faffd5156261b8b413394f +commit c7210d9a3fca6f31a57208bfddfc9ab20a2e097a Author: Lasse Collin Date: 2011-03-24 01:21:32 +0200 @@ -1675,7 +3859,52 @@ Date: 2011-03-24 01:21:32 +0200 src/scripts/xzgrep.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) -commit 82d5164839517f55daeadd9ee88c76425db30224 +commit 4eb83e32046a6d670862bc91c3d82530963b455e +Author: Lasse Collin +Date: 2011-03-19 13:08:22 +0200 + + Scripts: Add lzop (.lzo) support to xzdiff and xzgrep. + + src/scripts/xzdiff.1 | 6 ++++-- + src/scripts/xzdiff.in | 22 ++++++++++++++-------- + src/scripts/xzgrep.1 | 11 +++++++---- + src/scripts/xzgrep.in | 5 +++-- + 4 files changed, 28 insertions(+), 16 deletions(-) + +commit 923b22483bd9356f3219b2b784d96f455f4dc499 +Author: Lasse Collin +Date: 2011-03-18 19:10:30 +0200 + + xz: Add --block-size=SIZE. + + This uses LZMA_FULL_FLUSH every SIZE bytes of input. + + Man page wasn't updated yet. + + src/xz/args.c | 7 +++++++ + src/xz/coder.c | 50 ++++++++++++++++++++++++++++++++++++++++---------- + src/xz/coder.h | 3 +++ + src/xz/message.c | 4 ++++ + 4 files changed, 54 insertions(+), 10 deletions(-) + +commit 57597d42ca1740ad506437be168d800a50f1a0ad +Author: Lasse Collin +Date: 2011-03-18 18:19:19 +0200 + + xz: Add --single-stream. + + This can be useful when there is garbage after the + compressed stream (.xz, .lzma, or raw stream). + + Man page wasn't updated yet. + + src/xz/args.c | 6 ++++++ + src/xz/coder.c | 11 +++++++++-- + src/xz/coder.h | 3 +++ + src/xz/message.c | 6 +++++- + 4 files changed, 23 insertions(+), 3 deletions(-) + +commit 96f94bc925d579a700147fa5d7793b64d69cfc18 Author: Lasse Collin Date: 2011-02-04 22:49:31 +0200 @@ -1687,7 +3916,7 @@ Date: 2011-02-04 22:49:31 +0200 src/xz/suffix.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) -commit 6decc8b41882c2250f0450eb87b83c9fbf495e95 +commit 8930c7ae3f82bdae15aa129f01de08be23d7e8d7 Author: Lasse Collin Date: 2011-02-04 11:29:47 +0200 @@ -1700,7 +3929,7 @@ Date: 2011-02-04 11:29:47 +0200 src/xz/suffix.c | 9 +++++++++ 1 file changed, 9 insertions(+) -commit ecda90061df8d39399e707e5c76c2ec0a0f400e5 +commit 940d5852c6cf08abccc6befd9d1b5411c9076a58 Author: Lasse Collin Date: 2011-02-02 23:01:51 +0200 @@ -1709,7 +3938,7 @@ Date: 2011-02-02 23:01:51 +0200 THANKS | 1 + 1 file changed, 1 insertion(+) -commit 0fda1ae5b1aa0a5c629a09e5228db8ba1cd0dd5f +commit 4ebe65f839613f27f127bab7b8c347d982330ee3 Author: Lasse Collin Date: 2011-02-02 23:00:33 +0200 @@ -1721,7 +3950,7 @@ Date: 2011-02-02 23:00:33 +0200 po/pl.po | 825 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 826 insertions(+) -commit 00be32978fedc5038748438bf685ac1713d1db83 +commit fc1d292dca1925dfd17174f443f91a696ecd5bf8 Author: Lasse Collin Date: 2011-02-02 22:24:00 +0200 @@ -1730,15 +3959,12 @@ Date: 2011-02-02 22:24:00 +0200 THANKS | 1 + 1 file changed, 1 insertion(+) -commit 7232fcf96bf4bd5f9cd4fc6c93ca2912c665e004 +commit 6dd061adfd2775428b079eb03d6fd47d7c0f1ffe +Merge: 9d542ce 5fbce0b Author: Lasse Collin -Date: 2011-01-28 20:26:38 +0200 +Date: 2011-02-06 20:13:01 +0200 - Bump package version and liblzma soname to 5.0.1. - - src/liblzma/Makefile.am | 2 +- - src/liblzma/api/lzma/version.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) + Merge commit '5fbce0b8d96dc96775aa0215e3581addc830e23d' commit 5fbce0b8d96dc96775aa0215e3581addc830e23d Author: Lasse Collin @@ -1764,6 +3990,13 @@ Date: 2011-01-26 12:19:08 +0200 src/xz/file_io.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) +commit 9d542ceebcbe40b174169c132ccfcdc720ca7089 +Merge: 4f2c69a 7bd0a5e +Author: Lasse Collin +Date: 2011-01-19 11:45:35 +0200 + + Merge branch 'v5.0' + commit 7bd0a5e7ccc354f7c2e95c8bc27569c820f6a136 Author: Lasse Collin Date: 2011-01-18 21:25:24 +0200 @@ -1795,6 +4028,13 @@ Date: 2010-12-13 16:36:33 +0200 src/scripts/xzdiff.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) +commit 4f2c69a4e3e0aee2e37b0b1671d34086e20c8ac6 +Merge: adb89e6 9311774 +Author: Lasse Collin +Date: 2010-12-12 23:13:22 +0200 + + Merge branch 'v5.0' + commit 9311774c493c19deab51ded919dcd2e9c4aa2829 Author: Lasse Collin Date: 2010-12-12 21:23:55 +0200 @@ -1838,6 +4078,13 @@ Date: 2010-12-12 14:50:04 +0200 src/xz/suffix.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) +commit adb89e68d43a4cadb0c215b45ef7a75737c9c3ec +Merge: 7c24e0d b7afd3e +Author: Lasse Collin +Date: 2010-12-07 18:53:04 +0200 + + Merge branch 'v5.0' + commit b7afd3e22a8fac115b75c738d40d3eb1de7e286f Author: Lasse Collin Date: 2010-12-07 18:52:04 +0200 @@ -1849,6 +4096,13 @@ Date: 2010-12-07 18:52:04 +0200 po/cs.po | 88 ++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) +commit 7c24e0d1b8a2e86e9263b0d56d39621e01aed7af +Merge: b4d42f1 3e56470 +Author: Lasse Collin +Date: 2010-11-15 14:33:01 +0200 + + Merge branch 'v5.0' + commit 3e564704bc6f463cb2db11e3f3f0dbd71d85992e Author: Lasse Collin Date: 2010-11-15 14:28:26 +0200 @@ -1883,6 +4137,34 @@ Date: 2010-11-12 15:22:13 -0600 Doxyfile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) +commit b4d42f1a7120e2cefeb2f14425efe2ca6db85416 +Author: Anders F Bjorklund +Date: 2010-11-05 12:56:11 +0100 + + add build script for macosx universal + + macosx/build.sh | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 92 insertions(+) + +commit 15ee6935abe4a2fc76639ee342ca2e69af3e0ad6 +Author: Lasse Collin +Date: 2010-11-04 18:31:40 +0200 + + Update the copies of GPLv2 and LGPLv2.1 from gnu.org. + + There are only a few white space changes. + + COPYING.GPLv2 | 14 +++++++------- + COPYING.LGPLv2.1 | 16 +++++++--------- + 2 files changed, 14 insertions(+), 16 deletions(-) + +commit 8e355f7fdbeee6fe394eb02a28f267ce99a882a2 +Merge: 974ebe6 37c2565 +Author: Lasse Collin +Date: 2010-10-26 15:53:06 +0300 + + Merge branch 'v5.0' + commit 37c25658efd25b034266daf87cd381d20d1df776 Author: Lasse Collin Date: 2010-10-26 15:48:48 +0300 @@ -1898,6 +4180,37 @@ Date: 2010-10-26 15:48:48 +0300 windows/build.bash | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) +commit 974ebe63497bdf0d262e06474f0dd5a70b1dd000 +Author: Lasse Collin +Date: 2010-10-26 10:36:41 +0300 + + liblzma: Rename a few variables and constants. + + This has no semantic changes. I find the new names slightly + more logical and they match the names that are already used + in XZ Embedded. + + The name fastpos wasn't changed (not worth the hassle). + + src/liblzma/lzma/fastpos.h | 55 +++++------ + src/liblzma/lzma/lzma2_encoder.c | 2 +- + src/liblzma/lzma/lzma_common.h | 45 ++++----- + src/liblzma/lzma/lzma_decoder.c | 58 +++++------ + src/liblzma/lzma/lzma_encoder.c | 56 +++++------ + src/liblzma/lzma/lzma_encoder_optimum_fast.c | 9 +- + src/liblzma/lzma/lzma_encoder_optimum_normal.c | 128 ++++++++++++------------- + src/liblzma/lzma/lzma_encoder_private.h | 16 ++-- + 8 files changed, 183 insertions(+), 186 deletions(-) + +commit 7c427ec38d016c0070a42315d752857e33792fc4 +Author: Lasse Collin +Date: 2010-10-25 12:59:25 +0300 + + Bump version 5.1.0alpha. + + src/liblzma/api/lzma/version.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + commit e45929260cd902036efd40c5610a8d0a50d5712b Author: Lasse Collin Date: 2010-10-23 17:25:52 +0300 diff --git a/THANKS b/THANKS index 79a24f2537ec..f5f539c4b71e 100644 --- a/THANKS +++ b/THANKS @@ -30,17 +30,26 @@ has been important. :-) In alphabetical order: - Denis Excoffier - Michael Felt - Mike Frysinger + - Daniel Richard G. + - Bill Glessner - Jason Gorski - Juan Manuel Guerrero + - Diederik de Haas - Joachim Henke + - Christian Hesse + - Vincenzo Innocente - Peter Ivanov - Jouk Jansen + - Jun I Jin - Per Øyvind Karlsen - Thomas Klausner - Richard Koch - Ville Koskinen + - Jan Kratochvil + - Christian Kujau - Stephan Kulow - Peter Lawler + - James M Leddy - Hin-Tak Leung - Andraž 'ruskie' Levstik - Cary Lewis @@ -49,6 +58,7 @@ has been important. :-) In alphabetical order: - Bela Lubkin - Gregory Margo - Jim Meyering + - Arkadiusz Miskiewicz - Conley Moorhous - Rafał Mużyło - Adrien Nader @@ -61,6 +71,7 @@ has been important. :-) In alphabetical order: - Diego Elio Pettenò - Elbert Pol - Mikko Pouru + - Trần Ngọc Quân - Pavel Raiskup - Robert Readman - Bernhard Reutner-Fischer @@ -75,6 +86,7 @@ has been important. :-) In alphabetical order: - Stuart Shelton - Jonathan Stott - Dan Stromberg + - Vincent Torri - Paul Townsend - Mohammed Adnène Trojette - Alexey Tourbin @@ -82,6 +94,7 @@ has been important. :-) In alphabetical order: - Martin Väth - Christian Weisgerber - Bert Wesarg + - Fredrik Wikstrom - Ralf Wildenhues - Charles Wilson - Lars Wirzenius diff --git a/TODO b/TODO index 4d9b6b51ced3..45ba433a5832 100644 --- a/TODO +++ b/TODO @@ -28,14 +28,36 @@ Known bugs time and calculated (de)compression speed won't make sense in the progress indicator (xz --verbose). + If liblzma has created threads and fork() gets called, liblzma + code will break in the child process unless it calls exec() and + doesn't touch liblzma. + Missing features ---------------- + Add support for storing metadata in .xz files. A preliminary + idea is to create a new Stream type for metadata. When both + metadata and data are wanted in the same .xz file, two or more + Streams would be concatenated. + + The state stored in lzma_stream should be cloneable, which would + be mostly useful when using a preset dictionary in LZMA2, but + it may have other uses too. Compare to deflateCopy() in zlib. + + Support LZMA_FINISH in raw decoder to indicate end of LZMA1 and + other streams that don't have an end of payload marker. + + Adjust dictionary size when the input file size is known. + Maybe do this only if an option is given. + xz doesn't support copying extended attributes, access control lists etc. from source to target file. - Multithreaded compression + Multithreaded compression: + - Reduce memory usage of the current method. + - Implement threaded match finders. + - Implement pigz-style threading in LZMA2. Multithreaded decompression @@ -46,18 +68,44 @@ Missing features It will be a separate library that supports uncompressed, .gz, .bz2, .lzma, and .xz files. + Support changing lzma_options_lzma.mode with lzma_filters_update(). + + Support LZMA_FULL_FLUSH for lzma_stream_decoder() to stop at + Block and Stream boundaries. + lzma_strerror() to convert lzma_ret to human readable form? This is tricky, because the same error codes are used with slightly different meanings, and this cannot be fixed anymore. + Make it possible to adjust LZMA2 options in the middle of a Block + so that the encoding speed vs. compression ratio can be optimized + when the compressed data is streamed over network. + + Improved BCJ filters. The current filters are small but they aren't + so great when compressing binary packages that contain various file + types. Specifically, they make things worse if there are static + libraries or Linux kernel modules. The filtering could also be + more effective (without getting overly complex), for example, + streamable variant BCJ2 from 7-Zip could be implemented. + + Filter that autodetects specific data types in the input stream + and applies appropriate filters for the corrects parts of the input. + Perhaps combine this with the BCJ filter improvement point above. + + Long-range LZ77 method as a separate filter or as a new LZMA2 + match finder. + Documentation ------------- - Some tutorial is needed for liblzma. I have planned to write some - extremely well commented example programs, which would work as - a tutorial. I suppose the Doxygen tags are quite OK as a quick - reference once one is familiar with the liblzma API. + More tutorial programs are needed for liblzma. Document the LZMA1 and LZMA2 algorithms. + +Miscellaneous +------------ + + Try to get the media type for .xz registered at IANA. + diff --git a/src/common/mythread.h b/src/common/mythread.h index 476c2fc9e103..be22654240aa 100644 --- a/src/common/mythread.h +++ b/src/common/mythread.h @@ -1,7 +1,7 @@ /////////////////////////////////////////////////////////////////////////////// // /// \file mythread.h -/// \brief Wrappers for threads +/// \brief Some threading related helper macros and functions // // Author: Lasse Collin // @@ -10,33 +10,512 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifndef MYTHREAD_H +#define MYTHREAD_H + #include "sysdefs.h" +// If any type of threading is enabled, #define MYTHREAD_ENABLED. +#if defined(MYTHREAD_POSIX) || defined(MYTHREAD_WIN95) \ + || defined(MYTHREAD_VISTA) +# define MYTHREAD_ENABLED 1 +#endif -#ifdef HAVE_PTHREAD -# include -# define mythread_once(func) \ +#ifdef MYTHREAD_ENABLED + +//////////////////////////////////////// +// Shared between all threading types // +//////////////////////////////////////// + +// Locks a mutex for a duration of a block. +// +// Perform mythread_mutex_lock(&mutex) in the beginning of a block +// and mythread_mutex_unlock(&mutex) at the end of the block. "break" +// may be used to unlock the mutex and jump out of the block. +// mythread_sync blocks may be nested. +// +// Example: +// +// mythread_sync(mutex) { +// foo(); +// if (some_error) +// break; // Skips bar() +// bar(); +// } +// +// At least GCC optimizes the loops completely away so it doesn't slow +// things down at all compared to plain mythread_mutex_lock(&mutex) +// and mythread_mutex_unlock(&mutex) calls. +// +#define mythread_sync(mutex) mythread_sync_helper1(mutex, __LINE__) +#define mythread_sync_helper1(mutex, line) mythread_sync_helper2(mutex, line) +#define mythread_sync_helper2(mutex, line) \ + for (unsigned int mythread_i_ ## line = 0; \ + mythread_i_ ## line \ + ? (mythread_mutex_unlock(&(mutex)), 0) \ + : (mythread_mutex_lock(&(mutex)), 1); \ + mythread_i_ ## line = 1) \ + for (unsigned int mythread_j_ ## line = 0; \ + !mythread_j_ ## line; \ + mythread_j_ ## line = 1) +#endif + + +#if !defined(MYTHREAD_ENABLED) + +////////////////// +// No threading // +////////////////// + +// Calls the given function once. This isn't thread safe. +#define mythread_once(func) \ +do { \ + static bool once_ = false; \ + if (!once_) { \ + func(); \ + once_ = true; \ + } \ +} while (0) + + +#if !(defined(_WIN32) && !defined(__CYGWIN__)) +// Use sigprocmask() to set the signal mask in single-threaded programs. +#include + +static inline void +mythread_sigmask(int how, const sigset_t *restrict set, + sigset_t *restrict oset) +{ + int ret = sigprocmask(how, set, oset); + assert(ret == 0); + (void)ret; +} +#endif + + +#elif defined(MYTHREAD_POSIX) + +//////////////////// +// Using pthreads // +//////////////////// + +#include +#include +#include +#include +#include + +#define MYTHREAD_RET_TYPE void * +#define MYTHREAD_RET_VALUE NULL + +typedef pthread_t mythread; +typedef pthread_mutex_t mythread_mutex; + +typedef struct { + pthread_cond_t cond; +#ifdef HAVE_CLOCK_GETTIME + // Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with + // the condition variable. + clockid_t clk_id; +#endif +} mythread_cond; + +typedef struct timespec mythread_condtime; + + +// Calls the given function once in a thread-safe way. +#define mythread_once(func) \ do { \ static pthread_once_t once_ = PTHREAD_ONCE_INIT; \ pthread_once(&once_, &func); \ } while (0) -# define mythread_sigmask(how, set, oset) \ - pthread_sigmask(how, set, oset) +// Use pthread_sigmask() to set the signal mask in multi-threaded programs. +// Do nothing on OpenVMS since it lacks pthread_sigmask(). +static inline void +mythread_sigmask(int how, const sigset_t *restrict set, + sigset_t *restrict oset) +{ +#ifdef __VMS + (void)how; + (void)set; + (void)oset; #else + int ret = pthread_sigmask(how, set, oset); + assert(ret == 0); + (void)ret; +#endif +} -# define mythread_once(func) \ + +// Creates a new thread with all signals blocked. Returns zero on success +// and non-zero on error. +static inline int +mythread_create(mythread *thread, void *(*func)(void *arg), void *arg) +{ + sigset_t old; + sigset_t all; + sigfillset(&all); + + mythread_sigmask(SIG_SETMASK, &all, &old); + const int ret = pthread_create(thread, NULL, func, arg); + mythread_sigmask(SIG_SETMASK, &old, NULL); + + return ret; +} + +// Joins a thread. Returns zero on success and non-zero on error. +static inline int +mythread_join(mythread thread) +{ + return pthread_join(thread, NULL); +} + + +// Initiatlizes a mutex. Returns zero on success and non-zero on error. +static inline int +mythread_mutex_init(mythread_mutex *mutex) +{ + return pthread_mutex_init(mutex, NULL); +} + +static inline void +mythread_mutex_destroy(mythread_mutex *mutex) +{ + int ret = pthread_mutex_destroy(mutex); + assert(ret == 0); + (void)ret; +} + +static inline void +mythread_mutex_lock(mythread_mutex *mutex) +{ + int ret = pthread_mutex_lock(mutex); + assert(ret == 0); + (void)ret; +} + +static inline void +mythread_mutex_unlock(mythread_mutex *mutex) +{ + int ret = pthread_mutex_unlock(mutex); + assert(ret == 0); + (void)ret; +} + + +// Initializes a condition variable. +// +// Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the +// timeout in pthread_cond_timedwait() work correctly also if system time +// is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available +// everywhere while the default CLOCK_REALTIME is, so the default is +// used if CLOCK_MONOTONIC isn't available. +// +// If clock_gettime() isn't available at all, gettimeofday() will be used. +static inline int +mythread_cond_init(mythread_cond *mycond) +{ +#ifdef HAVE_CLOCK_GETTIME + // NOTE: HAVE_DECL_CLOCK_MONOTONIC is always defined to 0 or 1. +# if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && HAVE_DECL_CLOCK_MONOTONIC + struct timespec ts; + pthread_condattr_t condattr; + + // POSIX doesn't seem to *require* that pthread_condattr_setclock() + // will fail if given an unsupported clock ID. Test that + // CLOCK_MONOTONIC really is supported using clock_gettime(). + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0 + && pthread_condattr_init(&condattr) == 0) { + int ret = pthread_condattr_setclock( + &condattr, CLOCK_MONOTONIC); + if (ret == 0) + ret = pthread_cond_init(&mycond->cond, &condattr); + + pthread_condattr_destroy(&condattr); + + if (ret == 0) { + mycond->clk_id = CLOCK_MONOTONIC; + return 0; + } + } + + // If anything above fails, fall back to the default CLOCK_REALTIME. + // POSIX requires that all implementations of clock_gettime() must + // support at least CLOCK_REALTIME. +# endif + + mycond->clk_id = CLOCK_REALTIME; +#endif + + return pthread_cond_init(&mycond->cond, NULL); +} + +static inline void +mythread_cond_destroy(mythread_cond *cond) +{ + int ret = pthread_cond_destroy(&cond->cond); + assert(ret == 0); + (void)ret; +} + +static inline void +mythread_cond_signal(mythread_cond *cond) +{ + int ret = pthread_cond_signal(&cond->cond); + assert(ret == 0); + (void)ret; +} + +static inline void +mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex) +{ + int ret = pthread_cond_wait(&cond->cond, mutex); + assert(ret == 0); + (void)ret; +} + +// Waits on a condition or until a timeout expires. If the timeout expires, +// non-zero is returned, otherwise zero is returned. +static inline int +mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex, + const mythread_condtime *condtime) +{ + int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime); + assert(ret == 0 || ret == ETIMEDOUT); + return ret; +} + +// Sets condtime to the absolute time that is timeout_ms milliseconds +// in the future. The type of the clock to use is taken from cond. +static inline void +mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond, + uint32_t timeout_ms) +{ + condtime->tv_sec = timeout_ms / 1000; + condtime->tv_nsec = (timeout_ms % 1000) * 1000000; + +#ifdef HAVE_CLOCK_GETTIME + struct timespec now; + int ret = clock_gettime(cond->clk_id, &now); + assert(ret == 0); + (void)ret; + + condtime->tv_sec += now.tv_sec; + condtime->tv_nsec += now.tv_nsec; +#else + (void)cond; + + struct timeval now; + gettimeofday(&now, NULL); + + condtime->tv_sec += now.tv_sec; + condtime->tv_nsec += now.tv_usec * 1000L; +#endif + + // tv_nsec must stay in the range [0, 999_999_999]. + if (condtime->tv_nsec >= 1000000000L) { + condtime->tv_nsec -= 1000000000L; + ++condtime->tv_sec; + } +} + + +#elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA) + +///////////////////// +// Windows threads // +///////////////////// + +#define WIN32_LEAN_AND_MEAN +#ifdef MYTHREAD_VISTA +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0600 +#endif +#include +#include + +#define MYTHREAD_RET_TYPE unsigned int __stdcall +#define MYTHREAD_RET_VALUE 0 + +typedef HANDLE mythread; +typedef CRITICAL_SECTION mythread_mutex; + +#ifdef MYTHREAD_WIN95 +typedef HANDLE mythread_cond; +#else +typedef CONDITION_VARIABLE mythread_cond; +#endif + +typedef struct { + // Tick count (milliseconds) in the beginning of the timeout. + // NOTE: This is 32 bits so it wraps around after 49.7 days. + // Multi-day timeouts may not work as expected. + DWORD start; + + // Length of the timeout in milliseconds. The timeout expires + // when the current tick count minus "start" is equal or greater + // than "timeout". + DWORD timeout; +} mythread_condtime; + + +// mythread_once() is only available with Vista threads. +#ifdef MYTHREAD_VISTA +#define mythread_once(func) \ do { \ - static bool once_ = false; \ - if (!once_) { \ + static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \ + BOOL pending_; \ + if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \ + abort(); \ + if (pending_) \ func(); \ - once_ = true; \ - } \ + if (!InitOnceComplete(&once, 0, NULL)) \ + abort(); \ } while (0) +#endif -# define mythread_sigmask(how, set, oset) \ - sigprocmask(how, set, oset) + +// mythread_sigmask() isn't available on Windows. Even a dummy version would +// make no sense because the other POSIX signal functions are missing anyway. + + +static inline int +mythread_create(mythread *thread, + unsigned int (__stdcall *func)(void *arg), void *arg) +{ + uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL); + if (ret == 0) + return -1; + + *thread = (HANDLE)ret; + return 0; +} + +static inline int +mythread_join(mythread thread) +{ + int ret = 0; + + if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) + ret = -1; + + if (!CloseHandle(thread)) + ret = -1; + + return ret; +} + + +static inline int +mythread_mutex_init(mythread_mutex *mutex) +{ + InitializeCriticalSection(mutex); + return 0; +} + +static inline void +mythread_mutex_destroy(mythread_mutex *mutex) +{ + DeleteCriticalSection(mutex); +} + +static inline void +mythread_mutex_lock(mythread_mutex *mutex) +{ + EnterCriticalSection(mutex); +} + +static inline void +mythread_mutex_unlock(mythread_mutex *mutex) +{ + LeaveCriticalSection(mutex); +} + + +static inline int +mythread_cond_init(mythread_cond *cond) +{ +#ifdef MYTHREAD_WIN95 + *cond = CreateEvent(NULL, FALSE, FALSE, NULL); + return *cond == NULL ? -1 : 0; +#else + InitializeConditionVariable(cond); + return 0; +#endif +} + +static inline void +mythread_cond_destroy(mythread_cond *cond) +{ +#ifdef MYTHREAD_WIN95 + CloseHandle(*cond); +#else + (void)cond; +#endif +} + +static inline void +mythread_cond_signal(mythread_cond *cond) +{ +#ifdef MYTHREAD_WIN95 + SetEvent(*cond); +#else + WakeConditionVariable(cond); +#endif +} + +static inline void +mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex) +{ +#ifdef MYTHREAD_WIN95 + LeaveCriticalSection(mutex); + WaitForSingleObject(*cond, INFINITE); + EnterCriticalSection(mutex); +#else + BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE); + assert(ret); + (void)ret; +#endif +} + +static inline int +mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex, + const mythread_condtime *condtime) +{ +#ifdef MYTHREAD_WIN95 + LeaveCriticalSection(mutex); +#endif + + DWORD elapsed = GetTickCount() - condtime->start; + DWORD timeout = elapsed >= condtime->timeout + ? 0 : condtime->timeout - elapsed; + +#ifdef MYTHREAD_WIN95 + DWORD ret = WaitForSingleObject(*cond, timeout); + assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT); + + EnterCriticalSection(mutex); + + return ret == WAIT_TIMEOUT; +#else + BOOL ret = SleepConditionVariableCS(cond, mutex, timeout); + assert(ret || GetLastError() == ERROR_TIMEOUT); + return !ret; +#endif +} + +static inline void +mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond, + uint32_t timeout) +{ + (void)cond; + condtime->start = GetTickCount(); + condtime->timeout = timeout; +} + +#endif #endif diff --git a/src/common/sysdefs.h b/src/common/sysdefs.h index 5ea6bdae4aed..e056ca4ac908 100644 --- a/src/common/sysdefs.h +++ b/src/common/sysdefs.h @@ -165,6 +165,16 @@ typedef unsigned char _Bool; # include #endif +// As of MSVC 2013, inline and restrict are supported with +// non-standard keywords. +#if defined(_WIN32) && defined(_MSC_VER) +# ifndef inline +# define inline __inline +# endif +# ifndef restrict +# define restrict __restrict +# endif +#endif //////////// // Macros // diff --git a/src/common/tuklib_cpucores.c b/src/common/tuklib_cpucores.c index 1da13df7f5f6..7574bc9c0645 100644 --- a/src/common/tuklib_cpucores.c +++ b/src/common/tuklib_cpucores.c @@ -12,7 +12,13 @@ #include "tuklib_cpucores.h" -#if defined(TUKLIB_CPUCORES_SYSCTL) +#if defined(_WIN32) || defined(__CYGWIN__) +# ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x0500 +# endif +# include + +#elif defined(TUKLIB_CPUCORES_SYSCTL) # ifdef HAVE_SYS_PARAM_H # include # endif @@ -33,7 +39,12 @@ tuklib_cpucores(void) { uint32_t ret = 0; -#if defined(TUKLIB_CPUCORES_SYSCTL) +#if defined(_WIN32) || defined(__CYGWIN__) + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + ret = sysinfo.dwNumberOfProcessors; + +#elif defined(TUKLIB_CPUCORES_SYSCTL) int name[2] = { CTL_HW, HW_NCPU }; int cpus; size_t cpus_size = sizeof(cpus); diff --git a/src/common/tuklib_physmem.c b/src/common/tuklib_physmem.c index 623b6e70b7f2..3cc7d12a171f 100644 --- a/src/common/tuklib_physmem.c +++ b/src/common/tuklib_physmem.c @@ -33,6 +33,10 @@ # include # include +#elif defined(AMIGA) || defined(__AROS__) +# define __USE_INLINE__ +# include + // AIX #elif defined(TUKLIB_PHYSMEM_AIX) # include @@ -119,6 +123,9 @@ tuklib_physmem(void) if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL) ret = (uint64_t)vms_mem * 8192; +#elif defined(AMIGA) || defined(__AROS__) + ret = AvailMem(MEMF_TOTAL); + #elif defined(TUKLIB_PHYSMEM_AIX) ret = _system_configuration.physmem; diff --git a/src/liblzma/api/lzma.h b/src/liblzma/api/lzma.h index fb874c3e1377..72c51b2411c3 100644 --- a/src/liblzma/api/lzma.h +++ b/src/liblzma/api/lzma.h @@ -286,7 +286,7 @@ extern "C" { #include "lzma/filter.h" #include "lzma/bcj.h" #include "lzma/delta.h" -#include "lzma/lzma.h" +#include "lzma/lzma12.h" /* Container formats */ #include "lzma/container.h" diff --git a/src/liblzma/api/lzma/base.h b/src/liblzma/api/lzma/base.h index 43dde8d60f3d..7a31a4205136 100644 --- a/src/liblzma/api/lzma/base.h +++ b/src/liblzma/api/lzma/base.h @@ -240,12 +240,12 @@ typedef enum { /** * \brief The `action' argument for lzma_code() * - * After the first use of LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, or LZMA_FINISH, - * the same `action' must is used until lzma_code() returns LZMA_STREAM_END. - * Also, the amount of input (that is, strm->avail_in) must not be modified - * by the application until lzma_code() returns LZMA_STREAM_END. Changing the - * `action' or modifying the amount of input will make lzma_code() return - * LZMA_PROG_ERROR. + * After the first use of LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, LZMA_FULL_BARRIER, + * or LZMA_FINISH, the same `action' must is used until lzma_code() returns + * LZMA_STREAM_END. Also, the amount of input (that is, strm->avail_in) must + * not be modified by the application until lzma_code() returns + * LZMA_STREAM_END. Changing the `action' or modifying the amount of input + * will make lzma_code() return LZMA_PROG_ERROR. */ typedef enum { LZMA_RUN = 0, @@ -293,7 +293,7 @@ typedef enum { * * All the input data going to the current Block must have * been given to the encoder (the last bytes can still be - * pending in* next_in). Call lzma_code() with LZMA_FULL_FLUSH + * pending in *next_in). Call lzma_code() with LZMA_FULL_FLUSH * until it returns LZMA_STREAM_END. Then continue normally * with LZMA_RUN or finish the Stream with LZMA_FINISH. * @@ -302,6 +302,29 @@ typedef enum { * no unfinished Block, no empty Block is created. */ + LZMA_FULL_BARRIER = 4, + /**< + * \brief Finish encoding of the current Block + * + * This is like LZMA_FULL_FLUSH except that this doesn't + * necessarily wait until all the input has been made + * available via the output buffer. That is, lzma_code() + * might return LZMA_STREAM_END as soon as all the input + * has been consumed (avail_in == 0). + * + * LZMA_FULL_BARRIER is useful with a threaded encoder if + * one wants to split the .xz Stream into Blocks at specific + * offsets but doesn't care if the output isn't flushed + * immediately. Using LZMA_FULL_BARRIER allows keeping + * the threads busy while LZMA_FULL_FLUSH would make + * lzma_code() wait until all the threads have finished + * until more data could be passed to the encoder. + * + * With a lzma_stream initialized with the single-threaded + * lzma_stream_encoder() or lzma_easy_encoder(), + * LZMA_FULL_BARRIER is an alias for LZMA_FULL_FLUSH. + */ + LZMA_FINISH = 3 /**< * \brief Finish the coding operation @@ -332,11 +355,19 @@ typedef enum { * malloc() and free(). C++ users should note that the custom memory * handling functions must not throw exceptions. * - * liblzma doesn't make an internal copy of lzma_allocator. Thus, it is - * OK to change these function pointers in the middle of the coding - * process, but obviously it must be done carefully to make sure that the - * replacement `free' can deallocate memory allocated by the earlier - * `alloc' function(s). + * Single-threaded mode only: liblzma doesn't make an internal copy of + * lzma_allocator. Thus, it is OK to change these function pointers in + * the middle of the coding process, but obviously it must be done + * carefully to make sure that the replacement `free' can deallocate + * memory allocated by the earlier `alloc' function(s). + * + * Multithreaded mode: liblzma might internally store pointers to the + * lzma_allocator given via the lzma_stream structure. The application + * must not change the allocator pointer in lzma_stream or the contents + * of the pointed lzma_allocator structure until lzma_end() has been used + * to free the memory associated with that lzma_stream. The allocation + * functions might be called simultaneously from multiple threads, and + * thus they must be thread safe. */ typedef struct { /** @@ -448,7 +479,8 @@ typedef struct lzma_internal_s lzma_internal; * * Application may modify the values of total_in and total_out as it wants. * They are updated by liblzma to match the amount of data read and - * written, but aren't used for anything else. + * written but aren't used for anything else except as a possible return + * values from lzma_get_progress(). */ typedef struct { const uint8_t *next_in; /**< Pointer to the next input byte. */ @@ -464,8 +496,10 @@ typedef struct { * * In most cases this is NULL which makes liblzma use * the standard malloc() and free(). + * + * \note In 5.0.x this is not a const pointer. */ - lzma_allocator *allocator; + const lzma_allocator *allocator; /** Internal state is not visible to applications. */ lzma_internal *internal; @@ -546,6 +580,25 @@ extern LZMA_API(lzma_ret) lzma_code(lzma_stream *strm, lzma_action action) extern LZMA_API(void) lzma_end(lzma_stream *strm) lzma_nothrow; +/** + * \brief Get progress information + * + * In single-threaded mode, applications can get progress information from + * strm->total_in and strm->total_out. In multi-threaded mode this is less + * useful because a significant amount of both input and output data gets + * buffered internally by liblzma. This makes total_in and total_out give + * misleading information and also makes the progress indicator updates + * non-smooth. + * + * This function gives realistic progress information also in multi-threaded + * mode by taking into account the progress made by each thread. In + * single-threaded mode *progress_in and *progress_out are set to + * strm->total_in and strm->total_out, respectively. + */ +extern LZMA_API(void) lzma_get_progress(lzma_stream *strm, + uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow; + + /** * \brief Get the memory usage of decoder filter chain * diff --git a/src/liblzma/api/lzma/block.h b/src/liblzma/api/lzma/block.h index e6710a7bc816..7bdcfd7cbe0c 100644 --- a/src/liblzma/api/lzma/block.h +++ b/src/liblzma/api/lzma/block.h @@ -31,11 +31,16 @@ typedef struct { /** * \brief Block format version * - * To prevent API and ABI breakages if new features are needed in - * the Block field, a version number is used to indicate which - * fields in this structure are in use. For now, version must always - * be zero. With non-zero version, most Block related functions will - * return LZMA_OPTIONS_ERROR. + * To prevent API and ABI breakages when new features are needed, + * a version number is used to indicate which fields in this + * structure are in use: + * - liblzma >= 5.0.0: version = 0 is supported. + * - liblzma >= 5.1.4beta: Support for version = 1 was added, + * which adds the ignore_check field. + * + * If version is greater than one, most Block related functions + * will return LZMA_OPTIONS_ERROR (lzma_block_header_decode() works + * with any version value). * * Read by: * - All functions that take pointer to lzma_block as argument, @@ -233,7 +238,28 @@ typedef struct { lzma_reserved_enum reserved_enum2; lzma_reserved_enum reserved_enum3; lzma_reserved_enum reserved_enum4; - lzma_bool reserved_bool1; + + /** + * \brief A flag to Block decoder to not verify the Check field + * + * This field is supported by liblzma >= 5.1.4beta if .version >= 1. + * + * If this is set to true, the integrity check won't be calculated + * and verified. Unless you know what you are doing, you should + * leave this to false. (A reason to set this to true is when the + * file integrity is verified externally anyway and you want to + * speed up the decompression, which matters mostly when using + * SHA-256 as the integrity check.) + * + * If .version >= 1, read by: + * - lzma_block_decoder() + * - lzma_block_buffer_decode() + * + * Written by (.version is ignored): + * - lzma_block_header_decode() always sets this to false + */ + lzma_bool ignore_check; + lzma_bool reserved_bool2; lzma_bool reserved_bool3; lzma_bool reserved_bool4; @@ -310,10 +336,14 @@ extern LZMA_API(lzma_ret) lzma_block_header_encode( /** * \brief Decode Block Header * - * block->version should be set to the highest value supported by the - * application; currently the only possible version is zero. This function - * will set version to the lowest value that still supports all the features - * required by the Block Header. + * block->version should (usually) be set to the highest value supported + * by the application. If the application sets block->version to a value + * higher than supported by the current liblzma version, this function will + * downgrade block->version to the highest value supported by it. Thus one + * should check the value of block->version after calling this function if + * block->version was set to a non-zero value and the application doesn't + * otherwise know that the liblzma version being used is new enough to + * support the specified block->version. * * The size of the Block Header must have already been decoded with * lzma_block_header_size_decode() macro and stored to block->header_size. @@ -344,7 +374,7 @@ extern LZMA_API(lzma_ret) lzma_block_header_encode( * block->header_size is invalid or block->filters is NULL. */ extern LZMA_API(lzma_ret) lzma_block_header_decode(lzma_block *block, - lzma_allocator *allocator, const uint8_t *in) + const lzma_allocator *allocator, const uint8_t *in) lzma_nothrow lzma_attr_warn_unused_result; @@ -493,7 +523,25 @@ extern LZMA_API(size_t) lzma_block_buffer_bound(size_t uncompressed_size) * - LZMA_PROG_ERROR */ extern LZMA_API(lzma_ret) lzma_block_buffer_encode( - lzma_block *block, lzma_allocator *allocator, + lzma_block *block, const lzma_allocator *allocator, + const uint8_t *in, size_t in_size, + uint8_t *out, size_t *out_pos, size_t out_size) + lzma_nothrow lzma_attr_warn_unused_result; + + +/** + * \brief Single-call uncompressed .xz Block encoder + * + * This is like lzma_block_buffer_encode() except this doesn't try to + * compress the data and instead encodes the data using LZMA2 uncompressed + * chunks. The required output buffer size can be determined with + * lzma_block_buffer_bound(). + * + * Since the data won't be compressed, this function ignores block->filters. + * This function doesn't take lzma_allocator because this function doesn't + * allocate any memory from the heap. + */ +extern LZMA_API(lzma_ret) lzma_block_uncomp_encode(lzma_block *block, const uint8_t *in, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow lzma_attr_warn_unused_result; @@ -527,7 +575,7 @@ extern LZMA_API(lzma_ret) lzma_block_buffer_encode( * - LZMA_PROG_ERROR */ extern LZMA_API(lzma_ret) lzma_block_buffer_decode( - lzma_block *block, lzma_allocator *allocator, + lzma_block *block, const lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow; diff --git a/src/liblzma/api/lzma/container.h b/src/liblzma/api/lzma/container.h index 7a9ffc645788..86991add1967 100644 --- a/src/liblzma/api/lzma/container.h +++ b/src/liblzma/api/lzma/container.h @@ -60,6 +60,131 @@ #define LZMA_PRESET_EXTREME (UINT32_C(1) << 31) +/** + * \brief Multithreading options + */ +typedef struct { + /** + * \brief Flags + * + * Set this to zero if no flags are wanted. + * + * No flags are currently supported. + */ + uint32_t flags; + + /** + * \brief Number of worker threads to use + */ + uint32_t threads; + + /** + * \brief Maximum uncompressed size of a Block + * + * The encoder will start a new .xz Block every block_size bytes. + * Using LZMA_FULL_FLUSH or LZMA_FULL_BARRIER with lzma_code() + * the caller may tell liblzma to start a new Block earlier. + * + * With LZMA2, a recommended block size is 2-4 times the LZMA2 + * dictionary size. With very small dictionaries, it is recommended + * to use at least 1 MiB block size for good compression ratio, even + * if this is more than four times the dictionary size. Note that + * these are only recommendations for typical use cases; feel free + * to use other values. Just keep in mind that using a block size + * less than the LZMA2 dictionary size is waste of RAM. + * + * Set this to 0 to let liblzma choose the block size depending + * on the compression options. For LZMA2 it will be 3*dict_size + * or 1 MiB, whichever is more. + * + * For each thread, about 3 * block_size bytes of memory will be + * allocated. This may change in later liblzma versions. If so, + * the memory usage will probably be reduced, not increased. + */ + uint64_t block_size; + + /** + * \brief Timeout to allow lzma_code() to return early + * + * Multithreading can make liblzma to consume input and produce + * output in a very bursty way: it may first read a lot of input + * to fill internal buffers, then no input or output occurs for + * a while. + * + * In single-threaded mode, lzma_code() won't return until it has + * either consumed all the input or filled the output buffer. If + * this is done in multithreaded mode, it may cause a call + * lzma_code() to take even tens of seconds, which isn't acceptable + * in all applications. + * + * To avoid very long blocking times in lzma_code(), a timeout + * (in milliseconds) may be set here. If lzma_code() would block + * longer than this number of milliseconds, it will return with + * LZMA_OK. Reasonable values are 100 ms or more. The xz command + * line tool uses 300 ms. + * + * If long blocking times are fine for you, set timeout to a special + * value of 0, which will disable the timeout mechanism and will make + * lzma_code() block until all the input is consumed or the output + * buffer has been filled. + * + * \note Even with a timeout, lzma_code() might sometimes take + * somewhat long time to return. No timing guarantees + * are made. + */ + uint32_t timeout; + + /** + * \brief Compression preset (level and possible flags) + * + * The preset is set just like with lzma_easy_encoder(). + * The preset is ignored if filters below is non-NULL. + */ + uint32_t preset; + + /** + * \brief Filter chain (alternative to a preset) + * + * If this is NULL, the preset above is used. Otherwise the preset + * is ignored and the filter chain specified here is used. + */ + const lzma_filter *filters; + + /** + * \brief Integrity check type + * + * See check.h for available checks. The xz command line tool + * defaults to LZMA_CHECK_CRC64, which is a good choice if you + * are unsure. + */ + lzma_check check; + + /* + * Reserved space to allow possible future extensions without + * breaking the ABI. You should not touch these, because the names + * of these variables may change. These are and will never be used + * with the currently supported options, so it is safe to leave these + * uninitialized. + */ + lzma_reserved_enum reserved_enum1; + lzma_reserved_enum reserved_enum2; + lzma_reserved_enum reserved_enum3; + uint32_t reserved_int1; + uint32_t reserved_int2; + uint32_t reserved_int3; + uint32_t reserved_int4; + uint64_t reserved_int5; + uint64_t reserved_int6; + uint64_t reserved_int7; + uint64_t reserved_int8; + void *reserved_ptr1; + void *reserved_ptr2; + void *reserved_ptr3; + void *reserved_ptr4; + +} lzma_mt; + + /** * \brief Calculate approximate memory usage of easy encoder * @@ -165,7 +290,8 @@ extern LZMA_API(lzma_ret) lzma_easy_encoder( */ extern LZMA_API(lzma_ret) lzma_easy_buffer_encode( uint32_t preset, lzma_check check, - lzma_allocator *allocator, const uint8_t *in, size_t in_size, + const lzma_allocator *allocator, + const uint8_t *in, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow; @@ -190,6 +316,49 @@ extern LZMA_API(lzma_ret) lzma_stream_encoder(lzma_stream *strm, lzma_nothrow lzma_attr_warn_unused_result; +/** + * \brief Calculate approximate memory usage of multithreaded .xz encoder + * + * Since doing the encoding in threaded mode doesn't affect the memory + * requirements of single-threaded decompressor, you can use + * lzma_easy_decoder_memusage(options->preset) or + * lzma_raw_decoder_memusage(options->filters) to calculate + * the decompressor memory requirements. + * + * \param options Compression options + * + * \return Number of bytes of memory required for encoding with the + * given options. If an error occurs, for example due to + * unsupported preset or filter chain, UINT64_MAX is returned. + */ +extern LZMA_API(uint64_t) lzma_stream_encoder_mt_memusage( + const lzma_mt *options) lzma_nothrow lzma_attr_pure; + + +/** + * \brief Initialize multithreaded .xz Stream encoder + * + * This provides the functionality of lzma_easy_encoder() and + * lzma_stream_encoder() as a single function for multithreaded use. + * + * The supported actions for lzma_code() are LZMA_RUN, LZMA_FULL_FLUSH, + * LZMA_FULL_BARRIER, and LZMA_FINISH. Support for LZMA_SYNC_FLUSH might be + * added in the future. + * + * \param strm Pointer to properly prepared lzma_stream + * \param options Pointer to multithreaded compression options + * + * \return - LZMA_OK + * - LZMA_MEM_ERROR + * - LZMA_UNSUPPORTED_CHECK + * - LZMA_OPTIONS_ERROR + * - LZMA_PROG_ERROR + */ +extern LZMA_API(lzma_ret) lzma_stream_encoder_mt( + lzma_stream *strm, const lzma_mt *options) + lzma_nothrow lzma_attr_warn_unused_result; + + /** * \brief Initialize .lzma encoder (legacy file format) * @@ -269,7 +438,8 @@ extern LZMA_API(size_t) lzma_stream_buffer_bound(size_t uncompressed_size) */ extern LZMA_API(lzma_ret) lzma_stream_buffer_encode( lzma_filter *filters, lzma_check check, - lzma_allocator *allocator, const uint8_t *in, size_t in_size, + const lzma_allocator *allocator, + const uint8_t *in, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow lzma_attr_warn_unused_result; @@ -304,6 +474,30 @@ extern LZMA_API(lzma_ret) lzma_stream_buffer_encode( #define LZMA_TELL_ANY_CHECK UINT32_C(0x04) +/** + * This flag makes lzma_code() not calculate and verify the integrity check + * of the compressed data in .xz files. This means that invalid integrity + * check values won't be detected and LZMA_DATA_ERROR won't be returned in + * such cases. + * + * This flag only affects the checks of the compressed data itself; the CRC32 + * values in the .xz headers will still be verified normally. + * + * Don't use this flag unless you know what you are doing. Possible reasons + * to use this flag: + * + * - Trying to recover data from a corrupt .xz file. + * + * - Speeding up decompression, which matters mostly with SHA-256 + * or with files that have compressed extremely well. It's recommended + * to not use this flag for this purpose unless the file integrity is + * verified externally in some other way. + * + * Support for this flag was added in liblzma 5.1.4beta. + */ +#define LZMA_IGNORE_CHECK UINT32_C(0x10) + + /** * This flag enables decoding of concatenated files with file formats that * allow concatenating compressed files as is. From the formats currently @@ -418,7 +612,8 @@ extern LZMA_API(lzma_ret) lzma_alone_decoder( * - LZMA_PROG_ERROR */ extern LZMA_API(lzma_ret) lzma_stream_buffer_decode( - uint64_t *memlimit, uint32_t flags, lzma_allocator *allocator, + uint64_t *memlimit, uint32_t flags, + const lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow lzma_attr_warn_unused_result; diff --git a/src/liblzma/api/lzma/filter.h b/src/liblzma/api/lzma/filter.h index e0bc163ad35a..4e78752b8f79 100644 --- a/src/liblzma/api/lzma/filter.h +++ b/src/liblzma/api/lzma/filter.h @@ -116,8 +116,9 @@ extern LZMA_API(lzma_bool) lzma_filter_decoder_is_supported(lzma_vli id) * is not NULL. * - LZMA_PROG_ERROR: src or dest is NULL. */ -extern LZMA_API(lzma_ret) lzma_filters_copy(const lzma_filter *src, - lzma_filter *dest, lzma_allocator *allocator) lzma_nothrow; +extern LZMA_API(lzma_ret) lzma_filters_copy( + const lzma_filter *src, lzma_filter *dest, + const lzma_allocator *allocator) lzma_nothrow; /** @@ -256,7 +257,7 @@ extern LZMA_API(lzma_ret) lzma_filters_update( * won't necessarily meet that bound.) */ extern LZMA_API(lzma_ret) lzma_raw_buffer_encode( - const lzma_filter *filters, lzma_allocator *allocator, + const lzma_filter *filters, const lzma_allocator *allocator, const uint8_t *in, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow; @@ -280,7 +281,7 @@ extern LZMA_API(lzma_ret) lzma_raw_buffer_encode( * which no data is written to is out[out_size]. */ extern LZMA_API(lzma_ret) lzma_raw_buffer_decode( - const lzma_filter *filters, lzma_allocator *allocator, + const lzma_filter *filters, const lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow; @@ -356,7 +357,7 @@ extern LZMA_API(lzma_ret) lzma_properties_encode( * - LZMA_MEM_ERROR */ extern LZMA_API(lzma_ret) lzma_properties_decode( - lzma_filter *filter, lzma_allocator *allocator, + lzma_filter *filter, const lzma_allocator *allocator, const uint8_t *props, size_t props_size) lzma_nothrow; @@ -419,6 +420,6 @@ extern LZMA_API(lzma_ret) lzma_filter_flags_encode(const lzma_filter *filter, * - LZMA_PROG_ERROR */ extern LZMA_API(lzma_ret) lzma_filter_flags_decode( - lzma_filter *filter, lzma_allocator *allocator, + lzma_filter *filter, const lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size) lzma_nothrow lzma_attr_warn_unused_result; diff --git a/src/liblzma/api/lzma/hardware.h b/src/liblzma/api/lzma/hardware.h index e7dd03c3e8dd..5321d9af8e46 100644 --- a/src/liblzma/api/lzma/hardware.h +++ b/src/liblzma/api/lzma/hardware.h @@ -48,3 +48,17 @@ * of RAM on the specific operating system. */ extern LZMA_API(uint64_t) lzma_physmem(void) lzma_nothrow; + + +/** + * \brief Get the number of processor cores or threads + * + * This function may be useful when determining how many threads to use. + * If the hardware supports more than one thread per CPU core, the number + * of hardware threads is returned if that information is available. + * + * \brief On success, the number of available CPU threads or cores is + * returned. If this information isn't available or an error + * occurs, zero is returned. + */ +extern LZMA_API(uint32_t) lzma_cputhreads(void) lzma_nothrow; diff --git a/src/liblzma/api/lzma/index.h b/src/liblzma/api/lzma/index.h index 16bacc287dfc..dda60ec1c185 100644 --- a/src/liblzma/api/lzma/index.h +++ b/src/liblzma/api/lzma/index.h @@ -303,7 +303,7 @@ extern LZMA_API(uint64_t) lzma_index_memused(const lzma_index *i) * \return On success, a pointer to an empty initialized lzma_index is * returned. If allocation fails, NULL is returned. */ -extern LZMA_API(lzma_index *) lzma_index_init(lzma_allocator *allocator) +extern LZMA_API(lzma_index *) lzma_index_init(const lzma_allocator *allocator) lzma_nothrow; @@ -312,8 +312,8 @@ extern LZMA_API(lzma_index *) lzma_index_init(lzma_allocator *allocator) * * If i is NULL, this does nothing. */ -extern LZMA_API(void) lzma_index_end(lzma_index *i, lzma_allocator *allocator) - lzma_nothrow; +extern LZMA_API(void) lzma_index_end( + lzma_index *i, const lzma_allocator *allocator) lzma_nothrow; /** @@ -341,7 +341,7 @@ extern LZMA_API(void) lzma_index_end(lzma_index *i, lzma_allocator *allocator) * - LZMA_PROG_ERROR */ extern LZMA_API(lzma_ret) lzma_index_append( - lzma_index *i, lzma_allocator *allocator, + lzma_index *i, const lzma_allocator *allocator, lzma_vli unpadded_size, lzma_vli uncompressed_size) lzma_nothrow lzma_attr_warn_unused_result; @@ -564,8 +564,8 @@ extern LZMA_API(lzma_bool) lzma_index_iter_locate( * - LZMA_MEM_ERROR * - LZMA_PROG_ERROR */ -extern LZMA_API(lzma_ret) lzma_index_cat( - lzma_index *dest, lzma_index *src, lzma_allocator *allocator) +extern LZMA_API(lzma_ret) lzma_index_cat(lzma_index *dest, lzma_index *src, + const lzma_allocator *allocator) lzma_nothrow lzma_attr_warn_unused_result; @@ -575,7 +575,7 @@ extern LZMA_API(lzma_ret) lzma_index_cat( * \return A copy of the lzma_index, or NULL if memory allocation failed. */ extern LZMA_API(lzma_index *) lzma_index_dup( - const lzma_index *i, lzma_allocator *allocator) + const lzma_index *i, const lzma_allocator *allocator) lzma_nothrow lzma_attr_warn_unused_result; @@ -677,6 +677,6 @@ extern LZMA_API(lzma_ret) lzma_index_buffer_encode(const lzma_index *i, * - LZMA_PROG_ERROR */ extern LZMA_API(lzma_ret) lzma_index_buffer_decode(lzma_index **i, - uint64_t *memlimit, lzma_allocator *allocator, + uint64_t *memlimit, const lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size) lzma_nothrow; diff --git a/src/liblzma/api/lzma/index_hash.h b/src/liblzma/api/lzma/index_hash.h index fa2e048d552d..9287f1dfdb56 100644 --- a/src/liblzma/api/lzma/index_hash.h +++ b/src/liblzma/api/lzma/index_hash.h @@ -37,7 +37,7 @@ typedef struct lzma_index_hash_s lzma_index_hash; * pointer than the index_hash that was given as an argument. */ extern LZMA_API(lzma_index_hash *) lzma_index_hash_init( - lzma_index_hash *index_hash, lzma_allocator *allocator) + lzma_index_hash *index_hash, const lzma_allocator *allocator) lzma_nothrow lzma_attr_warn_unused_result; @@ -45,7 +45,7 @@ extern LZMA_API(lzma_index_hash *) lzma_index_hash_init( * \brief Deallocate lzma_index_hash structure */ extern LZMA_API(void) lzma_index_hash_end( - lzma_index_hash *index_hash, lzma_allocator *allocator) + lzma_index_hash *index_hash, const lzma_allocator *allocator) lzma_nothrow; diff --git a/src/liblzma/api/lzma/lzma.h b/src/liblzma/api/lzma/lzma12.h similarity index 99% rename from src/liblzma/api/lzma/lzma.h rename to src/liblzma/api/lzma/lzma12.h index 3f8e095f70e8..4e32fa3a214a 100644 --- a/src/liblzma/api/lzma/lzma.h +++ b/src/liblzma/api/lzma/lzma12.h @@ -1,5 +1,5 @@ /** - * \file lzma/lzma.h + * \file lzma/lzma12.h * \brief LZMA1 and LZMA2 filters */ diff --git a/src/liblzma/api/lzma/version.h b/src/liblzma/api/lzma/version.h index beec18e20440..d9614da76f7b 100644 --- a/src/liblzma/api/lzma/version.h +++ b/src/liblzma/api/lzma/version.h @@ -21,8 +21,8 @@ * Version number split into components */ #define LZMA_VERSION_MAJOR 5 -#define LZMA_VERSION_MINOR 0 -#define LZMA_VERSION_PATCH 7 +#define LZMA_VERSION_MINOR 2 +#define LZMA_VERSION_PATCH 0 #define LZMA_VERSION_STABILITY LZMA_VERSION_STABILITY_STABLE #ifndef LZMA_VERSION_COMMIT diff --git a/src/liblzma/check/check.h b/src/liblzma/check/check.h index e100d2b85303..0f96f65b360c 100644 --- a/src/liblzma/check/check.h +++ b/src/liblzma/check/check.h @@ -15,6 +15,43 @@ #include "common.h" +#if defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H) +# include +#elif defined(HAVE_SHA256_H) +# include +# include +#elif defined(HAVE_SHA2_H) +# include +# include +#elif defined(HAVE_MINIX_SHA2_H) +# include +# include +#endif + +#if defined(HAVE_CC_SHA256_CTX) +typedef CC_SHA256_CTX lzma_sha256_state; +#elif defined(HAVE_SHA256_CTX) +typedef SHA256_CTX lzma_sha256_state; +#elif defined(HAVE_SHA2_CTX) +typedef SHA2_CTX lzma_sha256_state; +#else +/// State for the internal SHA-256 implementation +typedef struct { + /// Internal state + uint32_t state[8]; + + /// Size of the message excluding padding + uint64_t size; +} lzma_sha256_state; +#endif + +#if defined(HAVE_CC_SHA256_INIT) +# define LZMA_SHA256FUNC(x) CC_SHA256_ ## x +#elif defined(HAVE_SHA256_INIT) +# define LZMA_SHA256FUNC(x) SHA256_ ## x +#elif defined(HAVE_SHA256INIT) +# define LZMA_SHA256FUNC(x) SHA256 ## x +#endif // Index hashing needs the best possible hash function (preferably // a cryptographic hash) for maximum reliability. @@ -43,14 +80,7 @@ typedef struct { union { uint32_t crc32; uint64_t crc64; - - struct { - /// Internal state - uint32_t state[8]; - - /// Size of the message excluding padding - uint64_t size; - } sha256; + lzma_sha256_state sha256; } state; } lzma_check_state; @@ -82,6 +112,8 @@ extern void lzma_check_update(lzma_check_state *check, lzma_check type, extern void lzma_check_finish(lzma_check_state *check, lzma_check type); +#ifndef LZMA_SHA256FUNC + /// Prepare SHA-256 state for new input. extern void lzma_sha256_init(lzma_check_state *check); @@ -92,4 +124,39 @@ extern void lzma_sha256_update( /// Finish the SHA-256 calculation and store the result to check->buffer.u8. extern void lzma_sha256_finish(lzma_check_state *check); + +#else + +static inline void +lzma_sha256_init(lzma_check_state *check) +{ + LZMA_SHA256FUNC(Init)(&check->state.sha256); +} + + +static inline void +lzma_sha256_update(const uint8_t *buf, size_t size, lzma_check_state *check) +{ +#if defined(HAVE_CC_SHA256_INIT) && SIZE_MAX > UINT32_MAX + // Darwin's CC_SHA256_Update takes uint32_t as the buffer size, + // so use a loop to support size_t. + while (size > UINT32_MAX) { + LZMA_SHA256FUNC(Update)(&check->state.sha256, buf, UINT32_MAX); + buf += UINT32_MAX; + size -= UINT32_MAX; + } +#endif + + LZMA_SHA256FUNC(Update)(&check->state.sha256, buf, size); +} + + +static inline void +lzma_sha256_finish(lzma_check_state *check) +{ + LZMA_SHA256FUNC(Final)(check->buffer.u8, &check->state.sha256); +} + +#endif + #endif diff --git a/src/liblzma/check/sha256.c b/src/liblzma/check/sha256.c index f2cc0d71ac63..5eede5ce05bc 100644 --- a/src/liblzma/check/sha256.c +++ b/src/liblzma/check/sha256.c @@ -21,22 +21,22 @@ // /////////////////////////////////////////////////////////////////////////////// -// Avoid bogus warnings in transform(). -#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __GNUC__ > 4 -# pragma GCC diagnostic ignored "-Wuninitialized" -#endif - #include "check.h" -// At least on x86, GCC is able to optimize this to a rotate instruction. -#define rotr_32(num, amount) ((num) >> (amount) | (num) << (32 - (amount))) +// Rotate a uint32_t. GCC can optimize this to a rotate instruction +// at least on x86. +static inline uint32_t +rotr_32(uint32_t num, unsigned amount) +{ + return (num >> amount) | (num << (32 - amount)); +} -#define blk0(i) (W[i] = data[i]) +#define blk0(i) (W[i] = conv32be(data[i])) #define blk2(i) (W[i & 15] += s1(W[(i - 2) & 15]) + W[(i - 7) & 15] \ + s0(W[(i - 15) & 15])) #define Ch(x, y, z) (z ^ (x & (y ^ z))) -#define Maj(x, y, z) ((x & y) | (z & (x | y))) +#define Maj(x, y, z) ((x & (y ^ z)) + (y & z)) #define a(i) T[(0 - i) & 7] #define b(i) T[(1 - i) & 7] @@ -47,16 +47,17 @@ #define g(i) T[(6 - i) & 7] #define h(i) T[(7 - i) & 7] -#define R(i) \ - h(i) += S1(e(i)) + Ch(e(i), f(i), g(i)) + SHA256_K[i + j] \ - + (j ? blk2(i) : blk0(i)); \ +#define R(i, j, blk) \ + h(i) += S1(e(i)) + Ch(e(i), f(i), g(i)) + SHA256_K[i + j] + blk; \ d(i) += h(i); \ h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) +#define R0(i) R(i, 0, blk0(i)) +#define R2(i) R(i, j, blk2(i)) -#define S0(x) (rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22)) -#define S1(x) (rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25)) -#define s0(x) (rotr_32(x, 7) ^ rotr_32(x, 18) ^ (x >> 3)) -#define s1(x) (rotr_32(x, 17) ^ rotr_32(x, 19) ^ (x >> 10)) +#define S0(x) rotr_32(x ^ rotr_32(x ^ rotr_32(x, 9), 11), 2) +#define S1(x) rotr_32(x ^ rotr_32(x ^ rotr_32(x, 14), 5), 6) +#define s0(x) (rotr_32(x ^ rotr_32(x, 11), 7) ^ (x >> 3)) +#define s1(x) (rotr_32(x ^ rotr_32(x, 2), 17) ^ (x >> 10)) static const uint32_t SHA256_K[64] = { @@ -88,12 +89,18 @@ transform(uint32_t state[8], const uint32_t data[16]) // Copy state[] to working vars. memcpy(T, state, sizeof(T)); - // 64 operations, partially loop unrolled - for (unsigned int j = 0; j < 64; j += 16) { - R( 0); R( 1); R( 2); R( 3); - R( 4); R( 5); R( 6); R( 7); - R( 8); R( 9); R(10); R(11); - R(12); R(13); R(14); R(15); + // The first 16 operations unrolled + R0( 0); R0( 1); R0( 2); R0( 3); + R0( 4); R0( 5); R0( 6); R0( 7); + R0( 8); R0( 9); R0(10); R0(11); + R0(12); R0(13); R0(14); R0(15); + + // The remaining 48 operations partially unrolled + for (unsigned int j = 16; j < 64; j += 16) { + R2( 0); R2( 1); R2( 2); R2( 3); + R2( 4); R2( 5); R2( 6); R2( 7); + R2( 8); R2( 9); R2(10); R2(11); + R2(12); R2(13); R2(14); R2(15); } // Add the working vars back into state[]. @@ -111,18 +118,7 @@ transform(uint32_t state[8], const uint32_t data[16]) static void process(lzma_check_state *check) { -#ifdef WORDS_BIGENDIAN transform(check->state.sha256.state, check->buffer.u32); - -#else - uint32_t data[16]; - - for (size_t i = 0; i < 16; ++i) - data[i] = bswap32(check->buffer.u32[i]); - - transform(check->state.sha256.state, data); -#endif - return; } diff --git a/src/liblzma/common/alone_decoder.c b/src/liblzma/common/alone_decoder.c index c25112e6875f..c1360ca1eb7a 100644 --- a/src/liblzma/common/alone_decoder.c +++ b/src/liblzma/common/alone_decoder.c @@ -51,7 +51,7 @@ struct lzma_coder_s { static lzma_ret alone_decode(lzma_coder *coder, - lzma_allocator *allocator lzma_attribute((__unused__)), + const lzma_allocator *allocator lzma_attribute((__unused__)), const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, @@ -166,7 +166,7 @@ alone_decode(lzma_coder *coder, static void -alone_decoder_end(lzma_coder *coder, lzma_allocator *allocator) +alone_decoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); @@ -193,7 +193,7 @@ alone_decoder_memconfig(lzma_coder *coder, uint64_t *memusage, extern lzma_ret -lzma_alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_alone_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, uint64_t memlimit, bool picky) { lzma_next_coder_init(&lzma_alone_decoder_init, next, allocator); diff --git a/src/liblzma/common/alone_decoder.h b/src/liblzma/common/alone_decoder.h index f666fc3823e1..dfa031aa77dd 100644 --- a/src/liblzma/common/alone_decoder.h +++ b/src/liblzma/common/alone_decoder.h @@ -17,7 +17,7 @@ extern lzma_ret lzma_alone_decoder_init( - lzma_next_coder *next, lzma_allocator *allocator, + lzma_next_coder *next, const lzma_allocator *allocator, uint64_t memlimit, bool picky); #endif diff --git a/src/liblzma/common/alone_encoder.c b/src/liblzma/common/alone_encoder.c index eb1697e99753..a2bc9eee1fa9 100644 --- a/src/liblzma/common/alone_encoder.c +++ b/src/liblzma/common/alone_encoder.c @@ -32,7 +32,7 @@ struct lzma_coder_s { static lzma_ret alone_encode(lzma_coder *coder, - lzma_allocator *allocator lzma_attribute((__unused__)), + const lzma_allocator *allocator lzma_attribute((__unused__)), const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, @@ -65,7 +65,7 @@ alone_encode(lzma_coder *coder, static void -alone_encoder_end(lzma_coder *coder, lzma_allocator *allocator) +alone_encoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); @@ -75,7 +75,7 @@ alone_encoder_end(lzma_coder *coder, lzma_allocator *allocator) // At least for now, this is not used by any internal function. static lzma_ret -alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +alone_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_options_lzma *options) { lzma_next_coder_init(&alone_encoder_init, next, allocator); @@ -137,7 +137,7 @@ alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, /* extern lzma_ret -lzma_alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_alone_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_options_alone *options) { lzma_next_coder_init(&alone_encoder_init, next, allocator, options); diff --git a/src/liblzma/common/auto_decoder.c b/src/liblzma/common/auto_decoder.c index 35c895fd14c2..bf3550701fe6 100644 --- a/src/liblzma/common/auto_decoder.c +++ b/src/liblzma/common/auto_decoder.c @@ -30,7 +30,7 @@ struct lzma_coder_s { static lzma_ret -auto_decode(lzma_coder *coder, lzma_allocator *allocator, +auto_decode(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, lzma_action action) @@ -100,7 +100,7 @@ auto_decode(lzma_coder *coder, lzma_allocator *allocator, static void -auto_decoder_end(lzma_coder *coder, lzma_allocator *allocator) +auto_decoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); @@ -143,7 +143,7 @@ auto_decoder_memconfig(lzma_coder *coder, uint64_t *memusage, static lzma_ret -auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +auto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, uint64_t memlimit, uint32_t flags) { lzma_next_coder_init(&auto_decoder_init, next, allocator); diff --git a/src/liblzma/common/block_buffer_decoder.c b/src/liblzma/common/block_buffer_decoder.c index ff27a11ccfe6..b0ded90ddc3e 100644 --- a/src/liblzma/common/block_buffer_decoder.c +++ b/src/liblzma/common/block_buffer_decoder.c @@ -14,7 +14,7 @@ extern LZMA_API(lzma_ret) -lzma_block_buffer_decode(lzma_block *block, lzma_allocator *allocator, +lzma_block_buffer_decode(lzma_block *block, const lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) { diff --git a/src/liblzma/common/block_buffer_encoder.c b/src/liblzma/common/block_buffer_encoder.c index 519c6a684d76..39e263aa4765 100644 --- a/src/liblzma/common/block_buffer_encoder.c +++ b/src/liblzma/common/block_buffer_encoder.c @@ -10,6 +10,7 @@ // /////////////////////////////////////////////////////////////////////////////// +#include "block_buffer_encoder.h" #include "block_encoder.h" #include "filter_encoder.h" #include "lzma2_encoder.h" @@ -28,8 +29,8 @@ + LZMA_CHECK_SIZE_MAX + 3) & ~3) -static lzma_vli -lzma2_bound(lzma_vli uncompressed_size) +static uint64_t +lzma2_bound(uint64_t uncompressed_size) { // Prevent integer overflow in overhead calculation. if (uncompressed_size > COMPRESSED_SIZE_MAX) @@ -39,7 +40,7 @@ lzma2_bound(lzma_vli uncompressed_size) // uncompressed_size up to the next multiple of LZMA2_CHUNK_MAX, // multiply by the size of per-chunk header, and add one byte for // the end marker. - const lzma_vli overhead = ((uncompressed_size + LZMA2_CHUNK_MAX - 1) + const uint64_t overhead = ((uncompressed_size + LZMA2_CHUNK_MAX - 1) / LZMA2_CHUNK_MAX) * LZMA2_HEADER_UNCOMPRESSED + 1; @@ -51,30 +52,36 @@ lzma2_bound(lzma_vli uncompressed_size) } -extern LZMA_API(size_t) -lzma_block_buffer_bound(size_t uncompressed_size) +extern uint64_t +lzma_block_buffer_bound64(uint64_t uncompressed_size) { - // For now, if the data doesn't compress, we always use uncompressed - // chunks of LZMA2. In future we may use Subblock filter too, but - // but for simplicity we probably will still use the same bound - // calculation even though Subblock filter would have slightly less - // overhead. - lzma_vli lzma2_size = lzma2_bound(uncompressed_size); + // If the data doesn't compress, we always use uncompressed + // LZMA2 chunks. + uint64_t lzma2_size = lzma2_bound(uncompressed_size); if (lzma2_size == 0) return 0; // Take Block Padding into account. - lzma2_size = (lzma2_size + 3) & ~LZMA_VLI_C(3); + lzma2_size = (lzma2_size + 3) & ~UINT64_C(3); -#if SIZE_MAX < LZMA_VLI_MAX - // Catch the possible integer overflow on 32-bit systems. There's no - // overflow on 64-bit systems, because lzma2_bound() already takes + // No risk of integer overflow because lzma2_bound() already takes // into account the size of the headers in the Block. - if (SIZE_MAX - HEADERS_BOUND < lzma2_size) + return HEADERS_BOUND + lzma2_size; +} + + +extern LZMA_API(size_t) +lzma_block_buffer_bound(size_t uncompressed_size) +{ + uint64_t ret = lzma_block_buffer_bound64(uncompressed_size); + +#if SIZE_MAX < UINT64_MAX + // Catch the possible integer overflow on 32-bit systems. + if (ret > SIZE_MAX) return 0; #endif - return HEADERS_BOUND + lzma2_size; + return ret; } @@ -82,9 +89,6 @@ static lzma_ret block_encode_uncompressed(lzma_block *block, const uint8_t *in, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) { - // TODO: Figure out if the last filter is LZMA2 or Subblock and use - // that filter to encode the uncompressed chunks. - // Use LZMA2 uncompressed chunks. We wouldn't need a dictionary at // all, but LZMA2 always requires a dictionary, so use the minimum // value to minimize memory usage of the decoder. @@ -160,16 +164,11 @@ block_encode_uncompressed(lzma_block *block, const uint8_t *in, size_t in_size, static lzma_ret -block_encode_normal(lzma_block *block, lzma_allocator *allocator, +block_encode_normal(lzma_block *block, const lzma_allocator *allocator, const uint8_t *in, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) { // Find out the size of the Block Header. - block->compressed_size = lzma2_bound(in_size); - if (block->compressed_size == 0) - return LZMA_DATA_ERROR; - - block->uncompressed_size = in_size; return_if_error(lzma_block_header_size(block)); // Reserve space for the Block Header and skip it for now. @@ -221,10 +220,11 @@ block_encode_normal(lzma_block *block, lzma_allocator *allocator, } -extern LZMA_API(lzma_ret) -lzma_block_buffer_encode(lzma_block *block, lzma_allocator *allocator, +static lzma_ret +block_buffer_encode(lzma_block *block, const lzma_allocator *allocator, const uint8_t *in, size_t in_size, - uint8_t *out, size_t *out_pos, size_t out_size) + uint8_t *out, size_t *out_pos, size_t out_size, + bool try_to_compress) { // Validate the arguments. if (block == NULL || (in == NULL && in_size != 0) || out == NULL @@ -233,11 +233,11 @@ lzma_block_buffer_encode(lzma_block *block, lzma_allocator *allocator, // The contents of the structure may depend on the version so // check the version before validating the contents of *block. - if (block->version != 0) + if (block->version > 1) return LZMA_OPTIONS_ERROR; if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX - || block->filters == NULL) + || (try_to_compress && block->filters == NULL)) return LZMA_PROG_ERROR; if (!lzma_check_is_supported(block->check)) @@ -258,9 +258,19 @@ lzma_block_buffer_encode(lzma_block *block, lzma_allocator *allocator, out_size -= check_size; + // Initialize block->uncompressed_size and calculate the worst-case + // value for block->compressed_size. + block->uncompressed_size = in_size; + block->compressed_size = lzma2_bound(in_size); + if (block->compressed_size == 0) + return LZMA_DATA_ERROR; + // Do the actual compression. - const lzma_ret ret = block_encode_normal(block, allocator, - in, in_size, out, out_pos, out_size); + lzma_ret ret = LZMA_BUF_ERROR; + if (try_to_compress) + ret = block_encode_normal(block, allocator, + in, in_size, out, out_pos, out_size); + if (ret != LZMA_OK) { // If the error was something else than output buffer // becoming full, return the error now. @@ -303,3 +313,25 @@ lzma_block_buffer_encode(lzma_block *block, lzma_allocator *allocator, return LZMA_OK; } + + +extern LZMA_API(lzma_ret) +lzma_block_buffer_encode(lzma_block *block, const lzma_allocator *allocator, + const uint8_t *in, size_t in_size, + uint8_t *out, size_t *out_pos, size_t out_size) +{ + return block_buffer_encode(block, allocator, + in, in_size, out, out_pos, out_size, true); +} + + +extern LZMA_API(lzma_ret) +lzma_block_uncomp_encode(lzma_block *block, + const uint8_t *in, size_t in_size, + uint8_t *out, size_t *out_pos, size_t out_size) +{ + // It won't allocate any memory from heap so no need + // for lzma_allocator. + return block_buffer_encode(block, NULL, + in, in_size, out, out_pos, out_size, false); +} diff --git a/src/liblzma/common/block_buffer_encoder.h b/src/liblzma/common/block_buffer_encoder.h new file mode 100644 index 000000000000..653207f73498 --- /dev/null +++ b/src/liblzma/common/block_buffer_encoder.h @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file block_buffer_encoder.h +/// \brief Single-call .xz Block encoder +// +// Author: Lasse Collin +// +// This file has been put into the public domain. +// You can do whatever you want with this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef LZMA_BLOCK_BUFFER_ENCODER_H +#define LZMA_BLOCK_BUFFER_ENCODER_H + +#include "common.h" + + +/// uint64_t version of lzma_block_buffer_bound(). It is used by +/// stream_encoder_mt.c. Probably the original lzma_block_buffer_bound() +/// should have been 64-bit, but fixing it would break the ABI. +extern uint64_t lzma_block_buffer_bound64(uint64_t uncompressed_size); + +#endif diff --git a/src/liblzma/common/block_decoder.c b/src/liblzma/common/block_decoder.c index a3ce6f49500c..685c3b038fc3 100644 --- a/src/liblzma/common/block_decoder.c +++ b/src/liblzma/common/block_decoder.c @@ -45,6 +45,9 @@ struct lzma_coder_s { /// Check of the uncompressed data lzma_check_state check; + + /// True if the integrity check won't be calculated and verified. + bool ignore_check; }; @@ -71,7 +74,7 @@ is_size_valid(lzma_vli size, lzma_vli reference) static lzma_ret -block_decode(lzma_coder *coder, lzma_allocator *allocator, +block_decode(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, lzma_action action) @@ -97,8 +100,9 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator, coder->block->uncompressed_size)) return LZMA_DATA_ERROR; - lzma_check_update(&coder->check, coder->block->check, - out + out_start, out_used); + if (!coder->ignore_check) + lzma_check_update(&coder->check, coder->block->check, + out + out_start, out_used); if (ret != LZMA_STREAM_END) return ret; @@ -140,7 +144,9 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator, if (coder->block->check == LZMA_CHECK_NONE) return LZMA_STREAM_END; - lzma_check_finish(&coder->check, coder->block->check); + if (!coder->ignore_check) + lzma_check_finish(&coder->check, coder->block->check); + coder->sequence = SEQ_CHECK; // Fall through @@ -155,7 +161,8 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator, // Validate the Check only if we support it. // coder->check.buffer may be uninitialized // when the Check ID is not supported. - if (lzma_check_is_supported(coder->block->check) + if (!coder->ignore_check + && lzma_check_is_supported(coder->block->check) && memcmp(coder->block->raw_check, coder->check.buffer.u8, check_size) != 0) @@ -170,7 +177,7 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator, static void -block_decoder_end(lzma_coder *coder, lzma_allocator *allocator) +block_decoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); @@ -179,7 +186,7 @@ block_decoder_end(lzma_coder *coder, lzma_allocator *allocator) extern lzma_ret -lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, lzma_block *block) { lzma_next_coder_init(&lzma_block_decoder_init, next, allocator); @@ -224,6 +231,9 @@ lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, next->coder->check_pos = 0; lzma_check_init(&next->coder->check, block->check); + next->coder->ignore_check = block->version >= 1 + ? block->ignore_check : false; + // Initialize the filter chain. return lzma_raw_decoder_init(&next->coder->next, allocator, block->filters); diff --git a/src/liblzma/common/block_decoder.h b/src/liblzma/common/block_decoder.h index 7da9df63f767..718c5ced886c 100644 --- a/src/liblzma/common/block_decoder.h +++ b/src/liblzma/common/block_decoder.h @@ -17,6 +17,6 @@ extern lzma_ret lzma_block_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, lzma_block *block); + const lzma_allocator *allocator, lzma_block *block); #endif diff --git a/src/liblzma/common/block_encoder.c b/src/liblzma/common/block_encoder.c index 1eeb502b7f83..def586410d28 100644 --- a/src/liblzma/common/block_encoder.c +++ b/src/liblzma/common/block_encoder.c @@ -45,7 +45,7 @@ struct lzma_coder_s { static lzma_ret -block_encode(lzma_coder *coder, lzma_allocator *allocator, +block_encode(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, lzma_action action) @@ -134,7 +134,7 @@ block_encode(lzma_coder *coder, lzma_allocator *allocator, static void -block_encoder_end(lzma_coder *coder, lzma_allocator *allocator) +block_encoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); @@ -143,7 +143,7 @@ block_encoder_end(lzma_coder *coder, lzma_allocator *allocator) static lzma_ret -block_encoder_update(lzma_coder *coder, lzma_allocator *allocator, +block_encoder_update(lzma_coder *coder, const lzma_allocator *allocator, const lzma_filter *filters lzma_attribute((__unused__)), const lzma_filter *reversed_filters) { @@ -156,7 +156,7 @@ block_encoder_update(lzma_coder *coder, lzma_allocator *allocator, extern lzma_ret -lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_block_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, lzma_block *block) { lzma_next_coder_init(&lzma_block_encoder_init, next, allocator); @@ -166,7 +166,7 @@ lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, // The contents of the structure may depend on the version so // check the version first. - if (block->version != 0) + if (block->version > 1) return LZMA_OPTIONS_ERROR; // If the Check ID is not supported, we cannot calculate the check and diff --git a/src/liblzma/common/block_encoder.h b/src/liblzma/common/block_encoder.h index b9eff0be2736..bd97c186e503 100644 --- a/src/liblzma/common/block_encoder.h +++ b/src/liblzma/common/block_encoder.h @@ -42,6 +42,6 @@ extern lzma_ret lzma_block_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, lzma_block *block); + const lzma_allocator *allocator, lzma_block *block); #endif diff --git a/src/liblzma/common/block_header_decoder.c b/src/liblzma/common/block_header_decoder.c index 2c9573ee204c..1dd982f6bd68 100644 --- a/src/liblzma/common/block_header_decoder.c +++ b/src/liblzma/common/block_header_decoder.c @@ -15,7 +15,7 @@ static void -free_properties(lzma_block *block, lzma_allocator *allocator) +free_properties(lzma_block *block, const lzma_allocator *allocator) { // Free allocated filter options. The last array member is not // touched after the initialization in the beginning of @@ -32,7 +32,7 @@ free_properties(lzma_block *block, lzma_allocator *allocator) extern LZMA_API(lzma_ret) lzma_block_header_decode(lzma_block *block, - lzma_allocator *allocator, const uint8_t *in) + const lzma_allocator *allocator, const uint8_t *in) { // NOTE: We consider the header to be corrupt not only when the // CRC32 doesn't match, but also when variable-length integers @@ -46,8 +46,16 @@ lzma_block_header_decode(lzma_block *block, block->filters[i].options = NULL; } - // Always zero for now. - block->version = 0; + // Versions 0 and 1 are supported. If a newer version was specified, + // we need to downgrade it. + if (block->version > 1) + block->version = 1; + + // This isn't a Block Header option, but since the decompressor will + // read it if version >= 1, it's better to initialize it here than + // to expect the caller to do it since in almost all cases this + // should be false. + block->ignore_check = false; // Validate Block Header Size and Check type. The caller must have // already set these, so it is a programming error if this test fails. diff --git a/src/liblzma/common/block_header_encoder.c b/src/liblzma/common/block_header_encoder.c index 707dd0cb14a2..5c5f5424ae85 100644 --- a/src/liblzma/common/block_header_encoder.c +++ b/src/liblzma/common/block_header_encoder.c @@ -17,7 +17,7 @@ extern LZMA_API(lzma_ret) lzma_block_header_size(lzma_block *block) { - if (block->version != 0) + if (block->version > 1) return LZMA_OPTIONS_ERROR; // Block Header Size + Block Flags + CRC32. diff --git a/src/liblzma/common/block_util.c b/src/liblzma/common/block_util.c index 62c934547c9e..00c7fe8d5196 100644 --- a/src/liblzma/common/block_util.c +++ b/src/liblzma/common/block_util.c @@ -51,7 +51,7 @@ lzma_block_unpadded_size(const lzma_block *block) // NOTE: This function is used for validation too, so it is // essential that these checks are always done even if // Compressed Size is unknown. - if (block == NULL || block->version != 0 + if (block == NULL || block->version > 1 || block->header_size < LZMA_BLOCK_HEADER_SIZE_MIN || block->header_size > LZMA_BLOCK_HEADER_SIZE_MAX || (block->header_size & 3) diff --git a/src/liblzma/common/common.c b/src/liblzma/common/common.c index b9e386027368..28aa2b7142f4 100644 --- a/src/liblzma/common/common.c +++ b/src/liblzma/common/common.c @@ -36,7 +36,7 @@ lzma_version_string(void) /////////////////////// extern void * lzma_attribute((__malloc__)) lzma_attr_alloc_size(1) -lzma_alloc(size_t size, lzma_allocator *allocator) +lzma_alloc(size_t size, const lzma_allocator *allocator) { // Some malloc() variants return NULL if called with size == 0. if (size == 0) @@ -53,8 +53,29 @@ lzma_alloc(size_t size, lzma_allocator *allocator) } +extern void * lzma_attribute((__malloc__)) lzma_attr_alloc_size(1) +lzma_alloc_zero(size_t size, const lzma_allocator *allocator) +{ + // Some calloc() variants return NULL if called with size == 0. + if (size == 0) + size = 1; + + void *ptr; + + if (allocator != NULL && allocator->alloc != NULL) { + ptr = allocator->alloc(allocator->opaque, 1, size); + if (ptr != NULL) + memzero(ptr, size); + } else { + ptr = calloc(1, size); + } + + return ptr; +} + + extern void -lzma_free(void *ptr, lzma_allocator *allocator) +lzma_free(void *ptr, const lzma_allocator *allocator) { if (allocator != NULL && allocator->free != NULL) allocator->free(allocator->opaque, ptr); @@ -88,7 +109,7 @@ lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos, extern lzma_ret -lzma_next_filter_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_next_filter_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters) { lzma_next_coder_init(filters[0].init, next, allocator); @@ -99,7 +120,7 @@ lzma_next_filter_init(lzma_next_coder *next, lzma_allocator *allocator, extern lzma_ret -lzma_next_filter_update(lzma_next_coder *next, lzma_allocator *allocator, +lzma_next_filter_update(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *reversed_filters) { // Check that the application isn't trying to change the Filter ID. @@ -117,7 +138,7 @@ lzma_next_filter_update(lzma_next_coder *next, lzma_allocator *allocator, extern void -lzma_next_end(lzma_next_coder *next, lzma_allocator *allocator) +lzma_next_end(lzma_next_coder *next, const lzma_allocator *allocator) { if (next->init != (uintptr_t)(NULL)) { // To avoid tiny end functions that simply call @@ -156,10 +177,8 @@ lzma_strm_init(lzma_stream *strm) strm->internal->next = LZMA_NEXT_CODER_INIT; } - strm->internal->supported_actions[LZMA_RUN] = false; - strm->internal->supported_actions[LZMA_SYNC_FLUSH] = false; - strm->internal->supported_actions[LZMA_FULL_FLUSH] = false; - strm->internal->supported_actions[LZMA_FINISH] = false; + memzero(strm->internal->supported_actions, + sizeof(strm->internal->supported_actions)); strm->internal->sequence = ISEQ_RUN; strm->internal->allow_buf_error = false; @@ -178,7 +197,7 @@ lzma_code(lzma_stream *strm, lzma_action action) || (strm->next_out == NULL && strm->avail_out != 0) || strm->internal == NULL || strm->internal->next.code == NULL - || (unsigned int)(action) > LZMA_FINISH + || (unsigned int)(action) > LZMA_ACTION_MAX || !strm->internal->supported_actions[action]) return LZMA_PROG_ERROR; @@ -213,6 +232,10 @@ lzma_code(lzma_stream *strm, lzma_action action) case LZMA_FINISH: strm->internal->sequence = ISEQ_FINISH; break; + + case LZMA_FULL_BARRIER: + strm->internal->sequence = ISEQ_FULL_BARRIER; + break; } break; @@ -240,6 +263,13 @@ lzma_code(lzma_stream *strm, lzma_action action) break; + case ISEQ_FULL_BARRIER: + if (action != LZMA_FULL_BARRIER + || strm->internal->avail_in != strm->avail_in) + return LZMA_PROG_ERROR; + + break; + case ISEQ_END: return LZMA_STREAM_END; @@ -265,7 +295,9 @@ lzma_code(lzma_stream *strm, lzma_action action) strm->internal->avail_in = strm->avail_in; - switch (ret) { + // Cast is needed to silence a warning about LZMA_TIMED_OUT, which + // isn't part of lzma_ret enumeration. + switch ((unsigned int)(ret)) { case LZMA_OK: // Don't return LZMA_BUF_ERROR when it happens the first time. // This is to avoid returning LZMA_BUF_ERROR when avail_out @@ -281,9 +313,16 @@ lzma_code(lzma_stream *strm, lzma_action action) } break; + case LZMA_TIMED_OUT: + strm->internal->allow_buf_error = false; + ret = LZMA_OK; + break; + case LZMA_STREAM_END: if (strm->internal->sequence == ISEQ_SYNC_FLUSH - || strm->internal->sequence == ISEQ_FULL_FLUSH) + || strm->internal->sequence == ISEQ_FULL_FLUSH + || strm->internal->sequence + == ISEQ_FULL_BARRIER) strm->internal->sequence = ISEQ_RUN; else strm->internal->sequence = ISEQ_END; @@ -323,6 +362,22 @@ lzma_end(lzma_stream *strm) } +extern LZMA_API(void) +lzma_get_progress(lzma_stream *strm, + uint64_t *progress_in, uint64_t *progress_out) +{ + if (strm->internal->next.get_progress != NULL) { + strm->internal->next.get_progress(strm->internal->next.coder, + progress_in, progress_out); + } else { + *progress_in = strm->total_in; + *progress_out = strm->total_out; + } + + return; +} + + extern LZMA_API(lzma_check) lzma_get_check(const lzma_stream *strm) { diff --git a/src/liblzma/common/common.h b/src/liblzma/common/common.h index 45aba4f06b27..955d784a5b6a 100644 --- a/src/liblzma/common/common.h +++ b/src/liblzma/common/common.h @@ -49,6 +49,13 @@ #define LZMA_BUFFER_SIZE 4096 +/// Maximum number of worker threads within one multithreaded component. +/// The limit exists solely to make it simpler to prevent integer overflows +/// when allocating structures etc. This should be big enough for now... +/// the code won't scale anywhere close to this number anyway. +#define LZMA_THREADS_MAX 16384 + + /// Starting value for memory usage estimates. Instead of calculating size /// of _every_ structure and taking into account malloc() overhead etc., we /// add a base size to all memory usage estimates. It's not very accurate @@ -66,9 +73,21 @@ ( LZMA_TELL_NO_CHECK \ | LZMA_TELL_UNSUPPORTED_CHECK \ | LZMA_TELL_ANY_CHECK \ + | LZMA_IGNORE_CHECK \ | LZMA_CONCATENATED ) +/// Largest valid lzma_action value as unsigned integer. +#define LZMA_ACTION_MAX ((unsigned int)(LZMA_FULL_BARRIER)) + + +/// Special return value (lzma_ret) to indicate that a timeout was reached +/// and lzma_code() must not return LZMA_BUF_ERROR. This is converted to +/// LZMA_OK in lzma_code(). This is not in the lzma_ret enumeration because +/// there's no need to have it in the public API. +#define LZMA_TIMED_OUT 32 + + /// Type of encoder/decoder specific data; the actual structure is defined /// differently in different coders. typedef struct lzma_coder_s lzma_coder; @@ -80,7 +99,7 @@ typedef struct lzma_filter_info_s lzma_filter_info; /// Type of a function used to initialize a filter encoder or decoder typedef lzma_ret (*lzma_init_function)( - lzma_next_coder *next, lzma_allocator *allocator, + lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters); /// Type of a function to do some kind of coding work (filters, Stream, @@ -88,7 +107,7 @@ typedef lzma_ret (*lzma_init_function)( /// input and output buffers, but for simplicity they still use this same /// function prototype. typedef lzma_ret (*lzma_code_function)( - lzma_coder *coder, lzma_allocator *allocator, + lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, @@ -96,7 +115,7 @@ typedef lzma_ret (*lzma_code_function)( /// Type of a function to free the memory allocated for the coder typedef void (*lzma_end_function)( - lzma_coder *coder, lzma_allocator *allocator); + lzma_coder *coder, const lzma_allocator *allocator); /// Raw coder validates and converts an array of lzma_filter structures to @@ -139,6 +158,11 @@ struct lzma_next_coder_s { /// lzma_next_coder.coder. lzma_end_function end; + /// Pointer to a function to get progress information. If this is NULL, + /// lzma_stream.total_in and .total_out are used instead. + void (*get_progress)(lzma_coder *coder, + uint64_t *progress_in, uint64_t *progress_out); + /// Pointer to function to return the type of the integrity check. /// Most coders won't support this. lzma_check (*get_check)(const lzma_coder *coder); @@ -150,7 +174,7 @@ struct lzma_next_coder_s { /// Update the filter-specific options or the whole filter chain /// in the encoder. - lzma_ret (*update)(lzma_coder *coder, lzma_allocator *allocator, + lzma_ret (*update)(lzma_coder *coder, const lzma_allocator *allocator, const lzma_filter *filters, const lzma_filter *reversed_filters); }; @@ -164,6 +188,7 @@ struct lzma_next_coder_s { .id = LZMA_VLI_UNKNOWN, \ .code = NULL, \ .end = NULL, \ + .get_progress = NULL, \ .get_check = NULL, \ .memconfig = NULL, \ .update = NULL, \ @@ -185,6 +210,7 @@ struct lzma_internal_s { ISEQ_SYNC_FLUSH, ISEQ_FULL_FLUSH, ISEQ_FINISH, + ISEQ_FULL_BARRIER, ISEQ_END, ISEQ_ERROR, } sequence; @@ -195,7 +221,7 @@ struct lzma_internal_s { size_t avail_in; /// Indicates which lzma_action values are allowed by next.code. - bool supported_actions[4]; + bool supported_actions[LZMA_ACTION_MAX + 1]; /// If true, lzma_code will return LZMA_BUF_ERROR if no progress was /// made (no input consumed and no output produced by next.code). @@ -204,11 +230,17 @@ struct lzma_internal_s { /// Allocates memory -extern void *lzma_alloc(size_t size, lzma_allocator *allocator) +extern void *lzma_alloc(size_t size, const lzma_allocator *allocator) lzma_attribute((__malloc__)) lzma_attr_alloc_size(1); +/// Allocates memory and zeroes it (like calloc()). This can be faster +/// than lzma_alloc() + memzero() while being backward compatible with +/// custom allocators. +extern void * lzma_attribute((__malloc__)) lzma_attr_alloc_size(1) + lzma_alloc_zero(size_t size, const lzma_allocator *allocator); + /// Frees memory -extern void lzma_free(void *ptr, lzma_allocator *allocator); +extern void lzma_free(void *ptr, const lzma_allocator *allocator); /// Allocates strm->internal if it is NULL, and initializes *strm and @@ -220,17 +252,19 @@ extern lzma_ret lzma_strm_init(lzma_stream *strm); /// than the filter being initialized now. This way the actual filter /// initialization functions don't need to use lzma_next_coder_init macro. extern lzma_ret lzma_next_filter_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); /// Update the next filter in the chain, if any. This checks that /// the application is not trying to change the Filter IDs. extern lzma_ret lzma_next_filter_update( - lzma_next_coder *next, lzma_allocator *allocator, + lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *reversed_filters); /// Frees the memory allocated for next->coder either using next->end or, /// if next->end is NULL, using lzma_free. -extern void lzma_next_end(lzma_next_coder *next, lzma_allocator *allocator); +extern void lzma_next_end(lzma_next_coder *next, + const lzma_allocator *allocator); /// Copy as much data as possible from in[] to out[] and update *in_pos diff --git a/src/liblzma/common/easy_buffer_encoder.c b/src/liblzma/common/easy_buffer_encoder.c index c4be34ccfa27..48eb56f5cc91 100644 --- a/src/liblzma/common/easy_buffer_encoder.c +++ b/src/liblzma/common/easy_buffer_encoder.c @@ -15,8 +15,8 @@ extern LZMA_API(lzma_ret) lzma_easy_buffer_encode(uint32_t preset, lzma_check check, - lzma_allocator *allocator, const uint8_t *in, size_t in_size, - uint8_t *out, size_t *out_pos, size_t out_size) + const lzma_allocator *allocator, const uint8_t *in, + size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) { lzma_options_easy opt_easy; if (lzma_easy_preset(&opt_easy, preset)) diff --git a/src/liblzma/common/easy_encoder.c b/src/liblzma/common/easy_encoder.c index d13ccd7351f1..5cb492dd0681 100644 --- a/src/liblzma/common/easy_encoder.c +++ b/src/liblzma/common/easy_encoder.c @@ -11,7 +11,6 @@ /////////////////////////////////////////////////////////////////////////////// #include "easy_preset.h" -#include "stream_encoder.h" extern LZMA_API(lzma_ret) diff --git a/src/liblzma/common/filter_buffer_decoder.c b/src/liblzma/common/filter_buffer_decoder.c index 2d35ef8e0af4..6620986eea8a 100644 --- a/src/liblzma/common/filter_buffer_decoder.c +++ b/src/liblzma/common/filter_buffer_decoder.c @@ -14,7 +14,8 @@ extern LZMA_API(lzma_ret) -lzma_raw_buffer_decode(const lzma_filter *filters, lzma_allocator *allocator, +lzma_raw_buffer_decode( + const lzma_filter *filters, const lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) { diff --git a/src/liblzma/common/filter_buffer_encoder.c b/src/liblzma/common/filter_buffer_encoder.c index 646e1b30374e..dda18e3d8e5e 100644 --- a/src/liblzma/common/filter_buffer_encoder.c +++ b/src/liblzma/common/filter_buffer_encoder.c @@ -14,9 +14,10 @@ extern LZMA_API(lzma_ret) -lzma_raw_buffer_encode(const lzma_filter *filters, lzma_allocator *allocator, - const uint8_t *in, size_t in_size, uint8_t *out, - size_t *out_pos, size_t out_size) +lzma_raw_buffer_encode( + const lzma_filter *filters, const lzma_allocator *allocator, + const uint8_t *in, size_t in_size, + uint8_t *out, size_t *out_pos, size_t out_size) { // Validate what isn't validated later in filter_common.c. if ((in == NULL && in_size != 0) || out == NULL diff --git a/src/liblzma/common/filter_common.c b/src/liblzma/common/filter_common.c index 7c95b05f2a3f..9ad5d5d8e2af 100644 --- a/src/liblzma/common/filter_common.c +++ b/src/liblzma/common/filter_common.c @@ -123,7 +123,7 @@ static const struct { extern LZMA_API(lzma_ret) lzma_filters_copy(const lzma_filter *src, lzma_filter *dest, - lzma_allocator *allocator) + const lzma_allocator *allocator) { if (src == NULL || dest == NULL) return LZMA_PROG_ERROR; @@ -239,7 +239,7 @@ validate_chain(const lzma_filter *filters, size_t *count) extern lzma_ret -lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_raw_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *options, lzma_filter_find coder_find, bool is_encoder) { diff --git a/src/liblzma/common/filter_common.h b/src/liblzma/common/filter_common.h index cd61fc0724f3..42a26a24a47f 100644 --- a/src/liblzma/common/filter_common.h +++ b/src/liblzma/common/filter_common.h @@ -36,7 +36,7 @@ typedef const lzma_filter_coder *(*lzma_filter_find)(lzma_vli id); extern lzma_ret lzma_raw_coder_init( - lzma_next_coder *next, lzma_allocator *allocator, + lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *filters, lzma_filter_find coder_find, bool is_encoder); diff --git a/src/liblzma/common/filter_decoder.c b/src/liblzma/common/filter_decoder.c index 1ebbe2afef0c..c75b0a89c30f 100644 --- a/src/liblzma/common/filter_decoder.c +++ b/src/liblzma/common/filter_decoder.c @@ -35,7 +35,8 @@ typedef struct { /// \return - LZMA_OK: Properties decoded successfully. /// - LZMA_OPTIONS_ERROR: Unsupported properties /// - LZMA_MEM_ERROR: Memory allocation failed. - lzma_ret (*props_decode)(void **options, lzma_allocator *allocator, + lzma_ret (*props_decode)( + void **options, const lzma_allocator *allocator, const uint8_t *props, size_t props_size); } lzma_filter_decoder; @@ -136,7 +137,7 @@ lzma_filter_decoder_is_supported(lzma_vli id) extern lzma_ret -lzma_raw_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_raw_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *options) { return lzma_raw_coder_init(next, allocator, @@ -165,7 +166,7 @@ lzma_raw_decoder_memusage(const lzma_filter *filters) extern LZMA_API(lzma_ret) -lzma_properties_decode(lzma_filter *filter, lzma_allocator *allocator, +lzma_properties_decode(lzma_filter *filter, const lzma_allocator *allocator, const uint8_t *props, size_t props_size) { // Make it always NULL so that the caller can always safely free() it. diff --git a/src/liblzma/common/filter_decoder.h b/src/liblzma/common/filter_decoder.h index d5c68bdd4a68..a2e255fe5f06 100644 --- a/src/liblzma/common/filter_decoder.h +++ b/src/liblzma/common/filter_decoder.h @@ -17,7 +17,7 @@ extern lzma_ret lzma_raw_decoder_init( - lzma_next_coder *next, lzma_allocator *allocator, + lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *options); #endif diff --git a/src/liblzma/common/filter_encoder.c b/src/liblzma/common/filter_encoder.c index 635d81223472..c5d8f39721fe 100644 --- a/src/liblzma/common/filter_encoder.c +++ b/src/liblzma/common/filter_encoder.c @@ -30,11 +30,11 @@ typedef struct { /// invalid, UINT64_MAX is returned. uint64_t (*memusage)(const void *options); - /// Calculates the minimum sane size for Blocks (or other types of - /// chunks) to which the input data can be split to make - /// multithreaded encoding possible. If this is NULL, it is assumed - /// that the encoder is fast enough with single thread. - lzma_vli (*chunk_size)(const void *options); + /// Calculates the recommended Uncompressed Size for .xz Blocks to + /// which the input data can be split to make multithreaded + /// encoding possible. If this is NULL, it is assumed that + /// the encoder is fast enough with single thread. + uint64_t (*block_size)(const void *options); /// Tells the size of the Filter Properties field. If options are /// invalid, UINT32_MAX is returned. If this is NULL, props_size_fixed @@ -59,7 +59,7 @@ static const lzma_filter_encoder encoders[] = { .id = LZMA_FILTER_LZMA1, .init = &lzma_lzma_encoder_init, .memusage = &lzma_lzma_encoder_memusage, - .chunk_size = NULL, // FIXME + .block_size = NULL, // FIXME .props_size_get = NULL, .props_size_fixed = 5, .props_encode = &lzma_lzma_props_encode, @@ -70,7 +70,7 @@ static const lzma_filter_encoder encoders[] = { .id = LZMA_FILTER_LZMA2, .init = &lzma_lzma2_encoder_init, .memusage = &lzma_lzma2_encoder_memusage, - .chunk_size = NULL, // FIXME + .block_size = &lzma_lzma2_block_size, // FIXME .props_size_get = NULL, .props_size_fixed = 1, .props_encode = &lzma_lzma2_props_encode, @@ -81,7 +81,7 @@ static const lzma_filter_encoder encoders[] = { .id = LZMA_FILTER_X86, .init = &lzma_simple_x86_encoder_init, .memusage = NULL, - .chunk_size = NULL, + .block_size = NULL, .props_size_get = &lzma_simple_props_size, .props_encode = &lzma_simple_props_encode, }, @@ -91,7 +91,7 @@ static const lzma_filter_encoder encoders[] = { .id = LZMA_FILTER_POWERPC, .init = &lzma_simple_powerpc_encoder_init, .memusage = NULL, - .chunk_size = NULL, + .block_size = NULL, .props_size_get = &lzma_simple_props_size, .props_encode = &lzma_simple_props_encode, }, @@ -101,7 +101,7 @@ static const lzma_filter_encoder encoders[] = { .id = LZMA_FILTER_IA64, .init = &lzma_simple_ia64_encoder_init, .memusage = NULL, - .chunk_size = NULL, + .block_size = NULL, .props_size_get = &lzma_simple_props_size, .props_encode = &lzma_simple_props_encode, }, @@ -111,7 +111,7 @@ static const lzma_filter_encoder encoders[] = { .id = LZMA_FILTER_ARM, .init = &lzma_simple_arm_encoder_init, .memusage = NULL, - .chunk_size = NULL, + .block_size = NULL, .props_size_get = &lzma_simple_props_size, .props_encode = &lzma_simple_props_encode, }, @@ -121,7 +121,7 @@ static const lzma_filter_encoder encoders[] = { .id = LZMA_FILTER_ARMTHUMB, .init = &lzma_simple_armthumb_encoder_init, .memusage = NULL, - .chunk_size = NULL, + .block_size = NULL, .props_size_get = &lzma_simple_props_size, .props_encode = &lzma_simple_props_encode, }, @@ -131,7 +131,7 @@ static const lzma_filter_encoder encoders[] = { .id = LZMA_FILTER_SPARC, .init = &lzma_simple_sparc_encoder_init, .memusage = NULL, - .chunk_size = NULL, + .block_size = NULL, .props_size_get = &lzma_simple_props_size, .props_encode = &lzma_simple_props_encode, }, @@ -141,7 +141,7 @@ static const lzma_filter_encoder encoders[] = { .id = LZMA_FILTER_DELTA, .init = &lzma_delta_encoder_init, .memusage = &lzma_delta_coder_memusage, - .chunk_size = NULL, + .block_size = NULL, .props_size_get = NULL, .props_size_fixed = 1, .props_encode = &lzma_delta_props_encode, @@ -196,7 +196,7 @@ lzma_filters_update(lzma_stream *strm, const lzma_filter *filters) extern lzma_ret -lzma_raw_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_raw_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *options) { return lzma_raw_coder_init(next, allocator, @@ -226,20 +226,19 @@ lzma_raw_encoder_memusage(const lzma_filter *filters) } -/* -extern LZMA_API(lzma_vli) -lzma_chunk_size(const lzma_filter *filters) +extern uint64_t +lzma_mt_block_size(const lzma_filter *filters) { - lzma_vli max = 0; + uint64_t max = 0; for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) { const lzma_filter_encoder *const fe = encoder_find(filters[i].id); - if (fe->chunk_size != NULL) { - const lzma_vli size - = fe->chunk_size(filters[i].options); - if (size == LZMA_VLI_UNKNOWN) - return LZMA_VLI_UNKNOWN; + if (fe->block_size != NULL) { + const uint64_t size + = fe->block_size(filters[i].options); + if (size == 0) + return 0; if (size > max) max = size; @@ -248,7 +247,6 @@ lzma_chunk_size(const lzma_filter *filters) return max; } -*/ extern LZMA_API(lzma_ret) diff --git a/src/liblzma/common/filter_encoder.h b/src/liblzma/common/filter_encoder.h index 5bc137f64584..f1d5683fe793 100644 --- a/src/liblzma/common/filter_encoder.h +++ b/src/liblzma/common/filter_encoder.h @@ -16,12 +16,12 @@ #include "common.h" -// FIXME: Might become a part of the public API once finished. -// extern lzma_vli lzma_chunk_size(const lzma_filter *filters); +// FIXME: Might become a part of the public API. +extern uint64_t lzma_mt_block_size(const lzma_filter *filters); extern lzma_ret lzma_raw_encoder_init( - lzma_next_coder *next, lzma_allocator *allocator, + lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *filters); #endif diff --git a/src/liblzma/common/filter_flags_decoder.c b/src/liblzma/common/filter_flags_decoder.c index caae10ce79a0..ddfb085943d0 100644 --- a/src/liblzma/common/filter_flags_decoder.c +++ b/src/liblzma/common/filter_flags_decoder.c @@ -15,7 +15,7 @@ extern LZMA_API(lzma_ret) lzma_filter_flags_decode( - lzma_filter *filter, lzma_allocator *allocator, + lzma_filter *filter, const lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size) { // Set the pointer to NULL so the caller can always safely free it. diff --git a/src/liblzma/common/stream_encoder.h b/src/liblzma/common/hardware_cputhreads.c similarity index 53% rename from src/liblzma/common/stream_encoder.h rename to src/liblzma/common/hardware_cputhreads.c index 46a7aed72eaa..f468366a6045 100644 --- a/src/liblzma/common/stream_encoder.h +++ b/src/liblzma/common/hardware_cputhreads.c @@ -1,7 +1,7 @@ /////////////////////////////////////////////////////////////////////////////// // -/// \file stream_encoder.h -/// \brief Encodes .xz Streams +/// \file hardware_cputhreads.c +/// \brief Get the number of CPU threads or cores // // Author: Lasse Collin // @@ -10,14 +10,13 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifndef LZMA_STREAM_ENCODER_H -#define LZMA_STREAM_ENCODER_H - #include "common.h" +#include "tuklib_cpucores.h" -extern lzma_ret lzma_stream_encoder_init( - lzma_next_coder *next, lzma_allocator *allocator, - const lzma_filter *filters, lzma_check check); -#endif +extern LZMA_API(uint32_t) +lzma_cputhreads(void) +{ + return tuklib_cpucores(); +} diff --git a/src/liblzma/common/index.c b/src/liblzma/common/index.c index 9af4bc19d1b5..11f45f4009ea 100644 --- a/src/liblzma/common/index.c +++ b/src/liblzma/common/index.c @@ -191,8 +191,8 @@ index_tree_init(index_tree *tree) /// Helper for index_tree_end() static void -index_tree_node_end(index_tree_node *node, lzma_allocator *allocator, - void (*free_func)(void *node, lzma_allocator *allocator)) +index_tree_node_end(index_tree_node *node, const lzma_allocator *allocator, + void (*free_func)(void *node, const lzma_allocator *allocator)) { // The tree won't ever be very huge, so recursion should be fine. // 20 levels in the tree is likely quite a lot already in practice. @@ -215,8 +215,8 @@ index_tree_node_end(index_tree_node *node, lzma_allocator *allocator, /// to free the Record groups from each index_stream before freeing /// the index_stream itself. static void -index_tree_end(index_tree *tree, lzma_allocator *allocator, - void (*free_func)(void *node, lzma_allocator *allocator)) +index_tree_end(index_tree *tree, const lzma_allocator *allocator, + void (*free_func)(void *node, const lzma_allocator *allocator)) { if (tree->root != NULL) index_tree_node_end(tree->root, allocator, free_func); @@ -340,7 +340,7 @@ index_tree_locate(const index_tree *tree, lzma_vli target) static index_stream * index_stream_init(lzma_vli compressed_base, lzma_vli uncompressed_base, lzma_vli stream_number, lzma_vli block_number_base, - lzma_allocator *allocator) + const lzma_allocator *allocator) { index_stream *s = lzma_alloc(sizeof(index_stream), allocator); if (s == NULL) @@ -368,7 +368,7 @@ index_stream_init(lzma_vli compressed_base, lzma_vli uncompressed_base, /// Free the memory allocated for a Stream and its Record groups. static void -index_stream_end(void *node, lzma_allocator *allocator) +index_stream_end(void *node, const lzma_allocator *allocator) { index_stream *s = node; index_tree_end(&s->groups, allocator, NULL); @@ -377,7 +377,7 @@ index_stream_end(void *node, lzma_allocator *allocator) static lzma_index * -index_init_plain(lzma_allocator *allocator) +index_init_plain(const lzma_allocator *allocator) { lzma_index *i = lzma_alloc(sizeof(lzma_index), allocator); if (i != NULL) { @@ -395,7 +395,7 @@ index_init_plain(lzma_allocator *allocator) extern LZMA_API(lzma_index *) -lzma_index_init(lzma_allocator *allocator) +lzma_index_init(const lzma_allocator *allocator) { lzma_index *i = index_init_plain(allocator); if (i == NULL) @@ -414,7 +414,7 @@ lzma_index_init(lzma_allocator *allocator) extern LZMA_API(void) -lzma_index_end(lzma_index *i, lzma_allocator *allocator) +lzma_index_end(lzma_index *i, const lzma_allocator *allocator) { // NOTE: If you modify this function, check also the bottom // of lzma_index_cat(). @@ -637,7 +637,7 @@ lzma_index_stream_padding(lzma_index *i, lzma_vli stream_padding) extern LZMA_API(lzma_ret) -lzma_index_append(lzma_index *i, lzma_allocator *allocator, +lzma_index_append(lzma_index *i, const lzma_allocator *allocator, lzma_vli unpadded_size, lzma_vli uncompressed_size) { // Validate. @@ -765,7 +765,7 @@ index_cat_helper(const index_cat_info *info, index_stream *this) extern LZMA_API(lzma_ret) lzma_index_cat(lzma_index *restrict dest, lzma_index *restrict src, - lzma_allocator *allocator) + const lzma_allocator *allocator) { const lzma_vli dest_file_size = lzma_index_file_size(dest); @@ -859,7 +859,7 @@ lzma_index_cat(lzma_index *restrict dest, lzma_index *restrict src, /// Duplicate an index_stream. static index_stream * -index_dup_stream(const index_stream *src, lzma_allocator *allocator) +index_dup_stream(const index_stream *src, const lzma_allocator *allocator) { // Catch a somewhat theoretical integer overflow. if (src->record_count > PREALLOC_MAX) @@ -919,7 +919,7 @@ index_dup_stream(const index_stream *src, lzma_allocator *allocator) extern LZMA_API(lzma_index *) -lzma_index_dup(const lzma_index *src, lzma_allocator *allocator) +lzma_index_dup(const lzma_index *src, const lzma_allocator *allocator) { // Allocate the base structure (no initial Stream). lzma_index *dest = index_init_plain(allocator); diff --git a/src/liblzma/common/index_decoder.c b/src/liblzma/common/index_decoder.c index 83c8a3af1db8..795d1834cc58 100644 --- a/src/liblzma/common/index_decoder.c +++ b/src/liblzma/common/index_decoder.c @@ -54,7 +54,7 @@ struct lzma_coder_s { static lzma_ret -index_decode(lzma_coder *coder, lzma_allocator *allocator, +index_decode(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out lzma_attribute((__unused__)), @@ -207,7 +207,7 @@ index_decode(lzma_coder *coder, lzma_allocator *allocator, static void -index_decoder_end(lzma_coder *coder, lzma_allocator *allocator) +index_decoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_index_end(coder->index, allocator); lzma_free(coder, allocator); @@ -234,7 +234,7 @@ index_decoder_memconfig(lzma_coder *coder, uint64_t *memusage, static lzma_ret -index_decoder_reset(lzma_coder *coder, lzma_allocator *allocator, +index_decoder_reset(lzma_coder *coder, const lzma_allocator *allocator, lzma_index **i, uint64_t memlimit) { // Remember the pointer given by the application. We will set it @@ -261,7 +261,7 @@ index_decoder_reset(lzma_coder *coder, lzma_allocator *allocator, static lzma_ret -index_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +index_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, lzma_index **i, uint64_t memlimit) { lzma_next_coder_init(&index_decoder_init, next, allocator); @@ -299,8 +299,8 @@ lzma_index_decoder(lzma_stream *strm, lzma_index **i, uint64_t memlimit) extern LZMA_API(lzma_ret) -lzma_index_buffer_decode( - lzma_index **i, uint64_t *memlimit, lzma_allocator *allocator, +lzma_index_buffer_decode(lzma_index **i, uint64_t *memlimit, + const lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size) { // Sanity checks diff --git a/src/liblzma/common/index_encoder.c b/src/liblzma/common/index_encoder.c index 45919f094c42..d25ac7d3372b 100644 --- a/src/liblzma/common/index_encoder.c +++ b/src/liblzma/common/index_encoder.c @@ -42,7 +42,7 @@ struct lzma_coder_s { static lzma_ret index_encode(lzma_coder *coder, - lzma_allocator *allocator lzma_attribute((__unused__)), + const lzma_allocator *allocator lzma_attribute((__unused__)), const uint8_t *restrict in lzma_attribute((__unused__)), size_t *restrict in_pos lzma_attribute((__unused__)), size_t in_size lzma_attribute((__unused__)), @@ -159,7 +159,7 @@ index_encode(lzma_coder *coder, static void -index_encoder_end(lzma_coder *coder, lzma_allocator *allocator) +index_encoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_free(coder, allocator); return; @@ -181,7 +181,7 @@ index_encoder_reset(lzma_coder *coder, const lzma_index *i) extern lzma_ret -lzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_index *i) { lzma_next_coder_init(&lzma_index_encoder_init, next, allocator); diff --git a/src/liblzma/common/index_encoder.h b/src/liblzma/common/index_encoder.h index a13c94dcd077..4d55cd104785 100644 --- a/src/liblzma/common/index_encoder.h +++ b/src/liblzma/common/index_encoder.h @@ -17,7 +17,7 @@ extern lzma_ret lzma_index_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_index *i); + const lzma_allocator *allocator, const lzma_index *i); #endif diff --git a/src/liblzma/common/index_hash.c b/src/liblzma/common/index_hash.c index e3e9386ae8e3..d7a0344b76c3 100644 --- a/src/liblzma/common/index_hash.c +++ b/src/liblzma/common/index_hash.c @@ -70,7 +70,8 @@ struct lzma_index_hash_s { extern LZMA_API(lzma_index_hash *) -lzma_index_hash_init(lzma_index_hash *index_hash, lzma_allocator *allocator) +lzma_index_hash_init(lzma_index_hash *index_hash, + const lzma_allocator *allocator) { if (index_hash == NULL) { index_hash = lzma_alloc(sizeof(lzma_index_hash), allocator); @@ -101,7 +102,8 @@ lzma_index_hash_init(lzma_index_hash *index_hash, lzma_allocator *allocator) extern LZMA_API(void) -lzma_index_hash_end(lzma_index_hash *index_hash, lzma_allocator *allocator) +lzma_index_hash_end(lzma_index_hash *index_hash, + const lzma_allocator *allocator) { lzma_free(index_hash, allocator); return; diff --git a/src/liblzma/common/memcmplen.h b/src/liblzma/common/memcmplen.h new file mode 100644 index 000000000000..f66e7cdb66c6 --- /dev/null +++ b/src/liblzma/common/memcmplen.h @@ -0,0 +1,170 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file memcmplen.h +/// \brief Optimized comparison of two buffers +// +// Author: Lasse Collin +// +// This file has been put into the public domain. +// You can do whatever you want with this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef LZMA_MEMCMPLEN_H +#define LZMA_MEMCMPLEN_H + +#include "common.h" + +#ifdef HAVE_IMMINTRIN_H +# include +#endif + +/// How many extra bytes lzma_memcmplen() may read. This depends on +/// the method but since it is just a few bytes the biggest possible +/// value is used here. +#define LZMA_MEMCMPLEN_EXTRA 16 + + +/// Find out how many equal bytes the two buffers have. +/// +/// \param buf1 First buffer +/// \param buf2 Second buffer +/// \param len How many bytes have already been compared and will +/// be assumed to match +/// \param limit How many bytes to compare at most, including the +/// already-compared bytes. This must be significantly +/// smaller than UINT32_MAX to avoid integer overflows. +/// Up to LZMA_MEMCMPLEN_EXTRA bytes may be read past +/// the specified limit from both buf1 and buf2. +/// +/// \return Number of equal bytes in the buffers is returned. +/// This is always at least len and at most limit. +static inline uint32_t lzma_attribute((__always_inline__)) +lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2, + uint32_t len, uint32_t limit) +{ + assert(len <= limit); + assert(limit <= UINT32_MAX / 2); + +#if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \ + && ((TUKLIB_GNUC_REQ(3, 4) && defined(__x86_64__)) \ + || (defined(__INTEL_COMPILER) && defined(__x86_64__)) \ + || (defined(__INTEL_COMPILER) && defined(_M_X64)) \ + || (defined(_MSC_VER) && defined(_M_X64))) + // NOTE: This will use 64-bit unaligned access which + // TUKLIB_FAST_UNALIGNED_ACCESS wasn't meant to permit, but + // it's convenient here at least as long as it's x86-64 only. + // + // I keep this x86-64 only for now since that's where I know this + // to be a good method. This may be fine on other 64-bit CPUs too. + // On big endian one should use xor instead of subtraction and switch + // to __builtin_clzll(). + while (len < limit) { + const uint64_t x = *(const uint64_t *)(buf1 + len) + - *(const uint64_t *)(buf2 + len); + if (x != 0) { +# if defined(_M_X64) // MSVC or Intel C compiler on Windows + unsigned long tmp; + _BitScanForward64(&tmp, x); + len += (uint32_t)tmp >> 3; +# else // GCC, clang, or Intel C compiler + len += (uint32_t)__builtin_ctzll(x) >> 3; +# endif + return my_min(len, limit); + } + + len += 8; + } + + return limit; + +#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) \ + && defined(HAVE__MM_MOVEMASK_EPI8) \ + && ((defined(__GNUC__) && defined(__SSE2_MATH__)) \ + || (defined(__INTEL_COMPILER) && defined(__SSE2__)) \ + || (defined(_MSC_VER) && defined(_M_IX86_FP) \ + && _M_IX86_FP >= 2)) + // NOTE: Like above, this will use 128-bit unaligned access which + // TUKLIB_FAST_UNALIGNED_ACCESS wasn't meant to permit. + // + // SSE2 version for 32-bit and 64-bit x86. On x86-64 the above + // version is sometimes significantly faster and sometimes + // slightly slower than this SSE2 version, so this SSE2 + // version isn't used on x86-64. + while (len < limit) { + const uint32_t x = 0xFFFF ^ _mm_movemask_epi8(_mm_cmpeq_epi8( + _mm_loadu_si128((const __m128i *)(buf1 + len)), + _mm_loadu_si128((const __m128i *)(buf2 + len)))); + + if (x != 0) { +# if defined(__INTEL_COMPILER) + len += _bit_scan_forward(x); +# elif defined(_MSC_VER) + unsigned long tmp; + _BitScanForward(&tmp, x); + len += tmp; +# else + len += __builtin_ctz(x); +# endif + return my_min(len, limit); + } + + len += 16; + } + + return limit; + +#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && !defined(WORDS_BIGENDIAN) + // Generic 32-bit little endian method + while (len < limit) { + uint32_t x = *(const uint32_t *)(buf1 + len) + - *(const uint32_t *)(buf2 + len); + if (x != 0) { + if ((x & 0xFFFF) == 0) { + len += 2; + x >>= 16; + } + + if ((x & 0xFF) == 0) + ++len; + + return my_min(len, limit); + } + + len += 4; + } + + return limit; + +#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && defined(WORDS_BIGENDIAN) + // Generic 32-bit big endian method + while (len < limit) { + uint32_t x = *(const uint32_t *)(buf1 + len) + ^ *(const uint32_t *)(buf2 + len); + if (x != 0) { + if ((x & 0xFFFF0000) == 0) { + len += 2; + x <<= 16; + } + + if ((x & 0xFF000000) == 0) + ++len; + + return my_min(len, limit); + } + + len += 4; + } + + return limit; + +#else + // Simple portable version that doesn't use unaligned access. + while (len < limit && buf1[len] == buf2[len]) + ++len; + + return len; +#endif +} + +#endif diff --git a/src/liblzma/common/outqueue.c b/src/liblzma/common/outqueue.c new file mode 100644 index 000000000000..2dc8a38d1be3 --- /dev/null +++ b/src/liblzma/common/outqueue.c @@ -0,0 +1,184 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file outqueue.c +/// \brief Output queue handling in multithreaded coding +// +// Author: Lasse Collin +// +// This file has been put into the public domain. +// You can do whatever you want with this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "outqueue.h" + + +/// This is to ease integer overflow checking: We may allocate up to +/// 2 * LZMA_THREADS_MAX buffers and we need some extra memory for other +/// data structures (that's the second /2). +#define BUF_SIZE_MAX (UINT64_MAX / LZMA_THREADS_MAX / 2 / 2) + + +static lzma_ret +get_options(uint64_t *bufs_alloc_size, uint32_t *bufs_count, + uint64_t buf_size_max, uint32_t threads) +{ + if (threads > LZMA_THREADS_MAX || buf_size_max > BUF_SIZE_MAX) + return LZMA_OPTIONS_ERROR; + + // The number of buffers is twice the number of threads. + // This wastes RAM but keeps the threads busy when buffers + // finish out of order. + // + // NOTE: If this is changed, update BUF_SIZE_MAX too. + *bufs_count = threads * 2; + *bufs_alloc_size = *bufs_count * buf_size_max; + + return LZMA_OK; +} + + +extern uint64_t +lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads) +{ + uint64_t bufs_alloc_size; + uint32_t bufs_count; + + if (get_options(&bufs_alloc_size, &bufs_count, buf_size_max, threads) + != LZMA_OK) + return UINT64_MAX; + + return sizeof(lzma_outq) + bufs_count * sizeof(lzma_outbuf) + + bufs_alloc_size; +} + + +extern lzma_ret +lzma_outq_init(lzma_outq *outq, const lzma_allocator *allocator, + uint64_t buf_size_max, uint32_t threads) +{ + uint64_t bufs_alloc_size; + uint32_t bufs_count; + + // Set bufs_count and bufs_alloc_size. + return_if_error(get_options(&bufs_alloc_size, &bufs_count, + buf_size_max, threads)); + + // Allocate memory if needed. + if (outq->buf_size_max != buf_size_max + || outq->bufs_allocated != bufs_count) { + lzma_outq_end(outq, allocator); + +#if SIZE_MAX < UINT64_MAX + if (bufs_alloc_size > SIZE_MAX) + return LZMA_MEM_ERROR; +#endif + + outq->bufs = lzma_alloc(bufs_count * sizeof(lzma_outbuf), + allocator); + outq->bufs_mem = lzma_alloc((size_t)(bufs_alloc_size), + allocator); + + if (outq->bufs == NULL || outq->bufs_mem == NULL) { + lzma_outq_end(outq, allocator); + return LZMA_MEM_ERROR; + } + } + + // Initialize the rest of the main structure. Initialization of + // outq->bufs[] is done when they are actually needed. + outq->buf_size_max = (size_t)(buf_size_max); + outq->bufs_allocated = bufs_count; + outq->bufs_pos = 0; + outq->bufs_used = 0; + outq->read_pos = 0; + + return LZMA_OK; +} + + +extern void +lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator) +{ + lzma_free(outq->bufs, allocator); + outq->bufs = NULL; + + lzma_free(outq->bufs_mem, allocator); + outq->bufs_mem = NULL; + + return; +} + + +extern lzma_outbuf * +lzma_outq_get_buf(lzma_outq *outq) +{ + // Caller must have checked it with lzma_outq_has_buf(). + assert(outq->bufs_used < outq->bufs_allocated); + + // Initialize the new buffer. + lzma_outbuf *buf = &outq->bufs[outq->bufs_pos]; + buf->buf = outq->bufs_mem + outq->bufs_pos * outq->buf_size_max; + buf->size = 0; + buf->finished = false; + + // Update the queue state. + if (++outq->bufs_pos == outq->bufs_allocated) + outq->bufs_pos = 0; + + ++outq->bufs_used; + + return buf; +} + + +extern bool +lzma_outq_is_readable(const lzma_outq *outq) +{ + uint32_t i = outq->bufs_pos - outq->bufs_used; + if (outq->bufs_pos < outq->bufs_used) + i += outq->bufs_allocated; + + return outq->bufs[i].finished; +} + + +extern lzma_ret +lzma_outq_read(lzma_outq *restrict outq, uint8_t *restrict out, + size_t *restrict out_pos, size_t out_size, + lzma_vli *restrict unpadded_size, + lzma_vli *restrict uncompressed_size) +{ + // There must be at least one buffer from which to read. + if (outq->bufs_used == 0) + return LZMA_OK; + + // Get the buffer. + uint32_t i = outq->bufs_pos - outq->bufs_used; + if (outq->bufs_pos < outq->bufs_used) + i += outq->bufs_allocated; + + lzma_outbuf *buf = &outq->bufs[i]; + + // If it isn't finished yet, we cannot read from it. + if (!buf->finished) + return LZMA_OK; + + // Copy from the buffer to output. + lzma_bufcpy(buf->buf, &outq->read_pos, buf->size, + out, out_pos, out_size); + + // Return if we didn't get all the data from the buffer. + if (outq->read_pos < buf->size) + return LZMA_OK; + + // The buffer was finished. Tell the caller its size information. + *unpadded_size = buf->unpadded_size; + *uncompressed_size = buf->uncompressed_size; + + // Free this buffer for further use. + --outq->bufs_used; + outq->read_pos = 0; + + return LZMA_STREAM_END; +} diff --git a/src/liblzma/common/outqueue.h b/src/liblzma/common/outqueue.h new file mode 100644 index 000000000000..079634de4587 --- /dev/null +++ b/src/liblzma/common/outqueue.h @@ -0,0 +1,156 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file outqueue.h +/// \brief Output queue handling in multithreaded coding +// +// Author: Lasse Collin +// +// This file has been put into the public domain. +// You can do whatever you want with this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "common.h" + + +/// Output buffer for a single thread +typedef struct { + /// Pointer to the output buffer of lzma_outq.buf_size_max bytes + uint8_t *buf; + + /// Amount of data written to buf + size_t size; + + /// Additional size information + lzma_vli unpadded_size; + lzma_vli uncompressed_size; + + /// True when no more data will be written into this buffer. + /// + /// \note This is read by another thread and thus access + /// to this variable needs a mutex. + bool finished; + +} lzma_outbuf; + + +typedef struct { + /// Array of buffers that are used cyclically. + lzma_outbuf *bufs; + + /// Memory allocated for all the buffers + uint8_t *bufs_mem; + + /// Amount of buffer space available in each buffer + size_t buf_size_max; + + /// Number of buffers allocated + uint32_t bufs_allocated; + + /// Position in the bufs array. The next buffer to be taken + /// into use is bufs[bufs_pos]. + uint32_t bufs_pos; + + /// Number of buffers in use + uint32_t bufs_used; + + /// Position in the buffer in lzma_outq_read() + size_t read_pos; + +} lzma_outq; + + +/** + * \brief Calculate the memory usage of an output queue + * + * \return Approximate memory usage in bytes or UINT64_MAX on error. + */ +extern uint64_t lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads); + + +/// \brief Initialize an output queue +/// +/// \param outq Pointer to an output queue. Before calling +/// this function the first time, *outq should +/// have been zeroed with memzero() so that this +/// function knows that there are no previous +/// allocations to free. +/// \param allocator Pointer to allocator or NULL +/// \param buf_size_max Maximum amount of data that a single buffer +/// in the queue may need to store. +/// \param threads Number of buffers that may be in use +/// concurrently. Note that more than this number +/// of buffers will actually get allocated to +/// improve performance when buffers finish +/// out of order. +/// +/// \return - LZMA_OK +/// - LZMA_MEM_ERROR +/// +extern lzma_ret lzma_outq_init( + lzma_outq *outq, const lzma_allocator *allocator, + uint64_t buf_size_max, uint32_t threads); + + +/// \brief Free the memory associated with the output queue +extern void lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator); + + +/// \brief Get a new buffer +/// +/// lzma_outq_has_buf() must be used to check that there is a buffer +/// available before calling lzma_outq_get_buf(). +/// +extern lzma_outbuf *lzma_outq_get_buf(lzma_outq *outq); + + +/// \brief Test if there is data ready to be read +/// +/// Call to this function must be protected with the same mutex that +/// is used to protect lzma_outbuf.finished. +/// +extern bool lzma_outq_is_readable(const lzma_outq *outq); + + +/// \brief Read finished data +/// +/// \param outq Pointer to an output queue +/// \param out Beginning of the output buffer +/// \param out_pos The next byte will be written to +/// out[*out_pos]. +/// \param out_size Size of the out buffer; the first byte into +/// which no data is written to is out[out_size]. +/// \param unpadded_size Unpadded Size from the Block encoder +/// \param uncompressed_size Uncompressed Size from the Block encoder +/// +/// \return - LZMA: All OK. Either no data was available or the buffer +/// being read didn't become empty yet. +/// - LZMA_STREAM_END: The buffer being read was finished. +/// *unpadded_size and *uncompressed_size were set. +/// +/// \note This reads lzma_outbuf.finished variables and thus call +/// to this function needs to be protected with a mutex. +/// +extern lzma_ret lzma_outq_read(lzma_outq *restrict outq, + uint8_t *restrict out, size_t *restrict out_pos, + size_t out_size, lzma_vli *restrict unpadded_size, + lzma_vli *restrict uncompressed_size); + + +/// \brief Test if there is at least one buffer free +/// +/// This must be used before getting a new buffer with lzma_outq_get_buf(). +/// +static inline bool +lzma_outq_has_buf(const lzma_outq *outq) +{ + return outq->bufs_used < outq->bufs_allocated; +} + + +/// \brief Test if the queue is completely empty +static inline bool +lzma_outq_is_empty(const lzma_outq *outq) +{ + return outq->bufs_used == 0; +} diff --git a/src/liblzma/common/stream_buffer_decoder.c b/src/liblzma/common/stream_buffer_decoder.c index ae753155180d..b9745b5dbe18 100644 --- a/src/liblzma/common/stream_buffer_decoder.c +++ b/src/liblzma/common/stream_buffer_decoder.c @@ -15,7 +15,7 @@ extern LZMA_API(lzma_ret) lzma_stream_buffer_decode(uint64_t *memlimit, uint32_t flags, - lzma_allocator *allocator, + const lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) { diff --git a/src/liblzma/common/stream_buffer_encoder.c b/src/liblzma/common/stream_buffer_encoder.c index 2450ee2e1fa0..af49554a6b0c 100644 --- a/src/liblzma/common/stream_buffer_encoder.c +++ b/src/liblzma/common/stream_buffer_encoder.c @@ -42,7 +42,8 @@ lzma_stream_buffer_bound(size_t uncompressed_size) extern LZMA_API(lzma_ret) lzma_stream_buffer_encode(lzma_filter *filters, lzma_check check, - lzma_allocator *allocator, const uint8_t *in, size_t in_size, + const lzma_allocator *allocator, + const uint8_t *in, size_t in_size, uint8_t *out, size_t *out_pos_ptr, size_t out_size) { // Sanity checks diff --git a/src/liblzma/common/stream_decoder.c b/src/liblzma/common/stream_decoder.c index 37ea71edbd71..3ab938c9f142 100644 --- a/src/liblzma/common/stream_decoder.c +++ b/src/liblzma/common/stream_decoder.c @@ -57,6 +57,10 @@ struct lzma_coder_s { /// If true, LZMA_GET_CHECK is returned after decoding Stream Header. bool tell_any_check; + /// If true, we will tell the Block decoder to skip calculating + /// and verifying the integrity check. + bool ignore_check; + /// If true, we will decode concatenated Streams that possibly have /// Stream Padding between or after them. LZMA_STREAM_END is returned /// once the application isn't giving us any new input, and we aren't @@ -80,7 +84,7 @@ struct lzma_coder_s { static lzma_ret -stream_decoder_reset(lzma_coder *coder, lzma_allocator *allocator) +stream_decoder_reset(lzma_coder *coder, const lzma_allocator *allocator) { // Initialize the Index hash used to verify the Index. coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator); @@ -96,7 +100,7 @@ stream_decoder_reset(lzma_coder *coder, lzma_allocator *allocator) static lzma_ret -stream_decode(lzma_coder *coder, lzma_allocator *allocator, +stream_decode(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, lzma_action action) @@ -182,8 +186,8 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, coder->pos = 0; - // Version 0 is currently the only possible version. - coder->block_options.version = 0; + // Version 1 is needed to support the .ignore_check option. + coder->block_options.version = 1; // Set up a buffer to hold the filter chain. Block Header // decoder will initialize all members of this array so @@ -195,6 +199,11 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, return_if_error(lzma_block_header_decode(&coder->block_options, allocator, coder->buffer)); + // If LZMA_IGNORE_CHECK was used, this flag needs to be set. + // It has to be set after lzma_block_header_decode() because + // it always resets this to false. + coder->block_options.ignore_check = coder->ignore_check; + // Check the memory usage limit. const uint64_t memusage = lzma_raw_decoder_memusage(filters); lzma_ret ret; @@ -366,7 +375,7 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, static void -stream_decoder_end(lzma_coder *coder, lzma_allocator *allocator) +stream_decoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->block_decoder, allocator); lzma_index_hash_end(coder->index_hash, allocator); @@ -401,7 +410,8 @@ stream_decoder_memconfig(lzma_coder *coder, uint64_t *memusage, extern lzma_ret -lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_stream_decoder_init( + lzma_next_coder *next, const lzma_allocator *allocator, uint64_t memlimit, uint32_t flags) { lzma_next_coder_init(&lzma_stream_decoder_init, next, allocator); @@ -432,6 +442,7 @@ lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, next->coder->tell_unsupported_check = (flags & LZMA_TELL_UNSUPPORTED_CHECK) != 0; next->coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0; + next->coder->ignore_check = (flags & LZMA_IGNORE_CHECK) != 0; next->coder->concatenated = (flags & LZMA_CONCATENATED) != 0; next->coder->first_stream = true; diff --git a/src/liblzma/common/stream_decoder.h b/src/liblzma/common/stream_decoder.h index e54ac28f44a5..c13c6ba12706 100644 --- a/src/liblzma/common/stream_decoder.h +++ b/src/liblzma/common/stream_decoder.h @@ -15,7 +15,8 @@ #include "common.h" -extern lzma_ret lzma_stream_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, uint64_t memlimit, uint32_t flags); +extern lzma_ret lzma_stream_decoder_init( + lzma_next_coder *next, const lzma_allocator *allocator, + uint64_t memlimit, uint32_t flags); #endif diff --git a/src/liblzma/common/stream_encoder.c b/src/liblzma/common/stream_encoder.c index 97a7a23a8135..a7663bc48db3 100644 --- a/src/liblzma/common/stream_encoder.c +++ b/src/liblzma/common/stream_encoder.c @@ -10,7 +10,6 @@ // /////////////////////////////////////////////////////////////////////////////// -#include "stream_encoder.h" #include "block_encoder.h" #include "index_encoder.h" @@ -26,7 +25,7 @@ struct lzma_coder_s { } sequence; /// True if Block encoder has been initialized by - /// lzma_stream_encoder_init() or stream_encoder_update() + /// stream_encoder_init() or stream_encoder_update() /// and thus doesn't need to be initialized in stream_encode(). bool block_encoder_is_initialized; @@ -60,7 +59,7 @@ struct lzma_coder_s { static lzma_ret -block_encoder_init(lzma_coder *coder, lzma_allocator *allocator) +block_encoder_init(lzma_coder *coder, const lzma_allocator *allocator) { // Prepare the Block options. Even though Block encoder doesn't need // compressed_size, uncompressed_size, and header_size to be @@ -79,7 +78,7 @@ block_encoder_init(lzma_coder *coder, lzma_allocator *allocator) static lzma_ret -stream_encode(lzma_coder *coder, lzma_allocator *allocator, +stream_encode(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, lzma_action action) @@ -126,7 +125,7 @@ stream_encode(lzma_coder *coder, lzma_allocator *allocator, } // Initialize the Block encoder unless it was already - // initialized by lzma_stream_encoder_init() or + // initialized by stream_encoder_init() or // stream_encoder_update(). if (!coder->block_encoder_is_initialized) return_if_error(block_encoder_init(coder, allocator)); @@ -147,11 +146,12 @@ stream_encode(lzma_coder *coder, lzma_allocator *allocator, } case SEQ_BLOCK_ENCODE: { - static const lzma_action convert[4] = { + static const lzma_action convert[LZMA_ACTION_MAX + 1] = { LZMA_RUN, LZMA_SYNC_FLUSH, LZMA_FINISH, LZMA_FINISH, + LZMA_FINISH, }; const lzma_ret ret = coder->block_encoder.code( @@ -209,7 +209,7 @@ stream_encode(lzma_coder *coder, lzma_allocator *allocator, static void -stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator) +stream_encoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->block_encoder, allocator); lzma_next_end(&coder->index_encoder, allocator); @@ -224,7 +224,7 @@ stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator) static lzma_ret -stream_encoder_update(lzma_coder *coder, lzma_allocator *allocator, +stream_encoder_update(lzma_coder *coder, const lzma_allocator *allocator, const lzma_filter *filters, const lzma_filter *reversed_filters) { @@ -262,11 +262,11 @@ stream_encoder_update(lzma_coder *coder, lzma_allocator *allocator, } -extern lzma_ret -lzma_stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +static lzma_ret +stream_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *filters, lzma_check check) { - lzma_next_coder_init(&lzma_stream_encoder_init, next, allocator); + lzma_next_coder_init(&stream_encoder_init, next, allocator); if (filters == NULL) return LZMA_PROG_ERROR; @@ -320,11 +320,12 @@ extern LZMA_API(lzma_ret) lzma_stream_encoder(lzma_stream *strm, const lzma_filter *filters, lzma_check check) { - lzma_next_strm_init(lzma_stream_encoder_init, strm, filters, check); + lzma_next_strm_init(stream_encoder_init, strm, filters, check); strm->internal->supported_actions[LZMA_RUN] = true; strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; strm->internal->supported_actions[LZMA_FULL_FLUSH] = true; + strm->internal->supported_actions[LZMA_FULL_BARRIER] = true; strm->internal->supported_actions[LZMA_FINISH] = true; return LZMA_OK; diff --git a/src/liblzma/common/stream_encoder_mt.c b/src/liblzma/common/stream_encoder_mt.c new file mode 100644 index 000000000000..9780ed04cac4 --- /dev/null +++ b/src/liblzma/common/stream_encoder_mt.c @@ -0,0 +1,1131 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file stream_encoder_mt.c +/// \brief Multithreaded .xz Stream encoder +// +// Author: Lasse Collin +// +// This file has been put into the public domain. +// You can do whatever you want with this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "filter_encoder.h" +#include "easy_preset.h" +#include "block_encoder.h" +#include "block_buffer_encoder.h" +#include "index_encoder.h" +#include "outqueue.h" + + +/// Maximum supported block size. This makes it simpler to prevent integer +/// overflows if we are given unusually large block size. +#define BLOCK_SIZE_MAX (UINT64_MAX / LZMA_THREADS_MAX) + + +typedef enum { + /// Waiting for work. + THR_IDLE, + + /// Encoding is in progress. + THR_RUN, + + /// Encoding is in progress but no more input data will + /// be read. + THR_FINISH, + + /// The main thread wants the thread to stop whatever it was doing + /// but not exit. + THR_STOP, + + /// The main thread wants the thread to exit. We could use + /// cancellation but since there's stopped anyway, this is lazier. + THR_EXIT, + +} worker_state; + + +typedef struct worker_thread_s worker_thread; +struct worker_thread_s { + worker_state state; + + /// Input buffer of coder->block_size bytes. The main thread will + /// put new input into this and update in_size accordingly. Once + /// no more input is coming, state will be set to THR_FINISH. + uint8_t *in; + + /// Amount of data available in the input buffer. This is modified + /// only by the main thread. + size_t in_size; + + /// Output buffer for this thread. This is set by the main + /// thread every time a new Block is started with this thread + /// structure. + lzma_outbuf *outbuf; + + /// Pointer to the main structure is needed when putting this + /// thread back to the stack of free threads. + lzma_coder *coder; + + /// The allocator is set by the main thread. Since a copy of the + /// pointer is kept here, the application must not change the + /// allocator before calling lzma_end(). + const lzma_allocator *allocator; + + /// Amount of uncompressed data that has already been compressed. + uint64_t progress_in; + + /// Amount of compressed data that is ready. + uint64_t progress_out; + + /// Block encoder + lzma_next_coder block_encoder; + + /// Compression options for this Block + lzma_block block_options; + + /// Next structure in the stack of free worker threads. + worker_thread *next; + + mythread_mutex mutex; + mythread_cond cond; + + /// The ID of this thread is used to join the thread + /// when it's not needed anymore. + mythread thread_id; +}; + + +struct lzma_coder_s { + enum { + SEQ_STREAM_HEADER, + SEQ_BLOCK, + SEQ_INDEX, + SEQ_STREAM_FOOTER, + } sequence; + + /// Start a new Block every block_size bytes of input unless + /// LZMA_FULL_FLUSH or LZMA_FULL_BARRIER is used earlier. + size_t block_size; + + /// The filter chain currently in use + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + + + /// Index to hold sizes of the Blocks + lzma_index *index; + + /// Index encoder + lzma_next_coder index_encoder; + + + /// Stream Flags for encoding the Stream Header and Stream Footer. + lzma_stream_flags stream_flags; + + /// Buffer to hold Stream Header and Stream Footer. + uint8_t header[LZMA_STREAM_HEADER_SIZE]; + + /// Read position in header[] + size_t header_pos; + + + /// Output buffer queue for compressed data + lzma_outq outq; + + + /// Maximum wait time if cannot use all the input and cannot + /// fill the output buffer. This is in milliseconds. + uint32_t timeout; + + + /// Error code from a worker thread + lzma_ret thread_error; + + /// Array of allocated thread-specific structures + worker_thread *threads; + + /// Number of structures in "threads" above. This is also the + /// number of threads that will be created at maximum. + uint32_t threads_max; + + /// Number of thread structures that have been initialized, and + /// thus the number of worker threads actually created so far. + uint32_t threads_initialized; + + /// Stack of free threads. When a thread finishes, it puts itself + /// back into this stack. This starts as empty because threads + /// are created only when actually needed. + worker_thread *threads_free; + + /// The most recent worker thread to which the main thread writes + /// the new input from the application. + worker_thread *thr; + + + /// Amount of uncompressed data in Blocks that have already + /// been finished. + uint64_t progress_in; + + /// Amount of compressed data in Stream Header + Blocks that + /// have already been finished. + uint64_t progress_out; + + + mythread_mutex mutex; + mythread_cond cond; +}; + + +/// Tell the main thread that something has gone wrong. +static void +worker_error(worker_thread *thr, lzma_ret ret) +{ + assert(ret != LZMA_OK); + assert(ret != LZMA_STREAM_END); + + mythread_sync(thr->coder->mutex) { + if (thr->coder->thread_error == LZMA_OK) + thr->coder->thread_error = ret; + + mythread_cond_signal(&thr->coder->cond); + } + + return; +} + + +static worker_state +worker_encode(worker_thread *thr, worker_state state) +{ + assert(thr->progress_in == 0); + assert(thr->progress_out == 0); + + // Set the Block options. + thr->block_options = (lzma_block){ + .version = 0, + .check = thr->coder->stream_flags.check, + .compressed_size = thr->coder->outq.buf_size_max, + .uncompressed_size = thr->coder->block_size, + + // TODO: To allow changing the filter chain, the filters + // array must be copied to each worker_thread. + .filters = thr->coder->filters, + }; + + // Calculate maximum size of the Block Header. This amount is + // reserved in the beginning of the buffer so that Block Header + // along with Compressed Size and Uncompressed Size can be + // written there. + lzma_ret ret = lzma_block_header_size(&thr->block_options); + if (ret != LZMA_OK) { + worker_error(thr, ret); + return THR_STOP; + } + + // Initialize the Block encoder. + ret = lzma_block_encoder_init(&thr->block_encoder, + thr->allocator, &thr->block_options); + if (ret != LZMA_OK) { + worker_error(thr, ret); + return THR_STOP; + } + + size_t in_pos = 0; + size_t in_size = 0; + + thr->outbuf->size = thr->block_options.header_size; + const size_t out_size = thr->coder->outq.buf_size_max; + + do { + mythread_sync(thr->mutex) { + // Store in_pos and out_pos into *thr so that + // an application may read them via + // lzma_get_progress() to get progress information. + // + // NOTE: These aren't updated when the encoding + // finishes. Instead, the final values are taken + // later from thr->outbuf. + thr->progress_in = in_pos; + thr->progress_out = thr->outbuf->size; + + while (in_size == thr->in_size + && thr->state == THR_RUN) + mythread_cond_wait(&thr->cond, &thr->mutex); + + state = thr->state; + in_size = thr->in_size; + } + + // Return if we were asked to stop or exit. + if (state >= THR_STOP) + return state; + + lzma_action action = state == THR_FINISH + ? LZMA_FINISH : LZMA_RUN; + + // Limit the amount of input given to the Block encoder + // at once. This way this thread can react fairly quickly + // if the main thread wants us to stop or exit. + static const size_t in_chunk_max = 16384; + size_t in_limit = in_size; + if (in_size - in_pos > in_chunk_max) { + in_limit = in_pos + in_chunk_max; + action = LZMA_RUN; + } + + ret = thr->block_encoder.code( + thr->block_encoder.coder, thr->allocator, + thr->in, &in_pos, in_limit, thr->outbuf->buf, + &thr->outbuf->size, out_size, action); + } while (ret == LZMA_OK && thr->outbuf->size < out_size); + + switch (ret) { + case LZMA_STREAM_END: + assert(state == THR_FINISH); + + // Encode the Block Header. By doing it after + // the compression, we can store the Compressed Size + // and Uncompressed Size fields. + ret = lzma_block_header_encode(&thr->block_options, + thr->outbuf->buf); + if (ret != LZMA_OK) { + worker_error(thr, ret); + return THR_STOP; + } + + break; + + case LZMA_OK: + // The data was incompressible. Encode it using uncompressed + // LZMA2 chunks. + // + // First wait that we have gotten all the input. + mythread_sync(thr->mutex) { + while (thr->state == THR_RUN) + mythread_cond_wait(&thr->cond, &thr->mutex); + + state = thr->state; + in_size = thr->in_size; + } + + if (state >= THR_STOP) + return state; + + // Do the encoding. This takes care of the Block Header too. + thr->outbuf->size = 0; + ret = lzma_block_uncomp_encode(&thr->block_options, + thr->in, in_size, thr->outbuf->buf, + &thr->outbuf->size, out_size); + + // It shouldn't fail. + if (ret != LZMA_OK) { + worker_error(thr, LZMA_PROG_ERROR); + return THR_STOP; + } + + break; + + default: + worker_error(thr, ret); + return THR_STOP; + } + + // Set the size information that will be read by the main thread + // to write the Index field. + thr->outbuf->unpadded_size + = lzma_block_unpadded_size(&thr->block_options); + assert(thr->outbuf->unpadded_size != 0); + thr->outbuf->uncompressed_size = thr->block_options.uncompressed_size; + + return THR_FINISH; +} + + +static MYTHREAD_RET_TYPE +worker_start(void *thr_ptr) +{ + worker_thread *thr = thr_ptr; + worker_state state = THR_IDLE; // Init to silence a warning + + while (true) { + // Wait for work. + mythread_sync(thr->mutex) { + while (true) { + // The thread is already idle so if we are + // requested to stop, just set the state. + if (thr->state == THR_STOP) { + thr->state = THR_IDLE; + mythread_cond_signal(&thr->cond); + } + + state = thr->state; + if (state != THR_IDLE) + break; + + mythread_cond_wait(&thr->cond, &thr->mutex); + } + } + + assert(state != THR_IDLE); + assert(state != THR_STOP); + + if (state <= THR_FINISH) + state = worker_encode(thr, state); + + if (state == THR_EXIT) + break; + + // Mark the thread as idle unless the main thread has + // told us to exit. Signal is needed for the case + // where the main thread is waiting for the threads to stop. + mythread_sync(thr->mutex) { + if (thr->state != THR_EXIT) { + thr->state = THR_IDLE; + mythread_cond_signal(&thr->cond); + } + } + + mythread_sync(thr->coder->mutex) { + // Mark the output buffer as finished if + // no errors occurred. + thr->outbuf->finished = state == THR_FINISH; + + // Update the main progress info. + thr->coder->progress_in + += thr->outbuf->uncompressed_size; + thr->coder->progress_out += thr->outbuf->size; + thr->progress_in = 0; + thr->progress_out = 0; + + // Return this thread to the stack of free threads. + thr->next = thr->coder->threads_free; + thr->coder->threads_free = thr; + + mythread_cond_signal(&thr->coder->cond); + } + } + + // Exiting, free the resources. + mythread_mutex_destroy(&thr->mutex); + mythread_cond_destroy(&thr->cond); + + lzma_next_end(&thr->block_encoder, thr->allocator); + lzma_free(thr->in, thr->allocator); + return MYTHREAD_RET_VALUE; +} + + +/// Make the threads stop but not exit. Optionally wait for them to stop. +static void +threads_stop(lzma_coder *coder, bool wait_for_threads) +{ + // Tell the threads to stop. + for (uint32_t i = 0; i < coder->threads_initialized; ++i) { + mythread_sync(coder->threads[i].mutex) { + coder->threads[i].state = THR_STOP; + mythread_cond_signal(&coder->threads[i].cond); + } + } + + if (!wait_for_threads) + return; + + // Wait for the threads to settle in the idle state. + for (uint32_t i = 0; i < coder->threads_initialized; ++i) { + mythread_sync(coder->threads[i].mutex) { + while (coder->threads[i].state != THR_IDLE) + mythread_cond_wait(&coder->threads[i].cond, + &coder->threads[i].mutex); + } + } + + return; +} + + +/// Stop the threads and free the resources associated with them. +/// Wait until the threads have exited. +static void +threads_end(lzma_coder *coder, const lzma_allocator *allocator) +{ + for (uint32_t i = 0; i < coder->threads_initialized; ++i) { + mythread_sync(coder->threads[i].mutex) { + coder->threads[i].state = THR_EXIT; + mythread_cond_signal(&coder->threads[i].cond); + } + } + + for (uint32_t i = 0; i < coder->threads_initialized; ++i) { + int ret = mythread_join(coder->threads[i].thread_id); + assert(ret == 0); + (void)ret; + } + + lzma_free(coder->threads, allocator); + return; +} + + +/// Initialize a new worker_thread structure and create a new thread. +static lzma_ret +initialize_new_thread(lzma_coder *coder, const lzma_allocator *allocator) +{ + worker_thread *thr = &coder->threads[coder->threads_initialized]; + + thr->in = lzma_alloc(coder->block_size, allocator); + if (thr->in == NULL) + return LZMA_MEM_ERROR; + + if (mythread_mutex_init(&thr->mutex)) + goto error_mutex; + + if (mythread_cond_init(&thr->cond)) + goto error_cond; + + thr->state = THR_IDLE; + thr->allocator = allocator; + thr->coder = coder; + thr->progress_in = 0; + thr->progress_out = 0; + thr->block_encoder = LZMA_NEXT_CODER_INIT; + + if (mythread_create(&thr->thread_id, &worker_start, thr)) + goto error_thread; + + ++coder->threads_initialized; + coder->thr = thr; + + return LZMA_OK; + +error_thread: + mythread_cond_destroy(&thr->cond); + +error_cond: + mythread_mutex_destroy(&thr->mutex); + +error_mutex: + lzma_free(thr->in, allocator); + return LZMA_MEM_ERROR; +} + + +static lzma_ret +get_thread(lzma_coder *coder, const lzma_allocator *allocator) +{ + // If there are no free output subqueues, there is no + // point to try getting a thread. + if (!lzma_outq_has_buf(&coder->outq)) + return LZMA_OK; + + // If there is a free structure on the stack, use it. + mythread_sync(coder->mutex) { + if (coder->threads_free != NULL) { + coder->thr = coder->threads_free; + coder->threads_free = coder->threads_free->next; + } + } + + if (coder->thr == NULL) { + // If there are no uninitialized structures left, return. + if (coder->threads_initialized == coder->threads_max) + return LZMA_OK; + + // Initialize a new thread. + return_if_error(initialize_new_thread(coder, allocator)); + } + + // Reset the parts of the thread state that have to be done + // in the main thread. + mythread_sync(coder->thr->mutex) { + coder->thr->state = THR_RUN; + coder->thr->in_size = 0; + coder->thr->outbuf = lzma_outq_get_buf(&coder->outq); + mythread_cond_signal(&coder->thr->cond); + } + + return LZMA_OK; +} + + +static lzma_ret +stream_encode_in(lzma_coder *coder, const lzma_allocator *allocator, + const uint8_t *restrict in, size_t *restrict in_pos, + size_t in_size, lzma_action action) +{ + while (*in_pos < in_size + || (coder->thr != NULL && action != LZMA_RUN)) { + if (coder->thr == NULL) { + // Get a new thread. + const lzma_ret ret = get_thread(coder, allocator); + if (coder->thr == NULL) + return ret; + } + + // Copy the input data to thread's buffer. + size_t thr_in_size = coder->thr->in_size; + lzma_bufcpy(in, in_pos, in_size, coder->thr->in, + &thr_in_size, coder->block_size); + + // Tell the Block encoder to finish if + // - it has got block_size bytes of input; or + // - all input was used and LZMA_FINISH, LZMA_FULL_FLUSH, + // or LZMA_FULL_BARRIER was used. + // + // TODO: LZMA_SYNC_FLUSH and LZMA_SYNC_BARRIER. + const bool finish = thr_in_size == coder->block_size + || (*in_pos == in_size && action != LZMA_RUN); + + bool block_error = false; + + mythread_sync(coder->thr->mutex) { + if (coder->thr->state == THR_IDLE) { + // Something has gone wrong with the Block + // encoder. It has set coder->thread_error + // which we will read a few lines later. + block_error = true; + } else { + // Tell the Block encoder its new amount + // of input and update the state if needed. + coder->thr->in_size = thr_in_size; + + if (finish) + coder->thr->state = THR_FINISH; + + mythread_cond_signal(&coder->thr->cond); + } + } + + if (block_error) { + lzma_ret ret; + + mythread_sync(coder->mutex) { + ret = coder->thread_error; + } + + return ret; + } + + if (finish) + coder->thr = NULL; + } + + return LZMA_OK; +} + + +/// Wait until more input can be consumed, more output can be read, or +/// an optional timeout is reached. +static bool +wait_for_work(lzma_coder *coder, mythread_condtime *wait_abs, + bool *has_blocked, bool has_input) +{ + if (coder->timeout != 0 && !*has_blocked) { + // Every time when stream_encode_mt() is called via + // lzma_code(), *has_blocked starts as false. We set it + // to true here and calculate the absolute time when + // we must return if there's nothing to do. + // + // The idea of *has_blocked is to avoid unneeded calls + // to mythread_condtime_set(), which may do a syscall + // depending on the operating system. + *has_blocked = true; + mythread_condtime_set(wait_abs, &coder->cond, coder->timeout); + } + + bool timed_out = false; + + mythread_sync(coder->mutex) { + // There are four things that we wait. If one of them + // becomes possible, we return. + // - If there is input left, we need to get a free + // worker thread and an output buffer for it. + // - Data ready to be read from the output queue. + // - A worker thread indicates an error. + // - Time out occurs. + while ((!has_input || coder->threads_free == NULL + || !lzma_outq_has_buf(&coder->outq)) + && !lzma_outq_is_readable(&coder->outq) + && coder->thread_error == LZMA_OK + && !timed_out) { + if (coder->timeout != 0) + timed_out = mythread_cond_timedwait( + &coder->cond, &coder->mutex, + wait_abs) != 0; + else + mythread_cond_wait(&coder->cond, + &coder->mutex); + } + } + + return timed_out; +} + + +static lzma_ret +stream_encode_mt(lzma_coder *coder, const lzma_allocator *allocator, + const uint8_t *restrict in, size_t *restrict in_pos, + size_t in_size, uint8_t *restrict out, + size_t *restrict out_pos, size_t out_size, lzma_action action) +{ + switch (coder->sequence) { + case SEQ_STREAM_HEADER: + lzma_bufcpy(coder->header, &coder->header_pos, + sizeof(coder->header), + out, out_pos, out_size); + if (coder->header_pos < sizeof(coder->header)) + return LZMA_OK; + + coder->header_pos = 0; + coder->sequence = SEQ_BLOCK; + + // Fall through + + case SEQ_BLOCK: { + // Initialized to silence warnings. + lzma_vli unpadded_size = 0; + lzma_vli uncompressed_size = 0; + lzma_ret ret = LZMA_OK; + + // These are for wait_for_work(). + bool has_blocked = false; + mythread_condtime wait_abs; + + while (true) { + mythread_sync(coder->mutex) { + // Check for Block encoder errors. + ret = coder->thread_error; + if (ret != LZMA_OK) { + assert(ret != LZMA_STREAM_END); + break; + } + + // Try to read compressed data to out[]. + ret = lzma_outq_read(&coder->outq, + out, out_pos, out_size, + &unpadded_size, + &uncompressed_size); + } + + if (ret == LZMA_STREAM_END) { + // End of Block. Add it to the Index. + ret = lzma_index_append(coder->index, + allocator, unpadded_size, + uncompressed_size); + + // If we didn't fill the output buffer yet, + // try to read more data. Maybe the next + // outbuf has been finished already too. + if (*out_pos < out_size) + continue; + } + + if (ret != LZMA_OK) { + // coder->thread_error was set or + // lzma_index_append() failed. + threads_stop(coder, false); + return ret; + } + + // Try to give uncompressed data to a worker thread. + ret = stream_encode_in(coder, allocator, + in, in_pos, in_size, action); + if (ret != LZMA_OK) { + threads_stop(coder, false); + return ret; + } + + // See if we should wait or return. + // + // TODO: LZMA_SYNC_FLUSH and LZMA_SYNC_BARRIER. + if (*in_pos == in_size) { + // LZMA_RUN: More data is probably coming + // so return to let the caller fill the + // input buffer. + if (action == LZMA_RUN) + return LZMA_OK; + + // LZMA_FULL_BARRIER: The same as with + // LZMA_RUN but tell the caller that the + // barrier was completed. + if (action == LZMA_FULL_BARRIER) + return LZMA_STREAM_END; + + // Finishing or flushing isn't completed until + // all input data has been encoded and copied + // to the output buffer. + if (lzma_outq_is_empty(&coder->outq)) { + // LZMA_FINISH: Continue to encode + // the Index field. + if (action == LZMA_FINISH) + break; + + // LZMA_FULL_FLUSH: Return to tell + // the caller that flushing was + // completed. + if (action == LZMA_FULL_FLUSH) + return LZMA_STREAM_END; + } + } + + // Return if there is no output space left. + // This check must be done after testing the input + // buffer, because we might want to use a different + // return code. + if (*out_pos == out_size) + return LZMA_OK; + + // Neither in nor out has been used completely. + // Wait until there's something we can do. + if (wait_for_work(coder, &wait_abs, &has_blocked, + *in_pos < in_size)) + return LZMA_TIMED_OUT; + } + + // All Blocks have been encoded and the threads have stopped. + // Prepare to encode the Index field. + return_if_error(lzma_index_encoder_init( + &coder->index_encoder, allocator, + coder->index)); + coder->sequence = SEQ_INDEX; + + // Update the progress info to take the Index and + // Stream Footer into account. Those are very fast to encode + // so in terms of progress information they can be thought + // to be ready to be copied out. + coder->progress_out += lzma_index_size(coder->index) + + LZMA_STREAM_HEADER_SIZE; + } + + // Fall through + + case SEQ_INDEX: { + // Call the Index encoder. It doesn't take any input, so + // those pointers can be NULL. + const lzma_ret ret = coder->index_encoder.code( + coder->index_encoder.coder, allocator, + NULL, NULL, 0, + out, out_pos, out_size, LZMA_RUN); + if (ret != LZMA_STREAM_END) + return ret; + + // Encode the Stream Footer into coder->buffer. + coder->stream_flags.backward_size + = lzma_index_size(coder->index); + if (lzma_stream_footer_encode(&coder->stream_flags, + coder->header) != LZMA_OK) + return LZMA_PROG_ERROR; + + coder->sequence = SEQ_STREAM_FOOTER; + } + + // Fall through + + case SEQ_STREAM_FOOTER: + lzma_bufcpy(coder->header, &coder->header_pos, + sizeof(coder->header), + out, out_pos, out_size); + return coder->header_pos < sizeof(coder->header) + ? LZMA_OK : LZMA_STREAM_END; + } + + assert(0); + return LZMA_PROG_ERROR; +} + + +static void +stream_encoder_mt_end(lzma_coder *coder, const lzma_allocator *allocator) +{ + // Threads must be killed before the output queue can be freed. + threads_end(coder, allocator); + lzma_outq_end(&coder->outq, allocator); + + for (size_t i = 0; coder->filters[i].id != LZMA_VLI_UNKNOWN; ++i) + lzma_free(coder->filters[i].options, allocator); + + lzma_next_end(&coder->index_encoder, allocator); + lzma_index_end(coder->index, allocator); + + mythread_cond_destroy(&coder->cond); + mythread_mutex_destroy(&coder->mutex); + + lzma_free(coder, allocator); + return; +} + + +/// Options handling for lzma_stream_encoder_mt_init() and +/// lzma_stream_encoder_mt_memusage() +static lzma_ret +get_options(const lzma_mt *options, lzma_options_easy *opt_easy, + const lzma_filter **filters, uint64_t *block_size, + uint64_t *outbuf_size_max) +{ + // Validate some of the options. + if (options == NULL) + return LZMA_PROG_ERROR; + + if (options->flags != 0 || options->threads == 0 + || options->threads > LZMA_THREADS_MAX) + return LZMA_OPTIONS_ERROR; + + if (options->filters != NULL) { + // Filter chain was given, use it as is. + *filters = options->filters; + } else { + // Use a preset. + if (lzma_easy_preset(opt_easy, options->preset)) + return LZMA_OPTIONS_ERROR; + + *filters = opt_easy->filters; + } + + // Block size + if (options->block_size > 0) { + if (options->block_size > BLOCK_SIZE_MAX) + return LZMA_OPTIONS_ERROR; + + *block_size = options->block_size; + } else { + // Determine the Block size from the filter chain. + *block_size = lzma_mt_block_size(*filters); + if (*block_size == 0) + return LZMA_OPTIONS_ERROR; + + assert(*block_size <= BLOCK_SIZE_MAX); + } + + // Calculate the maximum amount output that a single output buffer + // may need to hold. This is the same as the maximum total size of + // a Block. + *outbuf_size_max = lzma_block_buffer_bound64(*block_size); + if (*outbuf_size_max == 0) + return LZMA_MEM_ERROR; + + return LZMA_OK; +} + + +static void +get_progress(lzma_coder *coder, uint64_t *progress_in, uint64_t *progress_out) +{ + // Lock coder->mutex to prevent finishing threads from moving their + // progress info from the worker_thread structure to lzma_coder. + mythread_sync(coder->mutex) { + *progress_in = coder->progress_in; + *progress_out = coder->progress_out; + + for (size_t i = 0; i < coder->threads_initialized; ++i) { + mythread_sync(coder->threads[i].mutex) { + *progress_in += coder->threads[i].progress_in; + *progress_out += coder->threads[i] + .progress_out; + } + } + } + + return; +} + + +static lzma_ret +stream_encoder_mt_init(lzma_next_coder *next, const lzma_allocator *allocator, + const lzma_mt *options) +{ + lzma_next_coder_init(&stream_encoder_mt_init, next, allocator); + + // Get the filter chain. + lzma_options_easy easy; + const lzma_filter *filters; + uint64_t block_size; + uint64_t outbuf_size_max; + return_if_error(get_options(options, &easy, &filters, + &block_size, &outbuf_size_max)); + +#if SIZE_MAX < UINT64_MAX + if (block_size > SIZE_MAX) + return LZMA_MEM_ERROR; +#endif + + // Validate the filter chain so that we can give an error in this + // function instead of delaying it to the first call to lzma_code(). + // The memory usage calculation verifies the filter chain as + // a side effect so we take advatange of that. + if (lzma_raw_encoder_memusage(filters) == UINT64_MAX) + return LZMA_OPTIONS_ERROR; + + // Validate the Check ID. + if ((unsigned int)(options->check) > LZMA_CHECK_ID_MAX) + return LZMA_PROG_ERROR; + + if (!lzma_check_is_supported(options->check)) + return LZMA_UNSUPPORTED_CHECK; + + // Allocate and initialize the base structure if needed. + if (next->coder == NULL) { + next->coder = lzma_alloc(sizeof(lzma_coder), allocator); + if (next->coder == NULL) + return LZMA_MEM_ERROR; + + // For the mutex and condition variable initializations + // the error handling has to be done here because + // stream_encoder_mt_end() doesn't know if they have + // already been initialized or not. + if (mythread_mutex_init(&next->coder->mutex)) { + lzma_free(next->coder, allocator); + next->coder = NULL; + return LZMA_MEM_ERROR; + } + + if (mythread_cond_init(&next->coder->cond)) { + mythread_mutex_destroy(&next->coder->mutex); + lzma_free(next->coder, allocator); + next->coder = NULL; + return LZMA_MEM_ERROR; + } + + next->code = &stream_encode_mt; + next->end = &stream_encoder_mt_end; + next->get_progress = &get_progress; +// next->update = &stream_encoder_mt_update; + + next->coder->filters[0].id = LZMA_VLI_UNKNOWN; + next->coder->index_encoder = LZMA_NEXT_CODER_INIT; + next->coder->index = NULL; + memzero(&next->coder->outq, sizeof(next->coder->outq)); + next->coder->threads = NULL; + next->coder->threads_max = 0; + next->coder->threads_initialized = 0; + } + + // Basic initializations + next->coder->sequence = SEQ_STREAM_HEADER; + next->coder->block_size = (size_t)(block_size); + next->coder->thread_error = LZMA_OK; + next->coder->thr = NULL; + + // Allocate the thread-specific base structures. + assert(options->threads > 0); + if (next->coder->threads_max != options->threads) { + threads_end(next->coder, allocator); + + next->coder->threads = NULL; + next->coder->threads_max = 0; + + next->coder->threads_initialized = 0; + next->coder->threads_free = NULL; + + next->coder->threads = lzma_alloc( + options->threads * sizeof(worker_thread), + allocator); + if (next->coder->threads == NULL) + return LZMA_MEM_ERROR; + + next->coder->threads_max = options->threads; + } else { + // Reuse the old structures and threads. Tell the running + // threads to stop and wait until they have stopped. + threads_stop(next->coder, true); + } + + // Output queue + return_if_error(lzma_outq_init(&next->coder->outq, allocator, + outbuf_size_max, options->threads)); + + // Timeout + next->coder->timeout = options->timeout; + + // Free the old filter chain and copy the new one. + for (size_t i = 0; next->coder->filters[i].id != LZMA_VLI_UNKNOWN; ++i) + lzma_free(next->coder->filters[i].options, allocator); + + return_if_error(lzma_filters_copy( + filters, next->coder->filters, allocator)); + + // Index + lzma_index_end(next->coder->index, allocator); + next->coder->index = lzma_index_init(allocator); + if (next->coder->index == NULL) + return LZMA_MEM_ERROR; + + // Stream Header + next->coder->stream_flags.version = 0; + next->coder->stream_flags.check = options->check; + return_if_error(lzma_stream_header_encode( + &next->coder->stream_flags, next->coder->header)); + + next->coder->header_pos = 0; + + // Progress info + next->coder->progress_in = 0; + next->coder->progress_out = LZMA_STREAM_HEADER_SIZE; + + return LZMA_OK; +} + + +extern LZMA_API(lzma_ret) +lzma_stream_encoder_mt(lzma_stream *strm, const lzma_mt *options) +{ + lzma_next_strm_init(stream_encoder_mt_init, strm, options); + + strm->internal->supported_actions[LZMA_RUN] = true; +// strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; + strm->internal->supported_actions[LZMA_FULL_FLUSH] = true; + strm->internal->supported_actions[LZMA_FULL_BARRIER] = true; + strm->internal->supported_actions[LZMA_FINISH] = true; + + return LZMA_OK; +} + + +// This function name is a monster but it's consistent with the older +// monster names. :-( 31 chars is the max that C99 requires so in that +// sense it's not too long. ;-) +extern LZMA_API(uint64_t) +lzma_stream_encoder_mt_memusage(const lzma_mt *options) +{ + lzma_options_easy easy; + const lzma_filter *filters; + uint64_t block_size; + uint64_t outbuf_size_max; + + if (get_options(options, &easy, &filters, &block_size, + &outbuf_size_max) != LZMA_OK) + return UINT64_MAX; + + // Memory usage of the input buffers + const uint64_t inbuf_memusage = options->threads * block_size; + + // Memory usage of the filter encoders + uint64_t filters_memusage = lzma_raw_encoder_memusage(filters); + if (filters_memusage == UINT64_MAX) + return UINT64_MAX; + + filters_memusage *= options->threads; + + // Memory usage of the output queue + const uint64_t outq_memusage = lzma_outq_memusage( + outbuf_size_max, options->threads); + if (outq_memusage == UINT64_MAX) + return UINT64_MAX; + + // Sum them with overflow checking. + uint64_t total_memusage = LZMA_MEMUSAGE_BASE + sizeof(lzma_coder) + + options->threads * sizeof(worker_thread); + + if (UINT64_MAX - total_memusage < inbuf_memusage) + return UINT64_MAX; + + total_memusage += inbuf_memusage; + + if (UINT64_MAX - total_memusage < filters_memusage) + return UINT64_MAX; + + total_memusage += filters_memusage; + + if (UINT64_MAX - total_memusage < outq_memusage) + return UINT64_MAX; + + return total_memusage + outq_memusage; +} diff --git a/src/liblzma/delta/delta_common.c b/src/liblzma/delta/delta_common.c index 930ad215131c..13dd46828d87 100644 --- a/src/liblzma/delta/delta_common.c +++ b/src/liblzma/delta/delta_common.c @@ -15,7 +15,7 @@ static void -delta_coder_end(lzma_coder *coder, lzma_allocator *allocator) +delta_coder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); @@ -24,7 +24,7 @@ delta_coder_end(lzma_coder *coder, lzma_allocator *allocator) extern lzma_ret -lzma_delta_coder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_delta_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters) { // Allocate memory for the decoder if needed. diff --git a/src/liblzma/delta/delta_decoder.c b/src/liblzma/delta/delta_decoder.c index 2cf60d5bdc7c..726d023991c0 100644 --- a/src/liblzma/delta/delta_decoder.c +++ b/src/liblzma/delta/delta_decoder.c @@ -27,7 +27,7 @@ decode_buffer(lzma_coder *coder, uint8_t *buffer, size_t size) static lzma_ret -delta_decode(lzma_coder *coder, lzma_allocator *allocator, +delta_decode(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, lzma_action action) @@ -47,7 +47,7 @@ delta_decode(lzma_coder *coder, lzma_allocator *allocator, extern lzma_ret -lzma_delta_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_delta_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters) { next->code = &delta_decode; @@ -56,7 +56,7 @@ lzma_delta_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, extern lzma_ret -lzma_delta_props_decode(void **options, lzma_allocator *allocator, +lzma_delta_props_decode(void **options, const lzma_allocator *allocator, const uint8_t *props, size_t props_size) { if (props_size != 1) diff --git a/src/liblzma/delta/delta_decoder.h b/src/liblzma/delta/delta_decoder.h index ae89acc59f8c..ad89cc659764 100644 --- a/src/liblzma/delta/delta_decoder.h +++ b/src/liblzma/delta/delta_decoder.h @@ -16,10 +16,11 @@ #include "delta_common.h" extern lzma_ret lzma_delta_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_delta_props_decode( - void **options, lzma_allocator *allocator, + void **options, const lzma_allocator *allocator, const uint8_t *props, size_t props_size); #endif diff --git a/src/liblzma/delta/delta_encoder.c b/src/liblzma/delta/delta_encoder.c index 15c7951e104a..5a842636ba1b 100644 --- a/src/liblzma/delta/delta_encoder.c +++ b/src/liblzma/delta/delta_encoder.c @@ -49,7 +49,7 @@ encode_in_place(lzma_coder *coder, uint8_t *buffer, size_t size) static lzma_ret -delta_encode(lzma_coder *coder, lzma_allocator *allocator, +delta_encode(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, lzma_action action) @@ -84,7 +84,7 @@ delta_encode(lzma_coder *coder, lzma_allocator *allocator, static lzma_ret -delta_encoder_update(lzma_coder *coder, lzma_allocator *allocator, +delta_encoder_update(lzma_coder *coder, const lzma_allocator *allocator, const lzma_filter *filters_null lzma_attribute((__unused__)), const lzma_filter *reversed_filters) { @@ -97,7 +97,7 @@ delta_encoder_update(lzma_coder *coder, lzma_allocator *allocator, extern lzma_ret -lzma_delta_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_delta_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters) { next->code = &delta_encode; diff --git a/src/liblzma/delta/delta_encoder.h b/src/liblzma/delta/delta_encoder.h index a447862f205b..4ab984785171 100644 --- a/src/liblzma/delta/delta_encoder.h +++ b/src/liblzma/delta/delta_encoder.h @@ -16,7 +16,8 @@ #include "delta_common.h" extern lzma_ret lzma_delta_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_delta_props_encode(const void *options, uint8_t *out); diff --git a/src/liblzma/delta/delta_private.h b/src/liblzma/delta/delta_private.h index 62b7fed86e45..46ce0c645091 100644 --- a/src/liblzma/delta/delta_private.h +++ b/src/liblzma/delta/delta_private.h @@ -31,7 +31,7 @@ struct lzma_coder_s { extern lzma_ret lzma_delta_coder_init( - lzma_next_coder *next, lzma_allocator *allocator, + lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters); #endif diff --git a/src/liblzma/liblzma.map b/src/liblzma/liblzma.map new file mode 100644 index 000000000000..f53a4ea30a3c --- /dev/null +++ b/src/liblzma/liblzma.map @@ -0,0 +1,108 @@ +XZ_5.0 { +global: + lzma_alone_decoder; + lzma_alone_encoder; + lzma_auto_decoder; + lzma_block_buffer_bound; + lzma_block_buffer_decode; + lzma_block_buffer_encode; + lzma_block_compressed_size; + lzma_block_decoder; + lzma_block_encoder; + lzma_block_header_decode; + lzma_block_header_encode; + lzma_block_header_size; + lzma_block_total_size; + lzma_block_unpadded_size; + lzma_check_is_supported; + lzma_check_size; + lzma_code; + lzma_crc32; + lzma_crc64; + lzma_easy_buffer_encode; + lzma_easy_decoder_memusage; + lzma_easy_encoder; + lzma_easy_encoder_memusage; + lzma_end; + lzma_filter_decoder_is_supported; + lzma_filter_encoder_is_supported; + lzma_filter_flags_decode; + lzma_filter_flags_encode; + lzma_filter_flags_size; + lzma_filters_copy; + lzma_filters_update; + lzma_get_check; + lzma_index_append; + lzma_index_block_count; + lzma_index_buffer_decode; + lzma_index_buffer_encode; + lzma_index_cat; + lzma_index_checks; + lzma_index_decoder; + lzma_index_dup; + lzma_index_encoder; + lzma_index_end; + lzma_index_file_size; + lzma_index_hash_append; + lzma_index_hash_decode; + lzma_index_hash_end; + lzma_index_hash_init; + lzma_index_hash_size; + lzma_index_init; + lzma_index_iter_init; + lzma_index_iter_locate; + lzma_index_iter_next; + lzma_index_iter_rewind; + lzma_index_memusage; + lzma_index_memused; + lzma_index_size; + lzma_index_stream_count; + lzma_index_stream_flags; + lzma_index_stream_padding; + lzma_index_stream_size; + lzma_index_total_size; + lzma_index_uncompressed_size; + lzma_lzma_preset; + lzma_memlimit_get; + lzma_memlimit_set; + lzma_memusage; + lzma_mf_is_supported; + lzma_mode_is_supported; + lzma_physmem; + lzma_properties_decode; + lzma_properties_encode; + lzma_properties_size; + lzma_raw_buffer_decode; + lzma_raw_buffer_encode; + lzma_raw_decoder; + lzma_raw_decoder_memusage; + lzma_raw_encoder; + lzma_raw_encoder_memusage; + lzma_stream_buffer_bound; + lzma_stream_buffer_decode; + lzma_stream_buffer_encode; + lzma_stream_decoder; + lzma_stream_encoder; + lzma_stream_flags_compare; + lzma_stream_footer_decode; + lzma_stream_footer_encode; + lzma_stream_header_decode; + lzma_stream_header_encode; + lzma_version_number; + lzma_version_string; + lzma_vli_decode; + lzma_vli_encode; + lzma_vli_size; +}; + +XZ_5.2 { +global: + lzma_block_uncomp_encode; + lzma_cputhreads; + lzma_get_progress; + lzma_stream_encoder_mt; + lzma_stream_encoder_mt_memusage; + +local: + *; +} XZ_5.0; diff --git a/src/liblzma/liblzma.pc.in b/src/liblzma/liblzma.pc.in index 7f11f1a2009e..9fa489115a0a 100644 --- a/src/liblzma/liblzma.pc.in +++ b/src/liblzma/liblzma.pc.in @@ -16,4 +16,4 @@ URL: @PACKAGE_URL@ Version: @PACKAGE_VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -llzma -Libs.private: @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ +Libs.private: @PTHREAD_CFLAGS@ @LIBS@ diff --git a/src/liblzma/lz/lz_decoder.c b/src/liblzma/lz/lz_decoder.c index d74085cf4471..2328a8e73f07 100644 --- a/src/liblzma/lz/lz_decoder.c +++ b/src/liblzma/lz/lz_decoder.c @@ -126,7 +126,7 @@ decode_buffer(lzma_coder *coder, static lzma_ret lz_decode(lzma_coder *coder, - lzma_allocator *allocator lzma_attribute((__unused__)), + const lzma_allocator *allocator lzma_attribute((__unused__)), const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, @@ -184,7 +184,7 @@ lz_decode(lzma_coder *coder, static void -lz_decoder_end(lzma_coder *coder, lzma_allocator *allocator) +lz_decoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->next, allocator); lzma_free(coder->dict.buf, allocator); @@ -200,10 +200,10 @@ lz_decoder_end(lzma_coder *coder, lzma_allocator *allocator) extern lzma_ret -lzma_lz_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters, lzma_ret (*lz_init)(lzma_lz_decoder *lz, - lzma_allocator *allocator, const void *options, + const lzma_allocator *allocator, const void *options, lzma_lz_options *lz_options)) { // Allocate the base structure if it isn't already allocated. diff --git a/src/liblzma/lz/lz_decoder.h b/src/liblzma/lz/lz_decoder.h index 7266e803165f..277900afb714 100644 --- a/src/liblzma/lz/lz_decoder.h +++ b/src/liblzma/lz/lz_decoder.h @@ -67,7 +67,7 @@ typedef struct { lzma_vli uncompressed_size); /// Free allocated resources - void (*end)(lzma_coder *coder, lzma_allocator *allocator); + void (*end)(lzma_coder *coder, const lzma_allocator *allocator); } lzma_lz_decoder; @@ -83,9 +83,10 @@ typedef struct { extern lzma_ret lzma_lz_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters, + const lzma_allocator *allocator, + const lzma_filter_info *filters, lzma_ret (*lz_init)(lzma_lz_decoder *lz, - lzma_allocator *allocator, const void *options, + const lzma_allocator *allocator, const void *options, lzma_lz_options *lz_options)); extern uint64_t lzma_lz_decoder_memusage(size_t dictionary_size); diff --git a/src/liblzma/lz/lz_encoder.c b/src/liblzma/lz/lz_encoder.c index e2406965882c..2033844f5d35 100644 --- a/src/liblzma/lz/lz_encoder.c +++ b/src/liblzma/lz/lz_encoder.c @@ -20,6 +20,8 @@ # include "lz_encoder_hash_table.h" #endif +#include "memcmplen.h" + struct lzma_coder_s { /// LZ-based encoder e.g. LZMA @@ -76,8 +78,9 @@ move_window(lzma_mf *mf) /// This function must not be called once it has returned LZMA_STREAM_END. /// static lzma_ret -fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in, - size_t *in_pos, size_t in_size, lzma_action action) +fill_window(lzma_coder *coder, const lzma_allocator *allocator, + const uint8_t *in, size_t *in_pos, size_t in_size, + lzma_action action) { assert(coder->mf.read_pos <= coder->mf.write_pos); @@ -148,7 +151,7 @@ fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in, static lzma_ret -lz_encode(lzma_coder *coder, lzma_allocator *allocator, +lz_encode(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, @@ -179,7 +182,7 @@ lz_encode(lzma_coder *coder, lzma_allocator *allocator, static bool -lz_encoder_prepare(lzma_mf *mf, lzma_allocator *allocator, +lz_encoder_prepare(lzma_mf *mf, const lzma_allocator *allocator, const lzma_lz_options *lz_options) { // For now, the dictionary size is limited to 1.5 GiB. This may grow @@ -325,25 +328,22 @@ lz_encoder_prepare(lzma_mf *mf, lzma_allocator *allocator, hs += HASH_4_SIZE; */ - // If the above code calculating hs is modified, make sure that - // this assertion stays valid (UINT32_MAX / 5 is not strictly the - // exact limit). If it doesn't, you need to calculate that - // hash_size_sum + sons_count cannot overflow. - assert(hs < UINT32_MAX / 5); - - const uint32_t old_count = mf->hash_size_sum + mf->sons_count; - mf->hash_size_sum = hs; + const uint32_t old_hash_count = mf->hash_count; + const uint32_t old_sons_count = mf->sons_count; + mf->hash_count = hs; mf->sons_count = mf->cyclic_size; if (is_bt) mf->sons_count *= 2; - const uint32_t new_count = mf->hash_size_sum + mf->sons_count; - // Deallocate the old hash array if it exists and has different size // than what is needed now. - if (old_count != new_count) { + if (old_hash_count != mf->hash_count + || old_sons_count != mf->sons_count) { lzma_free(mf->hash, allocator); mf->hash = NULL; + + lzma_free(mf->son, allocator); + mf->son = NULL; } // Maximum number of match finder cycles @@ -360,14 +360,23 @@ lz_encoder_prepare(lzma_mf *mf, lzma_allocator *allocator, static bool -lz_encoder_init(lzma_mf *mf, lzma_allocator *allocator, +lz_encoder_init(lzma_mf *mf, const lzma_allocator *allocator, const lzma_lz_options *lz_options) { // Allocate the history buffer. if (mf->buffer == NULL) { - mf->buffer = lzma_alloc(mf->size, allocator); + // lzma_memcmplen() is used for the dictionary buffer + // so we need to allocate a few extra bytes to prevent + // it from reading past the end of the buffer. + mf->buffer = lzma_alloc(mf->size + LZMA_MEMCMPLEN_EXTRA, + allocator); if (mf->buffer == NULL) return true; + + // Keep Valgrind happy with lzma_memcmplen() and initialize + // the extra bytes whose value may get read but which will + // effectively get ignored. + memzero(mf->buffer + mf->size, LZMA_MEMCMPLEN_EXTRA); } // Use cyclic_size as initial mf->offset. This allows @@ -381,44 +390,49 @@ lz_encoder_init(lzma_mf *mf, lzma_allocator *allocator, mf->write_pos = 0; mf->pending = 0; - // Allocate match finder's hash array. - const size_t alloc_count = mf->hash_size_sum + mf->sons_count; - #if UINT32_MAX >= SIZE_MAX / 4 // Check for integer overflow. (Huge dictionaries are not // possible on 32-bit CPU.) - if (alloc_count > SIZE_MAX / sizeof(uint32_t)) + if (mf->hash_count > SIZE_MAX / sizeof(uint32_t) + || mf->sons_count > SIZE_MAX / sizeof(uint32_t)) return true; #endif + // Allocate and initialize the hash table. Since EMPTY_HASH_VALUE + // is zero, we can use lzma_alloc_zero() or memzero() for mf->hash. + // + // We don't need to initialize mf->son, but not doing that may + // make Valgrind complain in normalization (see normalize() in + // lz_encoder_mf.c). Skipping the initialization is *very* good + // when big dictionary is used but only small amount of data gets + // actually compressed: most of the mf->son won't get actually + // allocated by the kernel, so we avoid wasting RAM and improve + // initialization speed a lot. if (mf->hash == NULL) { - mf->hash = lzma_alloc(alloc_count * sizeof(uint32_t), + mf->hash = lzma_alloc_zero(mf->hash_count * sizeof(uint32_t), allocator); - if (mf->hash == NULL) + mf->son = lzma_alloc(mf->sons_count * sizeof(uint32_t), + allocator); + + if (mf->hash == NULL || mf->son == NULL) { + lzma_free(mf->hash, allocator); + mf->hash = NULL; + + lzma_free(mf->son, allocator); + mf->son = NULL; + return true; + } + } else { +/* + for (uint32_t i = 0; i < mf->hash_count; ++i) + mf->hash[i] = EMPTY_HASH_VALUE; +*/ + memzero(mf->hash, mf->hash_count * sizeof(uint32_t)); } - mf->son = mf->hash + mf->hash_size_sum; mf->cyclic_pos = 0; - // Initialize the hash table. Since EMPTY_HASH_VALUE is zero, we - // can use memset(). -/* - for (uint32_t i = 0; i < hash_size_sum; ++i) - mf->hash[i] = EMPTY_HASH_VALUE; -*/ - memzero(mf->hash, (size_t)(mf->hash_size_sum) * sizeof(uint32_t)); - - // We don't need to initialize mf->son, but not doing that will - // make Valgrind complain in normalization (see normalize() in - // lz_encoder_mf.c). - // - // Skipping this initialization is *very* good when big dictionary is - // used but only small amount of data gets actually compressed: most - // of the mf->hash won't get actually allocated by the kernel, so - // we avoid wasting RAM and improve initialization speed a lot. - //memzero(mf->son, (size_t)(mf->sons_count) * sizeof(uint32_t)); - // Handle preset dictionary. if (lz_options->preset_dict != NULL && lz_options->preset_dict_size > 0) { @@ -445,7 +459,8 @@ lzma_lz_encoder_memusage(const lzma_lz_options *lz_options) lzma_mf mf = { .buffer = NULL, .hash = NULL, - .hash_size_sum = 0, + .son = NULL, + .hash_count = 0, .sons_count = 0, }; @@ -454,17 +469,17 @@ lzma_lz_encoder_memusage(const lzma_lz_options *lz_options) return UINT64_MAX; // Calculate the memory usage. - return (uint64_t)(mf.hash_size_sum + mf.sons_count) - * sizeof(uint32_t) - + (uint64_t)(mf.size) + sizeof(lzma_coder); + return ((uint64_t)(mf.hash_count) + mf.sons_count) * sizeof(uint32_t) + + mf.size + sizeof(lzma_coder); } static void -lz_encoder_end(lzma_coder *coder, lzma_allocator *allocator) +lz_encoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->next, allocator); + lzma_free(coder->mf.son, allocator); lzma_free(coder->mf.hash, allocator); lzma_free(coder->mf.buffer, allocator); @@ -479,7 +494,7 @@ lz_encoder_end(lzma_coder *coder, lzma_allocator *allocator) static lzma_ret -lz_encoder_update(lzma_coder *coder, lzma_allocator *allocator, +lz_encoder_update(lzma_coder *coder, const lzma_allocator *allocator, const lzma_filter *filters_null lzma_attribute((__unused__)), const lzma_filter *reversed_filters) { @@ -495,10 +510,10 @@ lz_encoder_update(lzma_coder *coder, lzma_allocator *allocator, extern lzma_ret -lzma_lz_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_lz_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters, lzma_ret (*lz_init)(lzma_lz_encoder *lz, - lzma_allocator *allocator, const void *options, + const lzma_allocator *allocator, const void *options, lzma_lz_options *lz_options)) { #ifdef HAVE_SMALL @@ -522,7 +537,8 @@ lzma_lz_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, next->coder->mf.buffer = NULL; next->coder->mf.hash = NULL; - next->coder->mf.hash_size_sum = 0; + next->coder->mf.son = NULL; + next->coder->mf.hash_count = 0; next->coder->mf.sons_count = 0; next->coder->next = LZMA_NEXT_CODER_INIT; diff --git a/src/liblzma/lz/lz_encoder.h b/src/liblzma/lz/lz_encoder.h index 741c4532280d..dad9c6b29980 100644 --- a/src/liblzma/lz/lz_encoder.h +++ b/src/liblzma/lz/lz_encoder.h @@ -119,7 +119,7 @@ struct lzma_mf_s { lzma_action action; /// Number of elements in hash[] - uint32_t hash_size_sum; + uint32_t hash_count; /// Number of elements in son[] uint32_t sons_count; @@ -199,7 +199,7 @@ typedef struct { size_t *restrict out_pos, size_t out_size); /// Free allocated resources - void (*end)(lzma_coder *coder, lzma_allocator *allocator); + void (*end)(lzma_coder *coder, const lzma_allocator *allocator); /// Update the options in the middle of the encoding. lzma_ret (*options_update)(lzma_coder *coder, @@ -296,10 +296,10 @@ mf_read(lzma_mf *mf, uint8_t *out, size_t *out_pos, size_t out_size, extern lzma_ret lzma_lz_encoder_init( - lzma_next_coder *next, lzma_allocator *allocator, + lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters, lzma_ret (*lz_init)(lzma_lz_encoder *lz, - lzma_allocator *allocator, const void *options, + const lzma_allocator *allocator, const void *options, lzma_lz_options *lz_options)); diff --git a/src/liblzma/lz/lz_encoder_mf.c b/src/liblzma/lz/lz_encoder_mf.c index f82a1c1d2959..78520779f1b6 100644 --- a/src/liblzma/lz/lz_encoder_mf.c +++ b/src/liblzma/lz/lz_encoder_mf.c @@ -13,6 +13,7 @@ #include "lz_encoder.h" #include "lz_encoder_hash.h" +#include "memcmplen.h" /// \brief Find matches starting from the current byte @@ -65,9 +66,7 @@ lzma_mf_find(lzma_mf *mf, uint32_t *count_ptr, lzma_match *matches) // here because the match distances are zero based. const uint8_t *p2 = p1 - matches[count - 1].dist - 1; - while (len_best < limit - && p1[len_best] == p2[len_best]) - ++len_best; + len_best = lzma_memcmplen(p1, p2, len_best, limit); } } @@ -116,24 +115,27 @@ normalize(lzma_mf *mf) = (MUST_NORMALIZE_POS - mf->cyclic_size); // & (~(UINT32_C(1) << 10) - 1); - const uint32_t count = mf->hash_size_sum + mf->sons_count; - uint32_t *hash = mf->hash; - - for (uint32_t i = 0; i < count; ++i) { + for (uint32_t i = 0; i < mf->hash_count; ++i) { // If the distance is greater than the dictionary size, // we can simply mark the hash element as empty. - // - // NOTE: Only the first mf->hash_size_sum elements are - // initialized for sure. There may be uninitialized elements - // in mf->son. Since we go through both mf->hash and - // mf->son here in normalization, Valgrind may complain - // that the "if" below depends on uninitialized value. In - // this case it is safe to ignore the warning. See also the - // comments in lz_encoder_init() in lz_encoder.c. - if (hash[i] <= subvalue) - hash[i] = EMPTY_HASH_VALUE; + if (mf->hash[i] <= subvalue) + mf->hash[i] = EMPTY_HASH_VALUE; else - hash[i] -= subvalue; + mf->hash[i] -= subvalue; + } + + for (uint32_t i = 0; i < mf->sons_count; ++i) { + // Do the same for mf->son. + // + // NOTE: There may be uninitialized elements in mf->son. + // Valgrind may complain that the "if" below depends on + // an uninitialized value. In this case it is safe to ignore + // the warning. See also the comments in lz_encoder_init() + // in lz_encoder.c. + if (mf->son[i] <= subvalue) + mf->son[i] = EMPTY_HASH_VALUE; + else + mf->son[i] -= subvalue; } // Update offset to match the new locations. @@ -269,10 +271,7 @@ hc_find_func( + (delta > cyclic_pos ? cyclic_size : 0)]; if (pb[len_best] == cur[len_best] && pb[0] == cur[0]) { - uint32_t len = 0; - while (++len != len_limit) - if (pb[len] != cur[len]) - break; + uint32_t len = lzma_memcmplen(pb, cur, 1, len_limit); if (len_best < len) { len_best = len; @@ -318,9 +317,8 @@ lzma_mf_hc3_find(lzma_mf *mf, lzma_match *matches) uint32_t len_best = 2; if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) { - for ( ; len_best != len_limit; ++len_best) - if (*(cur + len_best - delta2) != cur[len_best]) - break; + len_best = lzma_memcmplen(cur - delta2, cur, + len_best, len_limit); matches[0].len = len_best; matches[0].dist = delta2 - 1; @@ -397,9 +395,8 @@ lzma_mf_hc4_find(lzma_mf *mf, lzma_match *matches) } if (matches_count != 0) { - for ( ; len_best != len_limit; ++len_best) - if (*(cur + len_best - delta2) != cur[len_best]) - break; + len_best = lzma_memcmplen(cur - delta2, cur, + len_best, len_limit); matches[matches_count - 1].len = len_best; @@ -484,9 +481,7 @@ bt_find_func( uint32_t len = my_min(len0, len1); if (pb[len] == cur[len]) { - while (++len != len_limit) - if (pb[len] != cur[len]) - break; + len = lzma_memcmplen(pb, cur, len + 1, len_limit); if (len_best < len) { len_best = len; @@ -549,9 +544,7 @@ bt_skip_func( uint32_t len = my_min(len0, len1); if (pb[len] == cur[len]) { - while (++len != len_limit) - if (pb[len] != cur[len]) - break; + len = lzma_memcmplen(pb, cur, len + 1, len_limit); if (len == len_limit) { *ptr1 = pair[0]; @@ -639,9 +632,8 @@ lzma_mf_bt3_find(lzma_mf *mf, lzma_match *matches) uint32_t len_best = 2; if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) { - for ( ; len_best != len_limit; ++len_best) - if (*(cur + len_best - delta2) != cur[len_best]) - break; + len_best = lzma_memcmplen( + cur, cur - delta2, len_best, len_limit); matches[0].len = len_best; matches[0].dist = delta2 - 1; @@ -712,9 +704,8 @@ lzma_mf_bt4_find(lzma_mf *mf, lzma_match *matches) } if (matches_count != 0) { - for ( ; len_best != len_limit; ++len_best) - if (*(cur + len_best - delta2) != cur[len_best]) - break; + len_best = lzma_memcmplen( + cur, cur - delta2, len_best, len_limit); matches[matches_count - 1].len = len_best; diff --git a/src/liblzma/lzma/fastpos.h b/src/liblzma/lzma/fastpos.h index 4aea23181ab6..a3feea58d8d3 100644 --- a/src/liblzma/lzma/fastpos.h +++ b/src/liblzma/lzma/fastpos.h @@ -14,15 +14,15 @@ #ifndef LZMA_FASTPOS_H #define LZMA_FASTPOS_H -// LZMA encodes match distances (positions) by storing the highest two -// bits using a six-bit value [0, 63], and then the missing lower bits. -// Dictionary size is also stored using this encoding in the new .lzma +// LZMA encodes match distances by storing the highest two bits using +// a six-bit value [0, 63], and then the missing lower bits. +// Dictionary size is also stored using this encoding in the .xz // file format header. // // fastpos.h provides a way to quickly find out the correct six-bit // values. The following table gives some examples of this encoding: // -// pos return +// dist return // 0 0 // 1 1 // 2 2 @@ -48,10 +48,10 @@ // Provided functions or macros // ---------------------------- // -// get_pos_slot(pos) is the basic version. get_pos_slot_2(pos) -// assumes that pos >= FULL_DISTANCES, thus the result is at least -// FULL_DISTANCES_BITS * 2. Using get_pos_slot(pos) instead of -// get_pos_slot_2(pos) would give the same result, but get_pos_slot_2(pos) +// get_dist_slot(dist) is the basic version. get_dist_slot_2(dist) +// assumes that dist >= FULL_DISTANCES, thus the result is at least +// FULL_DISTANCES_BITS * 2. Using get_dist_slot(dist) instead of +// get_dist_slot_2(dist) would give the same result, but get_dist_slot_2(dist) // should be tiny bit faster due to the assumption being made. // // @@ -76,13 +76,14 @@ // slightly faster, but sometimes it is a lot slower. #ifdef HAVE_SMALL -# define get_pos_slot(pos) ((pos) <= 4 ? (pos) : get_pos_slot_2(pos)) +# define get_dist_slot(dist) \ + ((dist) <= 4 ? (dist) : get_dist_slot_2(dist)) static inline uint32_t -get_pos_slot_2(uint32_t pos) +get_dist_slot_2(uint32_t dist) { - const uint32_t i = bsr32(pos); - return (i + i) + ((pos >> (i - 1)) & 1); + const uint32_t i = bsr32(dist); + return (i + i) + ((dist >> (i - 1)) & 1); } @@ -99,39 +100,39 @@ extern const uint8_t lzma_fastpos[1 << FASTPOS_BITS]; #define fastpos_limit(extra, n) \ (UINT32_C(1) << (FASTPOS_BITS + fastpos_shift(extra, n))) -#define fastpos_result(pos, extra, n) \ - lzma_fastpos[(pos) >> fastpos_shift(extra, n)] \ +#define fastpos_result(dist, extra, n) \ + lzma_fastpos[(dist) >> fastpos_shift(extra, n)] \ + 2 * fastpos_shift(extra, n) static inline uint32_t -get_pos_slot(uint32_t pos) +get_dist_slot(uint32_t dist) { // If it is small enough, we can pick the result directly from // the precalculated table. - if (pos < fastpos_limit(0, 0)) - return lzma_fastpos[pos]; + if (dist < fastpos_limit(0, 0)) + return lzma_fastpos[dist]; - if (pos < fastpos_limit(0, 1)) - return fastpos_result(pos, 0, 1); + if (dist < fastpos_limit(0, 1)) + return fastpos_result(dist, 0, 1); - return fastpos_result(pos, 0, 2); + return fastpos_result(dist, 0, 2); } #ifdef FULL_DISTANCES_BITS static inline uint32_t -get_pos_slot_2(uint32_t pos) +get_dist_slot_2(uint32_t dist) { - assert(pos >= FULL_DISTANCES); + assert(dist >= FULL_DISTANCES); - if (pos < fastpos_limit(FULL_DISTANCES_BITS - 1, 0)) - return fastpos_result(pos, FULL_DISTANCES_BITS - 1, 0); + if (dist < fastpos_limit(FULL_DISTANCES_BITS - 1, 0)) + return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 0); - if (pos < fastpos_limit(FULL_DISTANCES_BITS - 1, 1)) - return fastpos_result(pos, FULL_DISTANCES_BITS - 1, 1); + if (dist < fastpos_limit(FULL_DISTANCES_BITS - 1, 1)) + return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 1); - return fastpos_result(pos, FULL_DISTANCES_BITS - 1, 2); + return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 2); } #endif diff --git a/src/liblzma/lzma/lzma2_decoder.c b/src/liblzma/lzma/lzma2_decoder.c index 3e42575d5b80..84982d2c4286 100644 --- a/src/liblzma/lzma/lzma2_decoder.c +++ b/src/liblzma/lzma/lzma2_decoder.c @@ -209,7 +209,7 @@ lzma2_decode(lzma_coder *restrict coder, lzma_dict *restrict dict, static void -lzma2_decoder_end(lzma_coder *coder, lzma_allocator *allocator) +lzma2_decoder_end(lzma_coder *coder, const lzma_allocator *allocator) { assert(coder->lzma.end == NULL); lzma_free(coder->lzma.coder, allocator); @@ -221,7 +221,7 @@ lzma2_decoder_end(lzma_coder *coder, lzma_allocator *allocator) static lzma_ret -lzma2_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator, +lzma2_decoder_init(lzma_lz_decoder *lz, const lzma_allocator *allocator, const void *opt, lzma_lz_options *lz_options) { if (lz->coder == NULL) { @@ -248,7 +248,7 @@ lzma2_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator, extern lzma_ret -lzma_lzma2_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_lzma2_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters) { // LZMA2 can only be the last filter in the chain. This is enforced @@ -269,7 +269,7 @@ lzma_lzma2_decoder_memusage(const void *options) extern lzma_ret -lzma_lzma2_props_decode(void **options, lzma_allocator *allocator, +lzma_lzma2_props_decode(void **options, const lzma_allocator *allocator, const uint8_t *props, size_t props_size) { if (props_size != 1) diff --git a/src/liblzma/lzma/lzma2_decoder.h b/src/liblzma/lzma/lzma2_decoder.h index fac4ac487b07..ef2dcbfa76f0 100644 --- a/src/liblzma/lzma/lzma2_decoder.h +++ b/src/liblzma/lzma/lzma2_decoder.h @@ -17,12 +17,13 @@ #include "common.h" extern lzma_ret lzma_lzma2_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern uint64_t lzma_lzma2_decoder_memusage(const void *options); extern lzma_ret lzma_lzma2_props_decode( - void **options, lzma_allocator *allocator, + void **options, const lzma_allocator *allocator, const uint8_t *props, size_t props_size); #endif diff --git a/src/liblzma/lzma/lzma2_encoder.c b/src/liblzma/lzma/lzma2_encoder.c index 992720ca6d5a..b6756bfc2b1c 100644 --- a/src/liblzma/lzma/lzma2_encoder.c +++ b/src/liblzma/lzma/lzma2_encoder.c @@ -262,7 +262,7 @@ lzma2_encode(lzma_coder *restrict coder, lzma_mf *restrict mf, static void -lzma2_encoder_end(lzma_coder *coder, lzma_allocator *allocator) +lzma2_encoder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_free(coder->lzma, allocator); lzma_free(coder, allocator); @@ -304,7 +304,7 @@ lzma2_encoder_options_update(lzma_coder *coder, const lzma_filter *filter) static lzma_ret -lzma2_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator, +lzma2_encoder_init(lzma_lz_encoder *lz, const lzma_allocator *allocator, const void *options, lzma_lz_options *lz_options) { if (options == NULL) @@ -349,7 +349,7 @@ lzma2_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator, extern lzma_ret -lzma_lzma2_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_lzma2_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters) { return lzma_lz_encoder_init( @@ -387,7 +387,17 @@ lzma_lzma2_props_encode(const void *options, uint8_t *out) if (d == UINT32_MAX) out[0] = 40; else - out[0] = get_pos_slot(d + 1) - 24; + out[0] = get_dist_slot(d + 1) - 24; return LZMA_OK; } + + +extern uint64_t +lzma_lzma2_block_size(const void *options) +{ + const lzma_options_lzma *const opt = options; + + // Use at least 1 MiB to keep compression ratio better. + return my_max((uint64_t)(opt->dict_size) * 3, UINT64_C(1) << 20); +} diff --git a/src/liblzma/lzma/lzma2_encoder.h b/src/liblzma/lzma/lzma2_encoder.h index ca19ef4691cc..515f1839347a 100644 --- a/src/liblzma/lzma/lzma2_encoder.h +++ b/src/liblzma/lzma/lzma2_encoder.h @@ -31,11 +31,13 @@ extern lzma_ret lzma_lzma2_encoder_init( - lzma_next_coder *next, lzma_allocator *allocator, + lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters); extern uint64_t lzma_lzma2_encoder_memusage(const void *options); extern lzma_ret lzma_lzma2_props_encode(const void *options, uint8_t *out); +extern uint64_t lzma_lzma2_block_size(const void *options); + #endif diff --git a/src/liblzma/lzma/lzma_common.h b/src/liblzma/lzma/lzma_common.h index e31e285f9a52..09efd3872917 100644 --- a/src/liblzma/lzma/lzma_common.h +++ b/src/liblzma/lzma/lzma_common.h @@ -171,53 +171,54 @@ literal_init(probability (*probs)[LITERAL_CODER_SIZE], // Match distance // //////////////////// -// Different set of probabilities is used for match distances that have very +// Different sets of probabilities are used for match distances that have very // short match length: Lengths of 2, 3, and 4 bytes have a separate set of // probabilities for each length. The matches with longer length use a shared // set of probabilities. -#define LEN_TO_POS_STATES 4 +#define DIST_STATES 4 // Macro to get the index of the appropriate probability array. -#define get_len_to_pos_state(len) \ - ((len) < LEN_TO_POS_STATES + MATCH_LEN_MIN \ +#define get_dist_state(len) \ + ((len) < DIST_STATES + MATCH_LEN_MIN \ ? (len) - MATCH_LEN_MIN \ - : LEN_TO_POS_STATES - 1) + : DIST_STATES - 1) -// The highest two bits of a match distance (pos slot) are encoded using six -// bits. See fastpos.h for more explanation. -#define POS_SLOT_BITS 6 -#define POS_SLOTS (1 << POS_SLOT_BITS) +// The highest two bits of a match distance (distance slot) are encoded +// using six bits. See fastpos.h for more explanation. +#define DIST_SLOT_BITS 6 +#define DIST_SLOTS (1 << DIST_SLOT_BITS) // Match distances up to 127 are fully encoded using probabilities. Since -// the highest two bits (pos slot) are always encoded using six bits, the -// distances 0-3 don't need any additional bits to encode, since the pos -// slot itself is the same as the actual distance. START_POS_MODEL_INDEX -// indicates the first pos slot where at least one additional bit is needed. -#define START_POS_MODEL_INDEX 4 +// the highest two bits (distance slot) are always encoded using six bits, +// the distances 0-3 don't need any additional bits to encode, since the +// distance slot itself is the same as the actual distance. DIST_MODEL_START +// indicates the first distance slot where at least one additional bit is +// needed. +#define DIST_MODEL_START 4 // Match distances greater than 127 are encoded in three pieces: -// - pos slot: the highest two bits +// - distance slot: the highest two bits // - direct bits: 2-26 bits below the highest two bits // - alignment bits: four lowest bits // // Direct bits don't use any probabilities. // -// The pos slot value of 14 is for distances 128-191 (see the table in +// The distance slot value of 14 is for distances 128-191 (see the table in // fastpos.h to understand why). -#define END_POS_MODEL_INDEX 14 +#define DIST_MODEL_END 14 -// Pos slots that indicate a distance <= 127. -#define FULL_DISTANCES_BITS (END_POS_MODEL_INDEX / 2) +// Distance slots that indicate a distance <= 127. +#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2) #define FULL_DISTANCES (1 << FULL_DISTANCES_BITS) // For match distances greater than 127, only the highest two bits and the // lowest four bits (alignment) is encoded using probabilities. #define ALIGN_BITS 4 -#define ALIGN_TABLE_SIZE (1 << ALIGN_BITS) -#define ALIGN_MASK (ALIGN_TABLE_SIZE - 1) +#define ALIGN_SIZE (1 << ALIGN_BITS) +#define ALIGN_MASK (ALIGN_SIZE - 1) // LZMA remembers the four most recent match distances. Reusing these distances // tends to take less space than re-encoding the actual distance value. -#define REP_DISTANCES 4 +#define REPS 4 #endif diff --git a/src/liblzma/lzma/lzma_decoder.c b/src/liblzma/lzma/lzma_decoder.c index 9979bb4261b8..b8f931705bf9 100644 --- a/src/liblzma/lzma/lzma_decoder.c +++ b/src/liblzma/lzma/lzma_decoder.c @@ -193,15 +193,15 @@ struct lzma_coder_s { /// Probability tree for the highest two bits of the match distance. /// There is a separate probability tree for match lengths of /// 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. - probability pos_slot[LEN_TO_POS_STATES][POS_SLOTS]; + probability dist_slot[DIST_STATES][DIST_SLOTS]; /// Probability trees for additional bits for match distance when the /// distance is in the range [4, 127]. - probability pos_special[FULL_DISTANCES - END_POS_MODEL_INDEX]; + probability pos_special[FULL_DISTANCES - DIST_MODEL_END]; /// Probability tree for the lowest four bits of a match distance /// that is equal to or greater than 128. - probability pos_align[ALIGN_TABLE_SIZE]; + probability pos_align[ALIGN_SIZE]; /// Length of a normal match lzma_length_decoder match_len_decoder; @@ -245,8 +245,8 @@ struct lzma_coder_s { SEQ_LITERAL_WRITE, SEQ_IS_REP, seq_len(SEQ_MATCH_LEN), - seq_6(SEQ_POS_SLOT), - SEQ_POS_MODEL, + seq_6(SEQ_DIST_SLOT), + SEQ_DIST_MODEL, SEQ_DIRECT, seq_4(SEQ_ALIGN), SEQ_EOPM, @@ -289,8 +289,12 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr, // Initialization // //////////////////// - if (!rc_read_init(&coder->rc, in, in_pos, in_size)) - return LZMA_OK; + { + const lzma_ret ret = rc_read_init( + &coder->rc, in, in_pos, in_size); + if (ret != LZMA_STREAM_END) + return ret; + } /////////////// // Variables // @@ -502,28 +506,28 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr, // Prepare to decode the highest two bits of the // match distance. - probs = coder->pos_slot[get_len_to_pos_state(len)]; + probs = coder->dist_slot[get_dist_state(len)]; symbol = 1; #ifdef HAVE_SMALL - case SEQ_POS_SLOT: + case SEQ_DIST_SLOT: do { - rc_bit(probs[symbol], , , SEQ_POS_SLOT); - } while (symbol < POS_SLOTS); + rc_bit(probs[symbol], , , SEQ_DIST_SLOT); + } while (symbol < DIST_SLOTS); #else - rc_bit_case(probs[symbol], , , SEQ_POS_SLOT0); - rc_bit_case(probs[symbol], , , SEQ_POS_SLOT1); - rc_bit_case(probs[symbol], , , SEQ_POS_SLOT2); - rc_bit_case(probs[symbol], , , SEQ_POS_SLOT3); - rc_bit_case(probs[symbol], , , SEQ_POS_SLOT4); - rc_bit_case(probs[symbol], , , SEQ_POS_SLOT5); + rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT0); + rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT1); + rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT2); + rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT3); + rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT4); + rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT5); #endif // Get rid of the highest bit that was needed for // indexing of the probability array. - symbol -= POS_SLOTS; + symbol -= DIST_SLOTS; assert(symbol <= 63); - if (symbol < START_POS_MODEL_INDEX) { + if (symbol < DIST_MODEL_START) { // Match distances [0, 3] have only two bits. rep0 = symbol; } else { @@ -533,7 +537,7 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr, assert(limit >= 1 && limit <= 30); rep0 = 2 + (symbol & 1); - if (symbol < END_POS_MODEL_INDEX) { + if (symbol < DIST_MODEL_END) { // Prepare to decode the low bits for // a distance of [4, 127]. assert(limit <= 5); @@ -553,12 +557,12 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr, - symbol - 1; symbol = 1; offset = 0; - case SEQ_POS_MODEL: + case SEQ_DIST_MODEL: #ifdef HAVE_SMALL do { rc_bit(probs[symbol], , rep0 += 1 << offset, - SEQ_POS_MODEL); + SEQ_DIST_MODEL); } while (++offset < limit); #else switch (limit) { @@ -566,25 +570,25 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr, assert(offset == 0); rc_bit(probs[symbol], , rep0 += 1, - SEQ_POS_MODEL); + SEQ_DIST_MODEL); ++offset; --limit; case 4: rc_bit(probs[symbol], , rep0 += 1 << offset, - SEQ_POS_MODEL); + SEQ_DIST_MODEL); ++offset; --limit; case 3: rc_bit(probs[symbol], , rep0 += 1 << offset, - SEQ_POS_MODEL); + SEQ_DIST_MODEL); ++offset; --limit; case 2: rc_bit(probs[symbol], , rep0 += 1 << offset, - SEQ_POS_MODEL); + SEQ_DIST_MODEL); ++offset; --limit; case 1: @@ -596,7 +600,7 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr, // "symbol". rc_bit_last(probs[symbol], , rep0 += 1 << offset, - SEQ_POS_MODEL); + SEQ_DIST_MODEL); } #endif } else { @@ -637,7 +641,7 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr, rc_bit(coder->pos_align[symbol], , rep0 += 4, SEQ_ALIGN2); case SEQ_ALIGN3: - // Like in SEQ_POS_MODEL, we don't + // Like in SEQ_DIST_MODEL, we don't // need "symbol" for anything else // than indexing the probability array. rc_bit_last(coder->pos_align[symbol], , @@ -891,10 +895,10 @@ lzma_decoder_reset(lzma_coder *coder, const void *opt) bit_reset(coder->is_rep2[i]); } - for (uint32_t i = 0; i < LEN_TO_POS_STATES; ++i) - bittree_reset(coder->pos_slot[i], POS_SLOT_BITS); + for (uint32_t i = 0; i < DIST_STATES; ++i) + bittree_reset(coder->dist_slot[i], DIST_SLOT_BITS); - for (uint32_t i = 0; i < FULL_DISTANCES - END_POS_MODEL_INDEX; ++i) + for (uint32_t i = 0; i < FULL_DISTANCES - DIST_MODEL_END; ++i) bit_reset(coder->pos_special[i]); bittree_reset(coder->pos_align, ALIGN_BITS); @@ -933,7 +937,7 @@ lzma_decoder_reset(lzma_coder *coder, const void *opt) extern lzma_ret -lzma_lzma_decoder_create(lzma_lz_decoder *lz, lzma_allocator *allocator, +lzma_lzma_decoder_create(lzma_lz_decoder *lz, const lzma_allocator *allocator, const void *opt, lzma_lz_options *lz_options) { if (lz->coder == NULL) { @@ -961,7 +965,7 @@ lzma_lzma_decoder_create(lzma_lz_decoder *lz, lzma_allocator *allocator, /// initialization (lzma_lzma_decoder_init() passes function pointer to /// the LZ initialization). static lzma_ret -lzma_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator, +lzma_decoder_init(lzma_lz_decoder *lz, const lzma_allocator *allocator, const void *options, lzma_lz_options *lz_options) { if (!is_lclppb_valid(options)) @@ -978,7 +982,7 @@ lzma_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator, extern lzma_ret -lzma_lzma_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_lzma_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters) { // LZMA can only be the last filter in the chain. This is enforced @@ -1025,7 +1029,7 @@ lzma_lzma_decoder_memusage(const void *options) extern lzma_ret -lzma_lzma_props_decode(void **options, lzma_allocator *allocator, +lzma_lzma_props_decode(void **options, const lzma_allocator *allocator, const uint8_t *props, size_t props_size) { if (props_size != 5) diff --git a/src/liblzma/lzma/lzma_decoder.h b/src/liblzma/lzma/lzma_decoder.h index a463a76fc694..fa8ecb23e43c 100644 --- a/src/liblzma/lzma/lzma_decoder.h +++ b/src/liblzma/lzma/lzma_decoder.h @@ -19,12 +19,13 @@ /// Allocates and initializes LZMA decoder extern lzma_ret lzma_lzma_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern uint64_t lzma_lzma_decoder_memusage(const void *options); extern lzma_ret lzma_lzma_props_decode( - void **options, lzma_allocator *allocator, + void **options, const lzma_allocator *allocator, const uint8_t *props, size_t props_size); @@ -40,7 +41,7 @@ extern bool lzma_lzma_lclppb_decode( /// Allocate and setup function pointers only. This is used by LZMA1 and /// LZMA2 decoders. extern lzma_ret lzma_lzma_decoder_create( - lzma_lz_decoder *lz, lzma_allocator *allocator, + lzma_lz_decoder *lz, const lzma_allocator *allocator, const void *opt, lzma_lz_options *lz_options); /// Gets memory usage without validating lc/lp/pb. This is used by LZMA2 diff --git a/src/liblzma/lzma/lzma_encoder.c b/src/liblzma/lzma/lzma_encoder.c index 0b9ee9e15079..31cb4f044829 100644 --- a/src/liblzma/lzma/lzma_encoder.c +++ b/src/liblzma/lzma/lzma_encoder.c @@ -148,28 +148,28 @@ match(lzma_coder *coder, const uint32_t pos_state, length(&coder->rc, &coder->match_len_encoder, pos_state, len, coder->fast_mode); - const uint32_t pos_slot = get_pos_slot(distance); - const uint32_t len_to_pos_state = get_len_to_pos_state(len); - rc_bittree(&coder->rc, coder->pos_slot[len_to_pos_state], - POS_SLOT_BITS, pos_slot); + const uint32_t dist_slot = get_dist_slot(distance); + const uint32_t dist_state = get_dist_state(len); + rc_bittree(&coder->rc, coder->dist_slot[dist_state], + DIST_SLOT_BITS, dist_slot); - if (pos_slot >= START_POS_MODEL_INDEX) { - const uint32_t footer_bits = (pos_slot >> 1) - 1; - const uint32_t base = (2 | (pos_slot & 1)) << footer_bits; - const uint32_t pos_reduced = distance - base; + if (dist_slot >= DIST_MODEL_START) { + const uint32_t footer_bits = (dist_slot >> 1) - 1; + const uint32_t base = (2 | (dist_slot & 1)) << footer_bits; + const uint32_t dist_reduced = distance - base; - if (pos_slot < END_POS_MODEL_INDEX) { - // Careful here: base - pos_slot - 1 can be -1, but + if (dist_slot < DIST_MODEL_END) { + // Careful here: base - dist_slot - 1 can be -1, but // rc_bittree_reverse starts at probs[1], not probs[0]. rc_bittree_reverse(&coder->rc, - coder->pos_special + base - pos_slot - 1, - footer_bits, pos_reduced); + coder->dist_special + base - dist_slot - 1, + footer_bits, dist_reduced); } else { - rc_direct(&coder->rc, pos_reduced >> ALIGN_BITS, + rc_direct(&coder->rc, dist_reduced >> ALIGN_BITS, footer_bits - ALIGN_BITS); rc_bittree_reverse( - &coder->rc, coder->pos_align, - ALIGN_BITS, pos_reduced & ALIGN_MASK); + &coder->rc, coder->dist_align, + ALIGN_BITS, dist_reduced & ALIGN_MASK); ++coder->align_price_count; } } @@ -247,7 +247,7 @@ encode_symbol(lzma_coder *coder, lzma_mf *mf, rc_bit(&coder->rc, &coder->is_match[coder->state][pos_state], 1); - if (back < REP_DISTANCES) { + if (back < REPS) { // It's a repeated match i.e. the same distance // has been used earlier. rc_bit(&coder->rc, &coder->is_rep[coder->state], 1); @@ -255,7 +255,7 @@ encode_symbol(lzma_coder *coder, lzma_mf *mf, } else { // Normal match rc_bit(&coder->rc, &coder->is_rep[coder->state], 0); - match(coder, pos_state, back - REP_DISTANCES, len); + match(coder, pos_state, back - REPS, len); } } @@ -353,9 +353,9 @@ lzma_lzma_encode(lzma_coder *restrict coder, lzma_mf *restrict mf, // Get optimal match (repeat position and length). // Value ranges for pos: - // - [0, REP_DISTANCES): repeated match - // - [REP_DISTANCES, UINT32_MAX): - // match at (pos - REP_DISTANCES) + // - [0, REPS): repeated match + // - [REPS, UINT32_MAX): + // match at (pos - REPS) // - UINT32_MAX: not a match but a literal // Value ranges for len: // - [MATCH_LEN_MIN, MATCH_LEN_MAX] @@ -487,7 +487,7 @@ lzma_lzma_encoder_reset(lzma_coder *coder, const lzma_options_lzma *options) // State coder->state = STATE_LIT_LIT; - for (size_t i = 0; i < REP_DISTANCES; ++i) + for (size_t i = 0; i < REPS; ++i) coder->reps[i] = 0; literal_init(coder->literal, options->lc, options->lp); @@ -505,14 +505,14 @@ lzma_lzma_encoder_reset(lzma_coder *coder, const lzma_options_lzma *options) bit_reset(coder->is_rep2[i]); } - for (size_t i = 0; i < FULL_DISTANCES - END_POS_MODEL_INDEX; ++i) - bit_reset(coder->pos_special[i]); + for (size_t i = 0; i < FULL_DISTANCES - DIST_MODEL_END; ++i) + bit_reset(coder->dist_special[i]); // Bit tree encoders - for (size_t i = 0; i < LEN_TO_POS_STATES; ++i) - bittree_reset(coder->pos_slot[i], POS_SLOT_BITS); + for (size_t i = 0; i < DIST_STATES; ++i) + bittree_reset(coder->dist_slot[i], DIST_SLOT_BITS); - bittree_reset(coder->pos_align, ALIGN_BITS); + bittree_reset(coder->dist_align, ALIGN_BITS); // Length encoders length_encoder_reset(&coder->match_len_encoder, @@ -545,7 +545,8 @@ lzma_lzma_encoder_reset(lzma_coder *coder, const lzma_options_lzma *options) extern lzma_ret -lzma_lzma_encoder_create(lzma_coder **coder_ptr, lzma_allocator *allocator, +lzma_lzma_encoder_create(lzma_coder **coder_ptr, + const lzma_allocator *allocator, const lzma_options_lzma *options, lzma_lz_options *lz_options) { // Allocate lzma_coder if it wasn't already allocated. @@ -604,7 +605,7 @@ lzma_lzma_encoder_create(lzma_coder **coder_ptr, lzma_allocator *allocator, static lzma_ret -lzma_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator, +lzma_encoder_init(lzma_lz_encoder *lz, const lzma_allocator *allocator, const void *options, lzma_lz_options *lz_options) { lz->code = &lzma_encode; @@ -614,7 +615,7 @@ lzma_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator, extern lzma_ret -lzma_lzma_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_lzma_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters) { return lzma_lz_encoder_init( diff --git a/src/liblzma/lzma/lzma_encoder.h b/src/liblzma/lzma/lzma_encoder.h index 835e1f583304..cc9cc2f27ecb 100644 --- a/src/liblzma/lzma/lzma_encoder.h +++ b/src/liblzma/lzma/lzma_encoder.h @@ -18,7 +18,8 @@ extern lzma_ret lzma_lzma_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern uint64_t lzma_lzma_encoder_memusage(const void *options); @@ -35,7 +36,7 @@ extern bool lzma_lzma_lclppb_encode( /// Initializes raw LZMA encoder; this is used by LZMA2. extern lzma_ret lzma_lzma_encoder_create( - lzma_coder **coder_ptr, lzma_allocator *allocator, + lzma_coder **coder_ptr, const lzma_allocator *allocator, const lzma_options_lzma *options, lzma_lz_options *lz_options); diff --git a/src/liblzma/lzma/lzma_encoder_optimum_fast.c b/src/liblzma/lzma/lzma_encoder_optimum_fast.c index f835f69356bd..8922cbd91d3f 100644 --- a/src/liblzma/lzma/lzma_encoder_optimum_fast.c +++ b/src/liblzma/lzma/lzma_encoder_optimum_fast.c @@ -10,6 +10,7 @@ /////////////////////////////////////////////////////////////////////////////// #include "lzma_encoder_private.h" +#include "memcmplen.h" #define change_pair(small_dist, big_dist) \ @@ -46,7 +47,7 @@ lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf, uint32_t rep_len = 0; uint32_t rep_index = 0; - for (uint32_t i = 0; i < REP_DISTANCES; ++i) { + for (uint32_t i = 0; i < REPS; ++i) { // Pointer to the beginning of the match candidate const uint8_t *const buf_back = buf - coder->reps[i] - 1; @@ -57,9 +58,8 @@ lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf, // The first two bytes matched. // Calculate the length of the match. - uint32_t len; - for (len = 2; len < buf_avail - && buf[len] == buf_back[len]; ++len) ; + const uint32_t len = lzma_memcmplen( + buf, buf_back, 2, buf_avail); // If we have found a repeated match that is at least // nice_len long, return it immediately. @@ -79,8 +79,7 @@ lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf, // We didn't find a long enough repeated match. Encode it as a normal // match if the match length is at least nice_len. if (len_main >= nice_len) { - *back_res = coder->matches[matches_count - 1].dist - + REP_DISTANCES; + *back_res = coder->matches[matches_count - 1].dist + REPS; *len_res = len_main; mf_skip(mf, len_main - 1); return; @@ -155,24 +154,15 @@ lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf, const uint32_t limit = len_main - 1; - for (uint32_t i = 0; i < REP_DISTANCES; ++i) { - const uint8_t *const buf_back = buf - coder->reps[i] - 1; - - if (not_equal_16(buf, buf_back)) - continue; - - uint32_t len; - for (len = 2; len < limit - && buf[len] == buf_back[len]; ++len) ; - - if (len >= limit) { + for (uint32_t i = 0; i < REPS; ++i) { + if (memcmp(buf, buf - coder->reps[i] - 1, limit) == 0) { *back_res = UINT32_MAX; *len_res = 1; return; } } - *back_res = back_main + REP_DISTANCES; + *back_res = back_main + REPS; *len_res = len_main; mf_skip(mf, len_main - 2); return; diff --git a/src/liblzma/lzma/lzma_encoder_optimum_normal.c b/src/liblzma/lzma/lzma_encoder_optimum_normal.c index 7e856493c8cd..a360579885db 100644 --- a/src/liblzma/lzma/lzma_encoder_optimum_normal.c +++ b/src/liblzma/lzma/lzma_encoder_optimum_normal.c @@ -11,6 +11,7 @@ #include "lzma_encoder_private.h" #include "fastpos.h" +#include "memcmplen.h" //////////// @@ -108,18 +109,18 @@ get_rep_price(const lzma_coder *const coder, const uint32_t rep_index, static inline uint32_t -get_pos_len_price(const lzma_coder *const coder, const uint32_t pos, +get_dist_len_price(const lzma_coder *const coder, const uint32_t dist, const uint32_t len, const uint32_t pos_state) { - const uint32_t len_to_pos_state = get_len_to_pos_state(len); + const uint32_t dist_state = get_dist_state(len); uint32_t price; - if (pos < FULL_DISTANCES) { - price = coder->distances_prices[len_to_pos_state][pos]; + if (dist < FULL_DISTANCES) { + price = coder->dist_prices[dist_state][dist]; } else { - const uint32_t pos_slot = get_pos_slot_2(pos); - price = coder->pos_slot_prices[len_to_pos_state][pos_slot] - + coder->align_prices[pos & ALIGN_MASK]; + const uint32_t dist_slot = get_dist_slot_2(dist); + price = coder->dist_slot_prices[dist_state][dist_slot] + + coder->align_prices[dist & ALIGN_MASK]; } price += get_len_price(&coder->match_len_encoder, len, pos_state); @@ -129,55 +130,53 @@ get_pos_len_price(const lzma_coder *const coder, const uint32_t pos, static void -fill_distances_prices(lzma_coder *coder) +fill_dist_prices(lzma_coder *coder) { - for (uint32_t len_to_pos_state = 0; - len_to_pos_state < LEN_TO_POS_STATES; - ++len_to_pos_state) { + for (uint32_t dist_state = 0; dist_state < DIST_STATES; ++dist_state) { - uint32_t *const pos_slot_prices - = coder->pos_slot_prices[len_to_pos_state]; + uint32_t *const dist_slot_prices + = coder->dist_slot_prices[dist_state]; - // Price to encode the pos_slot. - for (uint32_t pos_slot = 0; - pos_slot < coder->dist_table_size; ++pos_slot) - pos_slot_prices[pos_slot] = rc_bittree_price( - coder->pos_slot[len_to_pos_state], - POS_SLOT_BITS, pos_slot); + // Price to encode the dist_slot. + for (uint32_t dist_slot = 0; + dist_slot < coder->dist_table_size; ++dist_slot) + dist_slot_prices[dist_slot] = rc_bittree_price( + coder->dist_slot[dist_state], + DIST_SLOT_BITS, dist_slot); // For matches with distance >= FULL_DISTANCES, add the price // of the direct bits part of the match distance. (Align bits // are handled by fill_align_prices()). - for (uint32_t pos_slot = END_POS_MODEL_INDEX; - pos_slot < coder->dist_table_size; ++pos_slot) - pos_slot_prices[pos_slot] += rc_direct_price( - ((pos_slot >> 1) - 1) - ALIGN_BITS); + for (uint32_t dist_slot = DIST_MODEL_END; + dist_slot < coder->dist_table_size; + ++dist_slot) + dist_slot_prices[dist_slot] += rc_direct_price( + ((dist_slot >> 1) - 1) - ALIGN_BITS); // Distances in the range [0, 3] are fully encoded with - // pos_slot, so they are used for coder->distances_prices + // dist_slot, so they are used for coder->dist_prices // as is. - for (uint32_t i = 0; i < START_POS_MODEL_INDEX; ++i) - coder->distances_prices[len_to_pos_state][i] - = pos_slot_prices[i]; + for (uint32_t i = 0; i < DIST_MODEL_START; ++i) + coder->dist_prices[dist_state][i] + = dist_slot_prices[i]; } - // Distances in the range [4, 127] depend on pos_slot and pos_special. - // We do this in a loop separate from the above loop to avoid - // redundant calls to get_pos_slot(). - for (uint32_t i = START_POS_MODEL_INDEX; i < FULL_DISTANCES; ++i) { - const uint32_t pos_slot = get_pos_slot(i); - const uint32_t footer_bits = ((pos_slot >> 1) - 1); - const uint32_t base = (2 | (pos_slot & 1)) << footer_bits; + // Distances in the range [4, 127] depend on dist_slot and + // dist_special. We do this in a loop separate from the above + // loop to avoid redundant calls to get_dist_slot(). + for (uint32_t i = DIST_MODEL_START; i < FULL_DISTANCES; ++i) { + const uint32_t dist_slot = get_dist_slot(i); + const uint32_t footer_bits = ((dist_slot >> 1) - 1); + const uint32_t base = (2 | (dist_slot & 1)) << footer_bits; const uint32_t price = rc_bittree_reverse_price( - coder->pos_special + base - pos_slot - 1, + coder->dist_special + base - dist_slot - 1, footer_bits, i - base); - for (uint32_t len_to_pos_state = 0; - len_to_pos_state < LEN_TO_POS_STATES; - ++len_to_pos_state) - coder->distances_prices[len_to_pos_state][i] - = price + coder->pos_slot_prices[ - len_to_pos_state][pos_slot]; + for (uint32_t dist_state = 0; dist_state < DIST_STATES; + ++dist_state) + coder->dist_prices[dist_state][i] + = price + coder->dist_slot_prices[ + dist_state][dist_slot]; } coder->match_price_count = 0; @@ -188,9 +187,9 @@ fill_distances_prices(lzma_coder *coder) static void fill_align_prices(lzma_coder *coder) { - for (uint32_t i = 0; i < ALIGN_TABLE_SIZE; ++i) + for (uint32_t i = 0; i < ALIGN_SIZE; ++i) coder->align_prices[i] = rc_bittree_reverse_price( - coder->pos_align, ALIGN_BITS, i); + coder->dist_align, ALIGN_BITS, i); coder->align_price_count = 0; return; @@ -296,10 +295,10 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf, const uint8_t *const buf = mf_ptr(mf) - 1; - uint32_t rep_lens[REP_DISTANCES]; + uint32_t rep_lens[REPS]; uint32_t rep_max_index = 0; - for (uint32_t i = 0; i < REP_DISTANCES; ++i) { + for (uint32_t i = 0; i < REPS; ++i) { const uint8_t *const buf_back = buf - coder->reps[i] - 1; if (not_equal_16(buf, buf_back)) { @@ -307,13 +306,9 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf, continue; } - uint32_t len_test; - for (len_test = 2; len_test < buf_avail - && buf[len_test] == buf_back[len_test]; - ++len_test) ; + rep_lens[i] = lzma_memcmplen(buf, buf_back, 2, buf_avail); - rep_lens[i] = len_test; - if (len_test > rep_lens[rep_max_index]) + if (rep_lens[i] > rep_lens[rep_max_index]) rep_max_index = i; } @@ -326,8 +321,7 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf, if (len_main >= nice_len) { - *back_res = coder->matches[matches_count - 1].dist - + REP_DISTANCES; + *back_res = coder->matches[matches_count - 1].dist + REPS; *len_res = len_main; mf_skip(mf, len_main - 1); return UINT32_MAX; @@ -381,7 +375,7 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf, coder->opts[1].pos_prev = 0; - for (uint32_t i = 0; i < REP_DISTANCES; ++i) + for (uint32_t i = 0; i < REPS; ++i) coder->opts[0].backs[i] = coder->reps[i]; uint32_t len = len_end; @@ -390,7 +384,7 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf, } while (--len >= 2); - for (uint32_t i = 0; i < REP_DISTANCES; ++i) { + for (uint32_t i = 0; i < REPS; ++i) { uint32_t rep_len = rep_lens[i]; if (rep_len < 2) continue; @@ -426,14 +420,13 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf, for(; ; ++len) { const uint32_t dist = coder->matches[i].dist; const uint32_t cur_and_len_price = normal_match_price - + get_pos_len_price(coder, + + get_dist_len_price(coder, dist, len, pos_state); if (cur_and_len_price < coder->opts[len].price) { coder->opts[len].price = cur_and_len_price; coder->opts[len].pos_prev = 0; - coder->opts[len].back_prev - = dist + REP_DISTANCES; + coder->opts[len].back_prev = dist + REPS; coder->opts[len].prev_1_is_literal = false; } @@ -463,7 +456,7 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf, if (coder->opts[cur].prev_2) { state = coder->opts[coder->opts[cur].pos_prev_2].state; - if (coder->opts[cur].back_prev_2 < REP_DISTANCES) + if (coder->opts[cur].back_prev_2 < REPS) update_long_rep(state); else update_match(state); @@ -492,33 +485,33 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf, update_long_rep(state); } else { pos = coder->opts[cur].back_prev; - if (pos < REP_DISTANCES) + if (pos < REPS) update_long_rep(state); else update_match(state); } - if (pos < REP_DISTANCES) { + if (pos < REPS) { reps[0] = coder->opts[pos_prev].backs[pos]; uint32_t i; for (i = 1; i <= pos; ++i) reps[i] = coder->opts[pos_prev].backs[i - 1]; - for (; i < REP_DISTANCES; ++i) + for (; i < REPS; ++i) reps[i] = coder->opts[pos_prev].backs[i]; } else { - reps[0] = pos - REP_DISTANCES; + reps[0] = pos - REPS; - for (uint32_t i = 1; i < REP_DISTANCES; ++i) + for (uint32_t i = 1; i < REPS; ++i) reps[i] = coder->opts[pos_prev].backs[i - 1]; } } coder->opts[cur].state = state; - for (uint32_t i = 0; i < REP_DISTANCES; ++i) + for (uint32_t i = 0; i < REPS; ++i) coder->opts[cur].backs[i] = reps[i]; const uint32_t cur_price = coder->opts[cur].price; @@ -572,11 +565,7 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf, const uint8_t *const buf_back = buf - reps[0] - 1; const uint32_t limit = my_min(buf_avail_full, nice_len + 1); - uint32_t len_test = 1; - while (len_test < limit && buf[len_test] == buf_back[len_test]) - ++len_test; - - --len_test; + const uint32_t len_test = lzma_memcmplen(buf, buf_back, 1, limit) - 1; if (len_test >= 2) { lzma_lzma_state state_2 = state; @@ -611,15 +600,12 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf, uint32_t start_len = 2; // speed optimization - for (uint32_t rep_index = 0; rep_index < REP_DISTANCES; ++rep_index) { + for (uint32_t rep_index = 0; rep_index < REPS; ++rep_index) { const uint8_t *const buf_back = buf - reps[rep_index] - 1; if (not_equal_16(buf, buf_back)) continue; - uint32_t len_test; - for (len_test = 2; len_test < buf_avail - && buf[len_test] == buf_back[len_test]; - ++len_test) ; + uint32_t len_test = lzma_memcmplen(buf, buf_back, 2, buf_avail); while (len_end < cur + len_test) coder->opts[++len_end].price = RC_INFINITY_PRICE; @@ -728,14 +714,14 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf, for (uint32_t len_test = start_len; ; ++len_test) { const uint32_t cur_back = coder->matches[i].dist; uint32_t cur_and_len_price = normal_match_price - + get_pos_len_price(coder, + + get_dist_len_price(coder, cur_back, len_test, pos_state); if (cur_and_len_price < coder->opts[cur + len_test].price) { coder->opts[cur + len_test].price = cur_and_len_price; coder->opts[cur + len_test].pos_prev = cur; coder->opts[cur + len_test].back_prev - = cur_back + REP_DISTANCES; + = cur_back + REPS; coder->opts[cur + len_test].prev_1_is_literal = false; } @@ -795,7 +781,7 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf, coder->opts[offset].prev_2 = true; coder->opts[offset].pos_prev_2 = cur; coder->opts[offset].back_prev_2 - = cur_back + REP_DISTANCES; + = cur_back + REPS; } //} } @@ -831,9 +817,9 @@ lzma_lzma_optimum_normal(lzma_coder *restrict coder, lzma_mf *restrict mf, // In liblzma they were moved into this single place. if (mf->read_ahead == 0) { if (coder->match_price_count >= (1 << 7)) - fill_distances_prices(coder); + fill_dist_prices(coder); - if (coder->align_price_count >= ALIGN_TABLE_SIZE) + if (coder->align_price_count >= ALIGN_SIZE) fill_align_prices(coder); } @@ -845,7 +831,7 @@ lzma_lzma_optimum_normal(lzma_coder *restrict coder, lzma_mf *restrict mf, if (len_end == UINT32_MAX) return; - uint32_t reps[REP_DISTANCES]; + uint32_t reps[REPS]; memcpy(reps, coder->reps, sizeof(reps)); uint32_t cur; diff --git a/src/liblzma/lzma/lzma_encoder_private.h b/src/liblzma/lzma/lzma_encoder_private.h index 684745236c82..2f62d6cba0b7 100644 --- a/src/liblzma/lzma/lzma_encoder_private.h +++ b/src/liblzma/lzma/lzma_encoder_private.h @@ -64,7 +64,7 @@ typedef struct { uint32_t pos_prev; // pos_next; uint32_t back_prev; - uint32_t backs[REP_DISTANCES]; + uint32_t backs[REPS]; } lzma_optimal; @@ -77,7 +77,7 @@ struct lzma_coder_s { lzma_lzma_state state; /// The four most recent match distances - uint32_t reps[REP_DISTANCES]; + uint32_t reps[REPS]; /// Array of match candidates lzma_match matches[MATCH_LEN_MAX + 1]; @@ -112,9 +112,9 @@ struct lzma_coder_s { probability is_rep1[STATES]; probability is_rep2[STATES]; probability is_rep0_long[STATES][POS_STATES_MAX]; - probability pos_slot[LEN_TO_POS_STATES][POS_SLOTS]; - probability pos_special[FULL_DISTANCES - END_POS_MODEL_INDEX]; - probability pos_align[ALIGN_TABLE_SIZE]; + probability dist_slot[DIST_STATES][DIST_SLOTS]; + probability dist_special[FULL_DISTANCES - DIST_MODEL_END]; + probability dist_align[ALIGN_SIZE]; // These are the same as in lzma_decoder.c except that the encoders // include also price tables. @@ -122,12 +122,12 @@ struct lzma_coder_s { lzma_length_encoder rep_len_encoder; // Price tables - uint32_t pos_slot_prices[LEN_TO_POS_STATES][POS_SLOTS]; - uint32_t distances_prices[LEN_TO_POS_STATES][FULL_DISTANCES]; + uint32_t dist_slot_prices[DIST_STATES][DIST_SLOTS]; + uint32_t dist_prices[DIST_STATES][FULL_DISTANCES]; uint32_t dist_table_size; uint32_t match_price_count; - uint32_t align_prices[ALIGN_TABLE_SIZE]; + uint32_t align_prices[ALIGN_SIZE]; uint32_t align_price_count; // Optimal diff --git a/src/liblzma/rangecoder/range_decoder.h b/src/liblzma/rangecoder/range_decoder.h index fb96180fb399..e0b051fac2d2 100644 --- a/src/liblzma/rangecoder/range_decoder.h +++ b/src/liblzma/rangecoder/range_decoder.h @@ -25,20 +25,26 @@ typedef struct { /// Reads the first five bytes to initialize the range decoder. -static inline bool +static inline lzma_ret rc_read_init(lzma_range_decoder *rc, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size) { while (rc->init_bytes_left > 0) { if (*in_pos == in_size) - return false; + return LZMA_OK; + + // The first byte is always 0x00. It could have been omitted + // in LZMA2 but it wasn't, so one byte is wasted in every + // LZMA2 chunk. + if (rc->init_bytes_left == 5 && in[*in_pos] != 0x00) + return LZMA_DATA_ERROR; rc->code = (rc->code << 8) | in[*in_pos]; ++*in_pos; --rc->init_bytes_left; } - return true; + return LZMA_STREAM_END; } diff --git a/src/liblzma/simple/arm.c b/src/liblzma/simple/arm.c index a84702ac62f2..258d870fead3 100644 --- a/src/liblzma/simple/arm.c +++ b/src/liblzma/simple/arm.c @@ -45,7 +45,7 @@ arm_code(lzma_simple *simple lzma_attribute((__unused__)), static lzma_ret -arm_coder_init(lzma_next_coder *next, lzma_allocator *allocator, +arm_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters, bool is_encoder) { return lzma_simple_coder_init(next, allocator, filters, @@ -54,7 +54,8 @@ arm_coder_init(lzma_next_coder *next, lzma_allocator *allocator, extern lzma_ret -lzma_simple_arm_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_simple_arm_encoder_init(lzma_next_coder *next, + const lzma_allocator *allocator, const lzma_filter_info *filters) { return arm_coder_init(next, allocator, filters, true); @@ -62,7 +63,8 @@ lzma_simple_arm_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, extern lzma_ret -lzma_simple_arm_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_simple_arm_decoder_init(lzma_next_coder *next, + const lzma_allocator *allocator, const lzma_filter_info *filters) { return arm_coder_init(next, allocator, filters, false); diff --git a/src/liblzma/simple/armthumb.c b/src/liblzma/simple/armthumb.c index 4b49175fec4d..06c21e4067a5 100644 --- a/src/liblzma/simple/armthumb.c +++ b/src/liblzma/simple/armthumb.c @@ -50,7 +50,7 @@ armthumb_code(lzma_simple *simple lzma_attribute((__unused__)), static lzma_ret -armthumb_coder_init(lzma_next_coder *next, lzma_allocator *allocator, +armthumb_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters, bool is_encoder) { return lzma_simple_coder_init(next, allocator, filters, @@ -60,7 +60,8 @@ armthumb_coder_init(lzma_next_coder *next, lzma_allocator *allocator, extern lzma_ret lzma_simple_armthumb_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters) + const lzma_allocator *allocator, + const lzma_filter_info *filters) { return armthumb_coder_init(next, allocator, filters, true); } @@ -68,7 +69,8 @@ lzma_simple_armthumb_encoder_init(lzma_next_coder *next, extern lzma_ret lzma_simple_armthumb_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters) + const lzma_allocator *allocator, + const lzma_filter_info *filters) { return armthumb_coder_init(next, allocator, filters, false); } diff --git a/src/liblzma/simple/ia64.c b/src/liblzma/simple/ia64.c index ce3692b98f1d..ba7249c00178 100644 --- a/src/liblzma/simple/ia64.c +++ b/src/liblzma/simple/ia64.c @@ -86,7 +86,7 @@ ia64_code(lzma_simple *simple lzma_attribute((__unused__)), static lzma_ret -ia64_coder_init(lzma_next_coder *next, lzma_allocator *allocator, +ia64_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters, bool is_encoder) { return lzma_simple_coder_init(next, allocator, filters, @@ -96,7 +96,8 @@ ia64_coder_init(lzma_next_coder *next, lzma_allocator *allocator, extern lzma_ret lzma_simple_ia64_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters) + const lzma_allocator *allocator, + const lzma_filter_info *filters) { return ia64_coder_init(next, allocator, filters, true); } @@ -104,7 +105,8 @@ lzma_simple_ia64_encoder_init(lzma_next_coder *next, extern lzma_ret lzma_simple_ia64_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters) + const lzma_allocator *allocator, + const lzma_filter_info *filters) { return ia64_coder_init(next, allocator, filters, false); } diff --git a/src/liblzma/simple/powerpc.c b/src/liblzma/simple/powerpc.c index 6f8351176c5e..46899196af50 100644 --- a/src/liblzma/simple/powerpc.c +++ b/src/liblzma/simple/powerpc.c @@ -49,7 +49,7 @@ powerpc_code(lzma_simple *simple lzma_attribute((__unused__)), static lzma_ret -powerpc_coder_init(lzma_next_coder *next, lzma_allocator *allocator, +powerpc_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters, bool is_encoder) { return lzma_simple_coder_init(next, allocator, filters, @@ -59,7 +59,8 @@ powerpc_coder_init(lzma_next_coder *next, lzma_allocator *allocator, extern lzma_ret lzma_simple_powerpc_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters) + const lzma_allocator *allocator, + const lzma_filter_info *filters) { return powerpc_coder_init(next, allocator, filters, true); } @@ -67,7 +68,8 @@ lzma_simple_powerpc_encoder_init(lzma_next_coder *next, extern lzma_ret lzma_simple_powerpc_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters) + const lzma_allocator *allocator, + const lzma_filter_info *filters) { return powerpc_coder_init(next, allocator, filters, false); } diff --git a/src/liblzma/simple/simple_coder.c b/src/liblzma/simple/simple_coder.c index a02b039aa0bb..dba5417b4264 100644 --- a/src/liblzma/simple/simple_coder.c +++ b/src/liblzma/simple/simple_coder.c @@ -18,7 +18,7 @@ /// Copied or encodes/decodes more data to out[]. static lzma_ret -copy_or_code(lzma_coder *coder, lzma_allocator *allocator, +copy_or_code(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, lzma_action action) @@ -66,7 +66,7 @@ call_filter(lzma_coder *coder, uint8_t *buffer, size_t size) static lzma_ret -simple_code(lzma_coder *coder, lzma_allocator *allocator, +simple_code(lzma_coder *coder, const lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, size_t *restrict out_pos, size_t out_size, lzma_action action) @@ -198,7 +198,7 @@ simple_code(lzma_coder *coder, lzma_allocator *allocator, static void -simple_coder_end(lzma_coder *coder, lzma_allocator *allocator) +simple_coder_end(lzma_coder *coder, const lzma_allocator *allocator) { lzma_next_end(&coder->next, allocator); lzma_free(coder->simple, allocator); @@ -208,7 +208,7 @@ simple_coder_end(lzma_coder *coder, lzma_allocator *allocator) static lzma_ret -simple_coder_update(lzma_coder *coder, lzma_allocator *allocator, +simple_coder_update(lzma_coder *coder, const lzma_allocator *allocator, const lzma_filter *filters_null lzma_attribute((__unused__)), const lzma_filter *reversed_filters) { @@ -219,7 +219,7 @@ simple_coder_update(lzma_coder *coder, lzma_allocator *allocator, extern lzma_ret -lzma_simple_coder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_simple_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters, size_t (*filter)(lzma_simple *simple, uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size), diff --git a/src/liblzma/simple/simple_coder.h b/src/liblzma/simple/simple_coder.h index 0952fad33b34..19c2ee03affd 100644 --- a/src/liblzma/simple/simple_coder.h +++ b/src/liblzma/simple/simple_coder.h @@ -17,44 +17,56 @@ extern lzma_ret lzma_simple_x86_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_x86_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_powerpc_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_powerpc_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_ia64_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_ia64_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_arm_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_arm_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_armthumb_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_armthumb_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_sparc_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_sparc_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); + const lzma_allocator *allocator, + const lzma_filter_info *filters); #endif diff --git a/src/liblzma/simple/simple_decoder.c b/src/liblzma/simple/simple_decoder.c index 0beccd32a7d8..1d864f2bf781 100644 --- a/src/liblzma/simple/simple_decoder.c +++ b/src/liblzma/simple/simple_decoder.c @@ -14,7 +14,7 @@ extern lzma_ret -lzma_simple_props_decode(void **options, lzma_allocator *allocator, +lzma_simple_props_decode(void **options, const lzma_allocator *allocator, const uint8_t *props, size_t props_size) { if (props_size == 0) diff --git a/src/liblzma/simple/simple_decoder.h b/src/liblzma/simple/simple_decoder.h index b8bf590f7681..bed8d37a9653 100644 --- a/src/liblzma/simple/simple_decoder.h +++ b/src/liblzma/simple/simple_decoder.h @@ -16,7 +16,7 @@ #include "simple_coder.h" extern lzma_ret lzma_simple_props_decode( - void **options, lzma_allocator *allocator, + void **options, const lzma_allocator *allocator, const uint8_t *props, size_t props_size); #endif diff --git a/src/liblzma/simple/simple_private.h b/src/liblzma/simple/simple_private.h index fcf9f7c1980f..bb20cb419f8c 100644 --- a/src/liblzma/simple/simple_private.h +++ b/src/liblzma/simple/simple_private.h @@ -66,7 +66,8 @@ struct lzma_coder_s { extern lzma_ret lzma_simple_coder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters, + const lzma_allocator *allocator, + const lzma_filter_info *filters, size_t (*filter)(lzma_simple *simple, uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size), size_t simple_size, size_t unfiltered_max, diff --git a/src/liblzma/simple/sparc.c b/src/liblzma/simple/sparc.c index 8270d6ab19f1..53ee49d154f1 100644 --- a/src/liblzma/simple/sparc.c +++ b/src/liblzma/simple/sparc.c @@ -57,7 +57,7 @@ sparc_code(lzma_simple *simple lzma_attribute((__unused__)), static lzma_ret -sparc_coder_init(lzma_next_coder *next, lzma_allocator *allocator, +sparc_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters, bool is_encoder) { return lzma_simple_coder_init(next, allocator, filters, @@ -67,7 +67,8 @@ sparc_coder_init(lzma_next_coder *next, lzma_allocator *allocator, extern lzma_ret lzma_simple_sparc_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters) + const lzma_allocator *allocator, + const lzma_filter_info *filters) { return sparc_coder_init(next, allocator, filters, true); } @@ -75,7 +76,8 @@ lzma_simple_sparc_encoder_init(lzma_next_coder *next, extern lzma_ret lzma_simple_sparc_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters) + const lzma_allocator *allocator, + const lzma_filter_info *filters) { return sparc_coder_init(next, allocator, filters, false); } diff --git a/src/liblzma/simple/x86.c b/src/liblzma/simple/x86.c index 5d1509bb2278..3b2b4f852067 100644 --- a/src/liblzma/simple/x86.c +++ b/src/liblzma/simple/x86.c @@ -123,7 +123,7 @@ x86_code(lzma_simple *simple, uint32_t now_pos, bool is_encoder, static lzma_ret -x86_coder_init(lzma_next_coder *next, lzma_allocator *allocator, +x86_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters, bool is_encoder) { const lzma_ret ret = lzma_simple_coder_init(next, allocator, filters, @@ -139,7 +139,8 @@ x86_coder_init(lzma_next_coder *next, lzma_allocator *allocator, extern lzma_ret -lzma_simple_x86_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_simple_x86_encoder_init(lzma_next_coder *next, + const lzma_allocator *allocator, const lzma_filter_info *filters) { return x86_coder_init(next, allocator, filters, true); @@ -147,7 +148,8 @@ lzma_simple_x86_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, extern lzma_ret -lzma_simple_x86_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, +lzma_simple_x86_decoder_init(lzma_next_coder *next, + const lzma_allocator *allocator, const lzma_filter_info *filters) { return x86_coder_init(next, allocator, filters, false); diff --git a/src/liblzma/validate_map.sh b/src/liblzma/validate_map.sh new file mode 100755 index 000000000000..3aee46687c38 --- /dev/null +++ b/src/liblzma/validate_map.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +############################################################################### +# +# Check liblzma.map for certain types of errors +# +# Author: Lasse Collin +# +# This file has been put into the public domain. +# You can do whatever you want with this file. +# +############################################################################### + +LC_ALL=C +export LC_ALL + +STATUS=0 + +cd "$(dirname "$0")" + +# Get the list of symbols that aren't defined in liblzma.map. +SYMS=$(sed -n 's/^extern LZMA_API([^)]*) \([a-z0-9_]*\)(.*$/\1;/p' \ + api/lzma/*.h \ + | sort \ + | grep -Fve "$(sed '/[{}:*]/d;/^$/d;s/^ //' liblzma.map)") + +# Check that there are no old alpha or beta versions listed. +VER=$(cd ../.. && sh build-aux/version.sh) +NAMES= +case $VER in + *alpha | *beta) + NAMES=$(sed -n 's/^.*XZ_\([^ ]*\)\(alpha\|beta\) .*$/\1\2/p' \ + liblzma.map | grep -Fv "$VER") + ;; +esac + +# Check for duplicate lines. It can catch missing dependencies. +DUPS=$(sort liblzma.map | sed '/^$/d;/^global:$/d' | uniq -d) + +# Print error messages if needed. +if test -n "$SYMS$NAMES$DUPS"; then + echo + echo 'validate_map.sh found problems from liblzma.map:' + echo + + if test -n "$SYMS"; then + echo 'liblzma.map lacks the following symbols:' + echo "$SYMS" + echo + fi + + if test -n "$NAMES"; then + echo 'Obsolete alpha or beta version names:' + echo "$NAMES" + echo + fi + + if test -n "$DUPS"; then + echo 'Duplicate lines:' + echo "$DUPS" + echo + fi + + STATUS=1 +fi + +# Exit status is 1 if problems were found, 0 otherwise. +exit "$STATUS" diff --git a/src/xz/args.c b/src/xz/args.c index 34761d45d67e..041c80073e6d 100644 --- a/src/xz/args.c +++ b/src/xz/args.c @@ -22,6 +22,7 @@ bool opt_stdout = false; bool opt_force = false; bool opt_keep_original = false; bool opt_robot = false; +bool opt_ignore_check = false; // We don't modify or free() this, but we need to assign it in some // non-const pointers. @@ -54,6 +55,67 @@ parse_memlimit(const char *name, const char *name_percentage, char *str, } +static void +parse_block_list(char *str) +{ + // It must be non-empty and not begin with a comma. + if (str[0] == '\0' || str[0] == ',') + message_fatal(_("%s: Invalid argument to --block-list"), str); + + // Count the number of comma-separated strings. + size_t count = 1; + for (size_t i = 0; str[i] != '\0'; ++i) + if (str[i] == ',') + ++count; + + // Prevent an unlikely integer overflow. + if (count > SIZE_MAX / sizeof(uint64_t) - 1) + message_fatal(_("%s: Too many arguments to --block-list"), + str); + + // Allocate memory to hold all the sizes specified. + // If --block-list was specified already, its value is forgotten. + free(opt_block_list); + opt_block_list = xmalloc((count + 1) * sizeof(uint64_t)); + + for (size_t i = 0; i < count; ++i) { + // Locate the next comma and replace it with \0. + char *p = strchr(str, ','); + if (p != NULL) + *p = '\0'; + + if (str[0] == '\0') { + // There is no string, that is, a comma follows + // another comma. Use the previous value. + // + // NOTE: We checked earler that the first char + // of the whole list cannot be a comma. + assert(i > 0); + opt_block_list[i] = opt_block_list[i - 1]; + } else { + opt_block_list[i] = str_to_uint64("block-list", str, + 0, UINT64_MAX); + + // Zero indicates no more new Blocks. + if (opt_block_list[i] == 0) { + if (i + 1 != count) + message_fatal(_("0 can only be used " + "as the last element " + "in --block-list")); + + opt_block_list[i] = UINT64_MAX; + } + } + + str = p + 1; + } + + // Terminate the array. + opt_block_list[count] = 0; + return; +} + + static void parse_real(args_info *args, int argc, char **argv) { @@ -68,14 +130,19 @@ parse_real(args_info *args, int argc, char **argv) OPT_LZMA1, OPT_LZMA2, + OPT_SINGLE_STREAM, OPT_NO_SPARSE, OPT_FILES, OPT_FILES0, + OPT_BLOCK_SIZE, + OPT_BLOCK_LIST, OPT_MEM_COMPRESS, OPT_MEM_DECOMPRESS, OPT_NO_ADJUST, OPT_INFO_MEMORY, OPT_ROBOT, + OPT_FLUSH_TIMEOUT, + OPT_IGNORE_CHECK, }; static const char short_opts[] @@ -94,6 +161,7 @@ parse_real(args_info *args, int argc, char **argv) { "force", no_argument, NULL, 'f' }, { "stdout", no_argument, NULL, 'c' }, { "to-stdout", no_argument, NULL, 'c' }, + { "single-stream", no_argument, NULL, OPT_SINGLE_STREAM }, { "no-sparse", no_argument, NULL, OPT_NO_SPARSE }, { "suffix", required_argument, NULL, 'S' }, // { "recursive", no_argument, NULL, 'r' }, // TODO @@ -103,12 +171,16 @@ parse_real(args_info *args, int argc, char **argv) // Basic compression settings { "format", required_argument, NULL, 'F' }, { "check", required_argument, NULL, 'C' }, + { "ignore-check", no_argument, NULL, OPT_IGNORE_CHECK }, + { "block-size", required_argument, NULL, OPT_BLOCK_SIZE }, + { "block-list", required_argument, NULL, OPT_BLOCK_LIST }, { "memlimit-compress", required_argument, NULL, OPT_MEM_COMPRESS }, { "memlimit-decompress", required_argument, NULL, OPT_MEM_DECOMPRESS }, { "memlimit", required_argument, NULL, 'M' }, { "memory", required_argument, NULL, 'M' }, // Old alias { "no-adjust", no_argument, NULL, OPT_NO_ADJUST }, { "threads", required_argument, NULL, 'T' }, + { "flush-timeout", required_argument, NULL, OPT_FLUSH_TIMEOUT }, { "extreme", no_argument, NULL, 'e' }, { "fast", no_argument, NULL, '0' }, @@ -175,8 +247,9 @@ parse_real(args_info *args, int argc, char **argv) break; case 'T': - hardware_threadlimit_set(str_to_uint64( - "threads", optarg, 0, UINT32_MAX)); + // The max is from src/liblzma/common/common.h. + hardware_threads_set(str_to_uint64("threads", + optarg, 0, 16384)); break; // --version @@ -368,6 +441,24 @@ parse_real(args_info *args, int argc, char **argv) break; } + case OPT_IGNORE_CHECK: + opt_ignore_check = true; + break; + + case OPT_BLOCK_SIZE: + opt_block_size = str_to_uint64("block-size", optarg, + 0, LZMA_VLI_MAX); + break; + + case OPT_BLOCK_LIST: { + parse_block_list(optarg); + break; + } + + case OPT_SINGLE_STREAM: + opt_single_stream = true; + break; + case OPT_NO_SPARSE: io_no_sparse(); break; @@ -401,6 +492,11 @@ parse_real(args_info *args, int argc, char **argv) opt_auto_adjust = false; break; + case OPT_FLUSH_TIMEOUT: + opt_flush_timeout = str_to_uint64("flush-timeout", + optarg, 0, UINT64_MAX); + break; + default: message_try_help(); tuklib_exit(E_ERROR, E_ERROR, false); @@ -576,3 +672,13 @@ args_parse(args_info *args, int argc, char **argv) return; } + + +#ifndef NDEBUG +extern void +args_free(void) +{ + free(opt_block_list); + return; +} +#endif diff --git a/src/xz/args.h b/src/xz/args.h index b23f4ef12c92..1defad12e0dd 100644 --- a/src/xz/args.h +++ b/src/xz/args.h @@ -36,7 +36,9 @@ extern bool opt_force; extern bool opt_keep_original; // extern bool opt_recursive; extern bool opt_robot; +extern bool opt_ignore_check; extern const char stdin_filename[]; extern void args_parse(args_info *args, int argc, char **argv); +extern void args_free(void); diff --git a/src/xz/coder.c b/src/xz/coder.c index 017e04127e95..a94bdb83266f 100644 --- a/src/xz/coder.c +++ b/src/xz/coder.c @@ -24,6 +24,9 @@ enum coder_init_ret { enum operation_mode opt_mode = MODE_COMPRESS; enum format_type opt_format = FORMAT_AUTO; bool opt_auto_adjust = true; +bool opt_single_stream = false; +uint64_t opt_block_size = 0; +uint64_t *opt_block_list = NULL; /// Stream used to communicate with liblzma @@ -48,6 +51,14 @@ static lzma_check check; /// This becomes false if the --check=CHECK option is used. static bool check_default = true; +#ifdef MYTHREAD_ENABLED +static lzma_mt mt_options = { + .flags = 0, + .timeout = 300, + .filters = filters, +}; +#endif + extern void coder_set_check(lzma_check new_check) @@ -125,6 +136,15 @@ memlimit_too_small(uint64_t memory_usage) extern void coder_set_compression_settings(void) { + // The default check type is CRC64, but fallback to CRC32 + // if CRC64 isn't supported by the copy of liblzma we are + // using. CRC32 is always supported. + if (check_default) { + check = LZMA_CHECK_CRC64; + if (!lzma_check_is_supported(check)) + check = LZMA_CHECK_CRC32; + } + // Options for LZMA1 or LZMA2 in case we are using a preset. static lzma_options_lzma opt_lzma; @@ -175,15 +195,53 @@ coder_set_compression_settings(void) // Print the selected filter chain. message_filters_show(V_DEBUG, filters); - // If using --format=raw, we can be decoding. The memusage function - // also validates the filter chain and the options used for the - // filters. + // The --flush-timeout option requires LZMA_SYNC_FLUSH support + // from the filter chain. Currently threaded encoder doesn't support + // LZMA_SYNC_FLUSH so single-threaded mode must be used. + if (opt_mode == MODE_COMPRESS && opt_flush_timeout != 0) { + for (size_t i = 0; i < filters_count; ++i) { + switch (filters[i].id) { + case LZMA_FILTER_LZMA2: + case LZMA_FILTER_DELTA: + break; + + default: + message_fatal(_("The filter chain is " + "incompatible with --flush-timeout")); + } + } + + if (hardware_threads_get() > 1) { + message(V_WARNING, _("Switching to single-threaded " + "mode due to --flush-timeout")); + hardware_threads_set(1); + } + } + + // Get the memory usage. Note that if --format=raw was used, + // we can be decompressing. const uint64_t memory_limit = hardware_memlimit_get(opt_mode); uint64_t memory_usage; - if (opt_mode == MODE_COMPRESS) - memory_usage = lzma_raw_encoder_memusage(filters); - else + if (opt_mode == MODE_COMPRESS) { +#ifdef MYTHREAD_ENABLED + if (opt_format == FORMAT_XZ && hardware_threads_get() > 1) { + mt_options.threads = hardware_threads_get(); + mt_options.block_size = opt_block_size; + mt_options.check = check; + memory_usage = lzma_stream_encoder_mt_memusage( + &mt_options); + if (memory_usage != UINT64_MAX) + message(V_DEBUG, _("Using up to %" PRIu32 + " threads."), + mt_options.threads); + } else +#endif + { + memory_usage = lzma_raw_encoder_memusage(filters); + } + } else { memory_usage = lzma_raw_decoder_memusage(filters); + } if (memory_usage == UINT64_MAX) message_fatal(_("Unsupported filter chain or filter options")); @@ -199,90 +257,99 @@ coder_set_compression_settings(void) round_up_to_mib(decmem), 0)); } - if (memory_usage > memory_limit) { - // If --no-adjust was used or we didn't find LZMA1 or - // LZMA2 as the last filter, give an error immediately. - // --format=raw implies --no-adjust. - if (!opt_auto_adjust || opt_format == FORMAT_RAW) - memlimit_too_small(memory_usage); + if (memory_usage <= memory_limit) + return; - assert(opt_mode == MODE_COMPRESS); + // If --no-adjust was used or we didn't find LZMA1 or + // LZMA2 as the last filter, give an error immediately. + // --format=raw implies --no-adjust. + if (!opt_auto_adjust || opt_format == FORMAT_RAW) + memlimit_too_small(memory_usage); - // Look for the last filter if it is LZMA2 or LZMA1, so - // we can make it use less RAM. With other filters we don't - // know what to do. - size_t i = 0; - while (filters[i].id != LZMA_FILTER_LZMA2 - && filters[i].id != LZMA_FILTER_LZMA1) { - if (filters[i].id == LZMA_VLI_UNKNOWN) + assert(opt_mode == MODE_COMPRESS); + +#ifdef MYTHREAD_ENABLED + if (opt_format == FORMAT_XZ && mt_options.threads > 1) { + // Try to reduce the number of threads before + // adjusting the compression settings down. + do { + // FIXME? The real single-threaded mode has + // lower memory usage, but it's not comparable + // because it doesn't write the size info + // into Block Headers. + if (--mt_options.threads == 0) memlimit_too_small(memory_usage); - ++i; - } - - // Decrease the dictionary size until we meet the memory - // usage limit. First round down to full mebibytes. - lzma_options_lzma *opt = filters[i].options; - const uint32_t orig_dict_size = opt->dict_size; - opt->dict_size &= ~((UINT32_C(1) << 20) - 1); - while (true) { - // If it is below 1 MiB, auto-adjusting failed. We - // could be more sophisticated and scale it down even - // more, but let's see if many complain about this - // version. - // - // FIXME: Displays the scaled memory usage instead - // of the original. - if (opt->dict_size < (UINT32_C(1) << 20)) - memlimit_too_small(memory_usage); - - memory_usage = lzma_raw_encoder_memusage(filters); + memory_usage = lzma_stream_encoder_mt_memusage( + &mt_options); if (memory_usage == UINT64_MAX) message_bug(); - // Accept it if it is low enough. - if (memory_usage <= memory_limit) - break; + } while (memory_usage > memory_limit); - // Otherwise 1 MiB down and try again. I hope this - // isn't too slow method for cases where the original - // dict_size is very big. - opt->dict_size -= UINT32_C(1) << 20; - } + message(V_WARNING, _("Adjusted the number of threads " + "from %s to %s to not exceed " + "the memory usage limit of %s MiB"), + uint64_to_str(hardware_threads_get(), 0), + uint64_to_str(mt_options.threads, 1), + uint64_to_str(round_up_to_mib( + memory_limit), 2)); + } +#endif - // Tell the user that we decreased the dictionary size. - message(V_WARNING, _("Adjusted LZMA%c dictionary size " - "from %s MiB to %s MiB to not exceed " - "the memory usage limit of %s MiB"), - filters[i].id == LZMA_FILTER_LZMA2 - ? '2' : '1', - uint64_to_str(orig_dict_size >> 20, 0), - uint64_to_str(opt->dict_size >> 20, 1), - uint64_to_str(round_up_to_mib( - memory_limit), 2)); + if (memory_usage <= memory_limit) + return; + + // Look for the last filter if it is LZMA2 or LZMA1, so we can make + // it use less RAM. With other filters we don't know what to do. + size_t i = 0; + while (filters[i].id != LZMA_FILTER_LZMA2 + && filters[i].id != LZMA_FILTER_LZMA1) { + if (filters[i].id == LZMA_VLI_UNKNOWN) + memlimit_too_small(memory_usage); + + ++i; } -/* - // Limit the number of worker threads so that memory usage - // limit isn't exceeded. - assert(memory_usage > 0); - size_t thread_limit = memory_limit / memory_usage; - if (thread_limit == 0) - thread_limit = 1; + // Decrease the dictionary size until we meet the memory + // usage limit. First round down to full mebibytes. + lzma_options_lzma *opt = filters[i].options; + const uint32_t orig_dict_size = opt->dict_size; + opt->dict_size &= ~((UINT32_C(1) << 20) - 1); + while (true) { + // If it is below 1 MiB, auto-adjusting failed. We could be + // more sophisticated and scale it down even more, but let's + // see if many complain about this version. + // + // FIXME: Displays the scaled memory usage instead + // of the original. + if (opt->dict_size < (UINT32_C(1) << 20)) + memlimit_too_small(memory_usage); - if (opt_threads > thread_limit) - opt_threads = thread_limit; -*/ + memory_usage = lzma_raw_encoder_memusage(filters); + if (memory_usage == UINT64_MAX) + message_bug(); - if (check_default) { - // The default check type is CRC64, but fallback to CRC32 - // if CRC64 isn't supported by the copy of liblzma we are - // using. CRC32 is always supported. - check = LZMA_CHECK_CRC64; - if (!lzma_check_is_supported(check)) - check = LZMA_CHECK_CRC32; + // Accept it if it is low enough. + if (memory_usage <= memory_limit) + break; + + // Otherwise 1 MiB down and try again. I hope this + // isn't too slow method for cases where the original + // dict_size is very big. + opt->dict_size -= UINT32_C(1) << 20; } + // Tell the user that we decreased the dictionary size. + message(V_WARNING, _("Adjusted LZMA%c dictionary size " + "from %s MiB to %s MiB to not exceed " + "the memory usage limit of %s MiB"), + filters[i].id == LZMA_FILTER_LZMA2 + ? '2' : '1', + uint64_to_str(orig_dict_size >> 20, 0), + uint64_to_str(opt->dict_size >> 20, 1), + uint64_to_str(round_up_to_mib(memory_limit), 2)); + return; } @@ -364,7 +431,14 @@ coder_init(file_pair *pair) break; case FORMAT_XZ: - ret = lzma_stream_encoder(&strm, filters, check); +#ifdef MYTHREAD_ENABLED + if (hardware_threads_get() > 1) + ret = lzma_stream_encoder_mt( + &strm, &mt_options); + else +#endif + ret = lzma_stream_encoder( + &strm, filters, check); break; case FORMAT_LZMA: @@ -376,8 +450,17 @@ coder_init(file_pair *pair) break; } } else { - const uint32_t flags = LZMA_TELL_UNSUPPORTED_CHECK - | LZMA_CONCATENATED; + uint32_t flags = 0; + + // It seems silly to warn about unsupported check if the + // check won't be verified anyway due to --ignore-check. + if (opt_ignore_check) + flags |= LZMA_IGNORE_CHECK; + else + flags |= LZMA_TELL_UNSUPPORTED_CHECK; + + if (!opt_single_stream) + flags |= LZMA_CONCATENATED; // We abuse FORMAT_AUTO to indicate unknown file format, // for which we may consider passthru mode. @@ -408,7 +491,7 @@ coder_init(file_pair *pair) switch (init_format) { case FORMAT_AUTO: - // Uknown file format. If --decompress --stdout + // Unknown file format. If --decompress --stdout // --force have been given, then we copy the input // as is to stdout. Checking for MODE_DECOMPRESS // is needed, because we don't want to do use @@ -462,6 +545,56 @@ coder_init(file_pair *pair) } +/// Resolve conflicts between opt_block_size and opt_block_list in single +/// threaded mode. We want to default to opt_block_list, except when it is +/// larger than opt_block_size. If this is the case for the current Block +/// at *list_pos, then we break into smaller Blocks. Otherwise advance +/// to the next Block in opt_block_list, and break apart if needed. +static void +split_block(uint64_t *block_remaining, + uint64_t *next_block_remaining, + size_t *list_pos) +{ + if (*next_block_remaining > 0) { + // The Block at *list_pos has previously been split up. + assert(hardware_threads_get() == 1); + assert(opt_block_size > 0); + assert(opt_block_list != NULL); + + if (*next_block_remaining > opt_block_size) { + // We have to split the current Block at *list_pos + // into another opt_block_size length Block. + *block_remaining = opt_block_size; + } else { + // This is the last remaining split Block for the + // Block at *list_pos. + *block_remaining = *next_block_remaining; + } + + *next_block_remaining -= *block_remaining; + + } else { + // The Block at *list_pos has been finished. Go to the next + // entry in the list. If the end of the list has been reached, + // reuse the size of the last Block. + if (opt_block_list[*list_pos + 1] != 0) + ++*list_pos; + + *block_remaining = opt_block_list[*list_pos]; + + // If in single-threaded mode, split up the Block if needed. + // This is not needed in multi-threaded mode because liblzma + // will do this due to how threaded encoding works. + if (hardware_threads_get() == 1 && opt_block_size > 0 + && *block_remaining > opt_block_size) { + *next_block_remaining + = *block_remaining - opt_block_size; + *block_remaining = opt_block_size; + } + } +} + + /// Compress or decompress using liblzma. static bool coder_normal(file_pair *pair) @@ -469,8 +602,8 @@ coder_normal(file_pair *pair) // Encoder needs to know when we have given all the input to it. // The decoders need to know it too when we are using // LZMA_CONCATENATED. We need to check for src_eof here, because - // the first input chunk has been already read, and that may - // have been the only chunk we will read. + // the first input chunk has been already read if decompressing, + // and that may have been the only chunk we will read. lzma_action action = pair->src_eof ? LZMA_FINISH : LZMA_RUN; lzma_ret ret; @@ -478,22 +611,77 @@ coder_normal(file_pair *pair) // Assume that something goes wrong. bool success = false; + // block_remaining indicates how many input bytes to encode before + // finishing the current .xz Block. The Block size is set with + // --block-size=SIZE and --block-list. They have an effect only when + // compressing to the .xz format. If block_remaining == UINT64_MAX, + // only a single block is created. + uint64_t block_remaining = UINT64_MAX; + + // next_block_remining for when we are in single-threaded mode and + // the Block in --block-list is larger than the --block-size=SIZE. + uint64_t next_block_remaining = 0; + + // Position in opt_block_list. Unused if --block-list wasn't used. + size_t list_pos = 0; + + // Handle --block-size for single-threaded mode and the first step + // of --block-list. + if (opt_mode == MODE_COMPRESS && opt_format == FORMAT_XZ) { + // --block-size doesn't do anything here in threaded mode, + // because the threaded encoder will take care of splitting + // to fixed-sized Blocks. + if (hardware_threads_get() == 1 && opt_block_size > 0) + block_remaining = opt_block_size; + + // If --block-list was used, start with the first size. + // + // For threaded case, --block-size specifies how big Blocks + // the encoder needs to be prepared to create at maximum + // and --block-list will simultaneously cause new Blocks + // to be started at specified intervals. To keep things + // logical, the same is done in single-threaded mode. The + // output is still not identical because in single-threaded + // mode the size info isn't written into Block Headers. + if (opt_block_list != NULL) { + if (block_remaining < opt_block_list[list_pos]) { + assert(hardware_threads_get() == 1); + next_block_remaining = opt_block_list[list_pos] + - block_remaining; + } else { + block_remaining = opt_block_list[list_pos]; + } + } + } + strm.next_out = out_buf.u8; strm.avail_out = IO_BUFFER_SIZE; while (!user_abort) { - // Fill the input buffer if it is empty and we haven't reached - // end of file yet. - if (strm.avail_in == 0 && !pair->src_eof) { + // Fill the input buffer if it is empty and we aren't + // flushing or finishing. + if (strm.avail_in == 0 && action == LZMA_RUN) { strm.next_in = in_buf.u8; - strm.avail_in = io_read( - pair, &in_buf, IO_BUFFER_SIZE); + strm.avail_in = io_read(pair, &in_buf, + my_min(block_remaining, + IO_BUFFER_SIZE)); if (strm.avail_in == SIZE_MAX) break; - if (pair->src_eof) + if (pair->src_eof) { action = LZMA_FINISH; + + } else if (block_remaining != UINT64_MAX) { + // Start a new Block after every + // opt_block_size bytes of input. + block_remaining -= strm.avail_in; + if (block_remaining == 0) + action = LZMA_FULL_BARRIER; + } + + if (action == LZMA_RUN && flush_needed) + action = LZMA_SYNC_FLUSH; } // Let liblzma do the actual work. @@ -509,7 +697,39 @@ coder_normal(file_pair *pair) strm.avail_out = IO_BUFFER_SIZE; } - if (ret != LZMA_OK) { + if (ret == LZMA_STREAM_END && (action == LZMA_SYNC_FLUSH + || action == LZMA_FULL_BARRIER)) { + if (action == LZMA_SYNC_FLUSH) { + // Flushing completed. Write the pending data + // out immediatelly so that the reading side + // can decompress everything compressed so far. + if (io_write(pair, &out_buf, IO_BUFFER_SIZE + - strm.avail_out)) + break; + + strm.next_out = out_buf.u8; + strm.avail_out = IO_BUFFER_SIZE; + + // Set the time of the most recent flushing. + mytime_set_flush_time(); + } else { + // Start a new Block after LZMA_FULL_BARRIER. + if (opt_block_list == NULL) { + assert(hardware_threads_get() == 1); + assert(opt_block_size > 0); + block_remaining = opt_block_size; + } else { + split_block(&block_remaining, + &next_block_remaining, + &list_pos); + } + } + + // Start a new Block after LZMA_FULL_FLUSH or continue + // the same block after LZMA_SYNC_FLUSH. + action = LZMA_RUN; + + } else if (ret != LZMA_OK) { // Determine if the return value indicates that we // won't continue coding. const bool stop = ret != LZMA_NO_CHECK @@ -528,6 +748,12 @@ coder_normal(file_pair *pair) } if (ret == LZMA_STREAM_END) { + if (opt_single_stream) { + io_fix_src_pos(pair, strm.avail_in); + success = true; + break; + } + // Check that there is no trailing garbage. // This is needed for LZMA_Alone and raw // streams. @@ -630,10 +856,15 @@ coder_run(const char *filename) // Assume that something goes wrong. bool success = false; - // Read the first chunk of input data. This is needed to detect - // the input file type (for now, only for decompression). - strm.next_in = in_buf.u8; - strm.avail_in = io_read(pair, &in_buf, IO_BUFFER_SIZE); + if (opt_mode == MODE_COMPRESS) { + strm.next_in = NULL; + strm.avail_in = 0; + } else { + // Read the first chunk of input data. This is needed + // to detect the input file type. + strm.next_in = in_buf.u8; + strm.avail_in = io_read(pair, &in_buf, IO_BUFFER_SIZE); + } if (strm.avail_in != SIZE_MAX) { // Initialize the coder. This will detect the file format @@ -648,6 +879,11 @@ coder_run(const char *filename) // Don't open the destination file when --test // is used. if (opt_mode == MODE_TEST || !io_open_dest(pair)) { + // Remember the current time. It is needed + // for progress indicator and for timed + // flushing. + mytime_set_start_time(); + // Initialize the progress indicator. const uint64_t in_size = pair->src_st.st_size <= 0 @@ -671,3 +907,13 @@ coder_run(const char *filename) return; } + + +#ifndef NDEBUG +extern void +coder_free(void) +{ + lzma_end(&strm); + return; +} +#endif diff --git a/src/xz/coder.h b/src/xz/coder.h index 2d3add972745..583da8f68d50 100644 --- a/src/xz/coder.h +++ b/src/xz/coder.h @@ -41,6 +41,16 @@ extern enum format_type opt_format; /// they exceed the memory usage limit. extern bool opt_auto_adjust; +/// If true, stop after decoding the first stream. +extern bool opt_single_stream; + +/// If non-zero, start a new .xz Block after every opt_block_size bytes +/// of input. This has an effect only when compressing to the .xz format. +extern uint64_t opt_block_size; + +/// This is non-NULL if --block-list was used. This contains the Block sizes +/// as an array that is terminated with 0. +extern uint64_t *opt_block_list; /// Set the integrity check type used when compressing extern void coder_set_check(lzma_check check); @@ -59,3 +69,8 @@ extern void coder_set_compression_settings(void); /// Compress or decompress the given file extern void coder_run(const char *filename); + +#ifndef NDEBUG +/// Free the memory allocated for the coder and kill the worker threads. +extern void coder_free(void); +#endif diff --git a/src/xz/file_io.c b/src/xz/file_io.c index 871a099b6193..f135cf7cb6bd 100644 --- a/src/xz/file_io.c +++ b/src/xz/file_io.c @@ -17,6 +17,7 @@ #ifdef TUKLIB_DOSLIKE # include #else +# include static bool warn_fchown; #endif @@ -37,14 +38,30 @@ static bool warn_fchown; #endif +typedef enum { + IO_WAIT_MORE, // Reading or writing is possible. + IO_WAIT_ERROR, // Error or user_abort + IO_WAIT_TIMEOUT, // poll() timed out +} io_wait_ret; + + /// If true, try to create sparse files when decompressing. static bool try_sparse = true; #ifndef TUKLIB_DOSLIKE +/// File status flags of standard input. This is used by io_open_src() +/// and io_close_src(). +static int stdin_flags; +static bool restore_stdin_flags = false; + /// Original file status flags of standard output. This is used by /// io_open_dest() and io_close_dest() to save and restore the flags. static int stdout_flags; static bool restore_stdout_flags = false; + +/// Self-pipe used together with the user_abort variable to avoid +/// race conditions with signal handling. +static int user_abort_pipe[2]; #endif @@ -64,19 +81,43 @@ io_init(void) // If fchown() fails setting the owner, we warn about it only if // we are root. warn_fchown = geteuid() == 0; + + if (pipe(user_abort_pipe) + || fcntl(user_abort_pipe[0], F_SETFL, O_NONBLOCK) + == -1 + || fcntl(user_abort_pipe[1], F_SETFL, O_NONBLOCK) + == -1) + message_fatal(_("Error creating a pipe: %s"), + strerror(errno)); #endif #ifdef __DJGPP__ // Avoid doing useless things when statting files. // This isn't important but doesn't hurt. - _djstat_flags = _STAT_INODE | _STAT_EXEC_EXT - | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; + _djstat_flags = _STAT_EXEC_EXT | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; #endif return; } +#ifndef TUKLIB_DOSLIKE +extern void +io_write_to_user_abort_pipe(void) +{ + // If the write() fails, it's probably due to the pipe being full. + // Failing in that case is fine. If the reason is something else, + // there's not much we can do since this is called in a signal + // handler. So ignore the errors and try to avoid warnings with + // GCC and glibc when _FORTIFY_SOURCE=2 is used. + uint8_t b = '\0'; + const int ret = write(user_abort_pipe[1], &b, 1); + (void)ret; + return; +} +#endif + + extern void io_no_sparse(void) { @@ -85,6 +126,63 @@ io_no_sparse(void) } +#ifndef TUKLIB_DOSLIKE +/// \brief Waits for input or output to become available or for a signal +/// +/// This uses the self-pipe trick to avoid a race condition that can occur +/// if a signal is caught after user_abort has been checked but before e.g. +/// read() has been called. In that situation read() could block unless +/// non-blocking I/O is used. With non-blocking I/O something like select() +/// or poll() is needed to avoid a busy-wait loop, and the same race condition +/// pops up again. There are pselect() (POSIX-1.2001) and ppoll() (not in +/// POSIX) but neither is portable enough in 2013. The self-pipe trick is +/// old and very portable. +static io_wait_ret +io_wait(file_pair *pair, int timeout, bool is_reading) +{ + struct pollfd pfd[2]; + + if (is_reading) { + pfd[0].fd = pair->src_fd; + pfd[0].events = POLLIN; + } else { + pfd[0].fd = pair->dest_fd; + pfd[0].events = POLLOUT; + } + + pfd[1].fd = user_abort_pipe[0]; + pfd[1].events = POLLIN; + + while (true) { + const int ret = poll(pfd, 2, timeout); + + if (user_abort) + return IO_WAIT_ERROR; + + if (ret == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + + message_error(_("%s: poll() failed: %s"), + is_reading ? pair->src_name + : pair->dest_name, + strerror(errno)); + return IO_WAIT_ERROR; + } + + if (ret == 0) { + assert(opt_flush_timeout != 0); + flush_needed = true; + return IO_WAIT_TIMEOUT; + } + + if (pfd[0].revents != 0) + return IO_WAIT_MORE; + } +} +#endif + + /// \brief Unlink a file /// /// This tries to verify that the file being unlinked really is the file that @@ -294,6 +392,31 @@ io_open_src_real(file_pair *pair) pair->src_fd = STDIN_FILENO; #ifdef TUKLIB_DOSLIKE setmode(STDIN_FILENO, O_BINARY); +#else + // Enable O_NONBLOCK for stdin. + stdin_flags = fcntl(STDIN_FILENO, F_GETFL); + if (stdin_flags == -1) { + message_error(_("Error getting the file status flags " + "from standard input: %s"), + strerror(errno)); + return true; + } + + if ((stdin_flags & O_NONBLOCK) == 0) { + if (fcntl(STDIN_FILENO, F_SETFL, + stdin_flags | O_NONBLOCK) == -1) { + message_error(_("Error setting O_NONBLOCK " + "on standard input: %s"), + strerror(errno)); + return true; + } + + restore_stdin_flags = true; + } +#endif +#ifdef HAVE_POSIX_FADVISE + // It will fail if stdin is a pipe and that's fine. + (void)posix_fadvise(STDIN_FILENO, 0, 0, POSIX_FADV_SEQUENTIAL); #endif return false; } @@ -311,13 +434,12 @@ io_open_src_real(file_pair *pair) int flags = O_RDONLY | O_BINARY | O_NOCTTY; #ifndef TUKLIB_DOSLIKE - // If we accept only regular files, we need to be careful to avoid - // problems with special files like devices and FIFOs. O_NONBLOCK - // prevents blocking when opening such files. When we want to accept - // special files, we must not use O_NONBLOCK, or otherwise we won't - // block waiting e.g. FIFOs to become readable. - if (reg_files_only) - flags |= O_NONBLOCK; + // Use non-blocking I/O: + // - It prevents blocking when opening FIFOs and some other + // special files, which is good if we want to accept only + // regular files. + // - It can help avoiding some race conditions with signal handling. + flags |= O_NONBLOCK; #endif #if defined(O_NOFOLLOW) @@ -345,30 +467,13 @@ io_open_src_real(file_pair *pair) (void)follow_symlinks; #endif - // Try to open the file. If we are accepting non-regular files, - // unblock the caught signals so that open() can be interrupted - // if it blocks e.g. due to a FIFO file. - if (!reg_files_only) - signals_unblock(); - - // Maybe this wouldn't need a loop, since all the signal handlers for - // which we don't use SA_RESTART set user_abort to true. But it - // doesn't hurt to have it just in case. - do { - pair->src_fd = open(pair->src_name, flags); - } while (pair->src_fd == -1 && errno == EINTR && !user_abort); - - if (!reg_files_only) - signals_block(); + // Try to open the file. Signals have been blocked so EINTR shouldn't + // be possible. + pair->src_fd = open(pair->src_name, flags); if (pair->src_fd == -1) { - // If we were interrupted, don't display any error message. - if (errno == EINTR) { - // All the signals that don't have SA_RESTART - // set user_abort. - assert(user_abort); - return true; - } + // Signals (that have a signal handler) have been blocked. + assert(errno != EINTR); #ifdef O_NOFOLLOW // Give an understandable error message if the reason @@ -427,26 +532,20 @@ io_open_src_real(file_pair *pair) return true; } -#ifndef TUKLIB_DOSLIKE - // Drop O_NONBLOCK, which is used only when we are accepting only - // regular files. After the open() call, we want things to block - // instead of giving EAGAIN. - if (reg_files_only) { - flags = fcntl(pair->src_fd, F_GETFL); - if (flags == -1) - goto error_msg; - - flags &= ~O_NONBLOCK; - - if (fcntl(pair->src_fd, F_SETFL, flags) == -1) - goto error_msg; - } -#endif - // Stat the source file. We need the result also when we copy // the permissions, and when unlinking. + // + // NOTE: Use stat() instead of fstat() with DJGPP, because + // then we have a better chance to get st_ino value that can + // be used in io_open_dest_real() to prevent overwriting the + // source file. +#ifdef __DJGPP__ + if (stat(pair->src_name, &pair->src_st)) + goto error_msg; +#else if (fstat(pair->src_fd, &pair->src_st)) goto error_msg; +#endif if (S_ISDIR(pair->src_st.st_mode)) { message_warning(_("%s: Is a directory, skipping"), @@ -492,6 +591,23 @@ io_open_src_real(file_pair *pair) goto error; } } + + // If it is something else than a regular file, wait until + // there is input available. This way reading from FIFOs + // will work when open() is used with O_NONBLOCK. + if (!S_ISREG(pair->src_st.st_mode)) { + signals_unblock(); + const io_wait_ret ret = io_wait(pair, -1, true); + signals_block(); + + if (ret != IO_WAIT_MORE) + goto error; + } +#endif + +#ifdef HAVE_POSIX_FADVISE + // It will fail with some special files like FIFOs but that is fine. + (void)posix_fadvise(pair->src_fd, 0, 0, POSIX_FADV_SEQUENTIAL); #endif return false; @@ -542,6 +658,19 @@ io_open_src(const char *src_name) static void io_close_src(file_pair *pair, bool success) { +#ifndef TUKLIB_DOSLIKE + if (restore_stdin_flags) { + assert(pair->src_fd == STDIN_FILENO); + + restore_stdin_flags = false; + + if (fcntl(STDIN_FILENO, F_SETFL, stdin_flags) == -1) + message_error(_("Error restoring the status flags " + "to standard input: %s"), + strerror(errno)); + } +#endif + if (pair->src_fd != STDIN_FILENO && pair->src_fd != -1) { #ifdef TUKLIB_DOSLIKE (void)close(pair->src_fd); @@ -575,12 +704,58 @@ io_open_dest_real(file_pair *pair) pair->dest_fd = STDOUT_FILENO; #ifdef TUKLIB_DOSLIKE setmode(STDOUT_FILENO, O_BINARY); +#else + // Set O_NONBLOCK if it isn't already set. + // + // NOTE: O_APPEND may be unset later in this function + // and it relies on stdout_flags being set here. + stdout_flags = fcntl(STDOUT_FILENO, F_GETFL); + if (stdout_flags == -1) { + message_error(_("Error getting the file status flags " + "from standard output: %s"), + strerror(errno)); + return true; + } + + if ((stdout_flags & O_NONBLOCK) == 0) { + if (fcntl(STDOUT_FILENO, F_SETFL, + stdout_flags | O_NONBLOCK) == -1) { + message_error(_("Error setting O_NONBLOCK " + "on standard output: %s"), + strerror(errno)); + return true; + } + + restore_stdout_flags = true; + } #endif } else { pair->dest_name = suffix_get_dest_name(pair->src_name); if (pair->dest_name == NULL) return true; +#ifdef __DJGPP__ + struct stat st; + if (stat(pair->dest_name, &st) == 0) { + // Check that it isn't a special file like "prn". + if (st.st_dev == -1) { + message_error("%s: Refusing to write to " + "a DOS special file", + pair->dest_name); + return true; + } + + // Check that we aren't overwriting the source file. + if (st.st_dev == pair->src_st.st_dev + && st.st_ino == pair->src_st.st_ino) { + message_error("%s: Output file is the same " + "as the input file", + pair->dest_name); + return true; + } + } +#endif + // If --force was used, unlink the target file first. if (opt_force && unlink(pair->dest_name) && errno != ENOENT) { message_error(_("%s: Cannot remove: %s"), @@ -590,8 +765,11 @@ io_open_dest_real(file_pair *pair) } // Open the file. - const int flags = O_WRONLY | O_BINARY | O_NOCTTY + int flags = O_WRONLY | O_BINARY | O_NOCTTY | O_CREAT | O_EXCL; +#ifndef TUKLIB_DOSLIKE + flags |= O_NONBLOCK; +#endif const mode_t mode = S_IRUSR | S_IWUSR; pair->dest_fd = open(pair->dest_name, flags, mode); @@ -603,17 +781,19 @@ io_open_dest_real(file_pair *pair) } } - // If this really fails... well, we have a safe fallback. +#ifndef TUKLIB_DOSLIKE + // dest_st isn't used on DOS-like systems except as a dummy + // argument to io_unlink(), so don't fstat() on such systems. if (fstat(pair->dest_fd, &pair->dest_st)) { -#if defined(__VMS) + // If fstat() really fails, we have a safe fallback here. +# if defined(__VMS) pair->dest_st.st_ino[0] = 0; pair->dest_st.st_ino[1] = 0; pair->dest_st.st_ino[2] = 0; -#elif !defined(TUKLIB_DOSLIKE) +# else pair->dest_st.st_dev = 0; pair->dest_st.st_ino = 0; -#endif -#ifndef TUKLIB_DOSLIKE +# endif } else if (try_sparse && opt_mode == MODE_DECOMPRESS) { // When writing to standard output, we need to be extra // careful: @@ -631,10 +811,6 @@ io_open_dest_real(file_pair *pair) if (!S_ISREG(pair->dest_st.st_mode)) return false; - stdout_flags = fcntl(STDOUT_FILENO, F_GETFL); - if (stdout_flags == -1) - return false; - if (stdout_flags & O_APPEND) { // Creating a sparse file is not possible // when O_APPEND is active (it's used by @@ -653,14 +829,23 @@ io_open_dest_real(file_pair *pair) if (lseek(STDOUT_FILENO, 0, SEEK_END) == -1) return false; + // O_NONBLOCK was set earlier in this function + // so it must be kept here too. If this + // fcntl() call fails, we continue but won't + // try to create sparse output. The original + // flags will still be restored if needed (to + // unset O_NONBLOCK) when the file is finished. if (fcntl(STDOUT_FILENO, F_SETFL, - stdout_flags & ~O_APPEND) - == -1) + (stdout_flags | O_NONBLOCK) + & ~O_APPEND) == -1) return false; // Disabling O_APPEND succeeded. Mark // that the flags should be restored - // in io_close_dest(). + // in io_close_dest(). This quite likely was + // already set when enabling O_NONBLOCK but + // just in case O_NONBLOCK was already set, + // set this again here. restore_stdout_flags = true; } else if (lseek(STDOUT_FILENO, 0, SEEK_CUR) @@ -673,8 +858,8 @@ io_open_dest_real(file_pair *pair) } pair->dest_try_sparse = true; -#endif } +#endif return false; } @@ -790,6 +975,21 @@ io_close(file_pair *pair, bool success) } +extern void +io_fix_src_pos(file_pair *pair, size_t rewind_size) +{ + assert(rewind_size <= IO_BUFFER_SIZE); + + if (rewind_size > 0) { + // This doesn't need to work on unseekable file descriptors, + // so just ignore possible errors. + (void)lseek(pair->src_fd, -(off_t)(rewind_size), SEEK_CUR); + } + + return; +} + + extern size_t io_read(file_pair *pair, io_buf *buf_union, size_t size) { @@ -815,12 +1015,30 @@ io_read(file_pair *pair, io_buf *buf_union, size_t size) continue; } +#ifndef TUKLIB_DOSLIKE + if (errno == EAGAIN || errno == EWOULDBLOCK) { + const io_wait_ret ret = io_wait(pair, + mytime_get_flush_timeout(), + true); + switch (ret) { + case IO_WAIT_MORE: + continue; + + case IO_WAIT_ERROR: + return SIZE_MAX; + + case IO_WAIT_TIMEOUT: + return size - left; + + default: + message_bug(); + } + } +#endif + message_error(_("%s: Read error: %s"), pair->src_name, strerror(errno)); - // FIXME Is this needed? - pair->src_eof = true; - return SIZE_MAX; } @@ -885,6 +1103,15 @@ io_write_buf(file_pair *pair, const uint8_t *buf, size_t size) continue; } +#ifndef TUKLIB_DOSLIKE + if (errno == EAGAIN || errno == EWOULDBLOCK) { + if (io_wait(pair, -1, false) == IO_WAIT_MORE) + continue; + + return true; + } +#endif + // Handle broken pipe specially. gzip and bzip2 // don't print anything on SIGPIPE. In addition, // gzip --quiet uses exit status 2 (warning) on diff --git a/src/xz/file_io.h b/src/xz/file_io.h index 967da868b079..2de3379238d6 100644 --- a/src/xz/file_io.h +++ b/src/xz/file_io.h @@ -68,6 +68,14 @@ typedef struct { extern void io_init(void); +#ifndef TUKLIB_DOSLIKE +/// \brief Write a byte to user_abort_pipe[1] +/// +/// This is called from a signal handler. +extern void io_write_to_user_abort_pipe(void); +#endif + + /// \brief Disable creation of sparse files when decompressing extern void io_no_sparse(void); @@ -102,6 +110,19 @@ extern void io_close(file_pair *pair, bool success); extern size_t io_read(file_pair *pair, io_buf *buf, size_t size); +/// \brief Fix the position in src_fd +/// +/// This is used when --single-thream has been specified and decompression +/// is successful. If the input file descriptor supports seeking, this +/// function fixes the input position to point to the next byte after the +/// decompressed stream. +/// +/// \param pair File pair having the source file open for reading +/// \param rewind_size How many bytes of extra have been read i.e. +/// how much to seek backwards. +extern void io_fix_src_pos(file_pair *pair, size_t rewind_size); + + /// \brief Read from source file from given offset to a buffer /// /// This is remotely similar to standard pread(). This uses lseek() though, diff --git a/src/xz/hardware.c b/src/xz/hardware.c index a4733c27e118..ff32f6d30148 100644 --- a/src/xz/hardware.c +++ b/src/xz/hardware.c @@ -11,12 +11,11 @@ /////////////////////////////////////////////////////////////////////////////// #include "private.h" -#include "tuklib_cpucores.h" -/// Maximum number of free *coder* threads. This can be set with +/// Maximum number of worker threads. This can be set with /// the --threads=NUM command line option. -static uint32_t threadlimit; +static uint32_t threads_max = 1; /// Memory usage limit for compression static uint64_t memlimit_compress; @@ -29,15 +28,23 @@ static uint64_t total_ram; extern void -hardware_threadlimit_set(uint32_t new_threadlimit) +hardware_threads_set(uint32_t n) { - if (new_threadlimit == 0) { - // The default is the number of available CPU cores. - threadlimit = tuklib_cpucores(); - if (threadlimit == 0) - threadlimit = 1; + if (n == 0) { + // Automatic number of threads was requested. + // If threading support was enabled at build time, + // use the number of available CPU cores. Otherwise + // use one thread since disabling threading support + // omits lzma_cputhreads() from liblzma. +#ifdef MYTHREAD_ENABLED + threads_max = lzma_cputhreads(); + if (threads_max == 0) + threads_max = 1; +#else + threads_max = 1; +#endif } else { - threadlimit = new_threadlimit; + threads_max = n; } return; @@ -45,9 +52,9 @@ hardware_threadlimit_set(uint32_t new_threadlimit) extern uint32_t -hardware_threadlimit_get(void) +hardware_threads_get(void) { - return threadlimit; + return threads_max; } @@ -139,6 +146,5 @@ hardware_init(void) // Set the defaults. hardware_memlimit_set(0, true, true, false); - hardware_threadlimit_set(0); return; } diff --git a/src/xz/hardware.h b/src/xz/hardware.h index ad526f260bc1..4fae61815656 100644 --- a/src/xz/hardware.h +++ b/src/xz/hardware.h @@ -15,12 +15,11 @@ extern void hardware_init(void); -/// Set custom value for maximum number of coder threads. -extern void hardware_threadlimit_set(uint32_t threadlimit); +/// Set the maximum number of worker threads. +extern void hardware_threads_set(uint32_t threadlimit); -/// Get the maximum number of coder threads. Some additional helper threads -/// are allowed on top of this). -extern uint32_t hardware_threadlimit_get(void); +/// Get the maximum number of worker threads. +extern uint32_t hardware_threads_get(void); /// Set the memory usage limit. There are separate limits for compression diff --git a/src/xz/list.c b/src/xz/list.c index 0e73d519ea4a..449c2bc4e02f 100644 --- a/src/xz/list.c +++ b/src/xz/list.c @@ -29,9 +29,12 @@ typedef struct { /// Uncompressed Size fields bool all_have_sizes; + /// Oldest XZ Utils version that will decompress the file + uint32_t min_version; + } xz_file_info; -#define XZ_FILE_INFO_INIT { NULL, 0, 0, true } +#define XZ_FILE_INFO_INIT { NULL, 0, 0, true, 50000002 } /// Information about a .xz Block @@ -104,8 +107,32 @@ static struct { uint64_t stream_padding; uint64_t memusage_max; uint32_t checks; + uint32_t min_version; bool all_have_sizes; -} totals = { 0, 0, 0, 0, 0, 0, 0, 0, true }; +} totals = { 0, 0, 0, 0, 0, 0, 0, 0, 0, true }; + + +/// Convert XZ Utils version number to a string. +static const char * +xz_ver_to_str(uint32_t ver) +{ + static char buf[32]; + + unsigned int major = ver / 10000000U; + ver -= major * 10000000U; + + unsigned int minor = ver / 10000U; + ver -= minor * 10000U; + + unsigned int patch = ver / 10U; + ver -= patch * 10U; + + const char *stability = ver == 0 ? "alpha" : ver == 1 ? "beta" : ""; + + snprintf(buf, sizeof(buf), "%u.%u.%u%s", + major, minor, patch, stability); + return buf; +} /// \brief Parse the Index(es) from the given .xz file @@ -478,6 +505,21 @@ parse_block_header(file_pair *pair, const lzma_index_iter *iter, if (xfi->memusage_max < bhi->memusage) xfi->memusage_max = bhi->memusage; + // Determine the minimum XZ Utils version that supports this Block. + // + // Currently the only thing that 5.0.0 doesn't support is empty + // LZMA2 Block. This decoder bug was fixed in 5.0.2. + { + size_t i = 0; + while (filters[i + 1].id != LZMA_VLI_UNKNOWN) + ++i; + + if (filters[i].id == LZMA_FILTER_LZMA2 + && iter->block.uncompressed_size == 0 + && xfi->min_version < 50000022U) + xfi->min_version = 50000022U; + } + // Convert the filter chain to human readable form. message_filters_to_str(bhi->filter_chain, filters, false); @@ -856,6 +898,8 @@ print_info_adv(xz_file_info *xfi, file_pair *pair) round_up_to_mib(xfi->memusage_max), 0)); printf(_(" Sizes in headers: %s\n"), xfi->all_have_sizes ? _("Yes") : _("No")); + printf(_(" Minimum XZ Utils version: %s\n"), + xz_ver_to_str(xfi->min_version)); } return false; @@ -938,9 +982,10 @@ print_info_robot(xz_file_info *xfi, file_pair *pair) } if (message_verbosity_get() >= V_DEBUG) - printf("summary\t%" PRIu64 "\t%s\n", + printf("summary\t%" PRIu64 "\t%s\t%" PRIu32 "\n", xfi->memusage_max, - xfi->all_have_sizes ? "yes" : "no"); + xfi->all_have_sizes ? "yes" : "no", + xfi->min_version); return false; } @@ -961,6 +1006,9 @@ update_totals(const xz_file_info *xfi) if (totals.memusage_max < xfi->memusage_max) totals.memusage_max = xfi->memusage_max; + if (totals.min_version < xfi->min_version) + totals.min_version = xfi->min_version; + totals.all_have_sizes &= xfi->all_have_sizes; return; @@ -1025,6 +1073,8 @@ print_totals_adv(void) round_up_to_mib(totals.memusage_max), 0)); printf(_(" Sizes in headers: %s\n"), totals.all_have_sizes ? _("Yes") : _("No")); + printf(_(" Minimum XZ Utils version: %s\n"), + xz_ver_to_str(totals.min_version)); } return; @@ -1050,9 +1100,10 @@ print_totals_robot(void) totals.files); if (message_verbosity_get() >= V_DEBUG) - printf("\t%" PRIu64 "\t%s", + printf("\t%" PRIu64 "\t%s\t%" PRIu32, totals.memusage_max, - totals.all_have_sizes ? "yes" : "no"); + totals.all_have_sizes ? "yes" : "no", + totals.min_version); putchar('\n'); diff --git a/src/xz/main.c b/src/xz/main.c index 8196c6e7e774..a8f0683a47bd 100644 --- a/src/xz/main.c +++ b/src/xz/main.c @@ -275,6 +275,11 @@ main(int argc, char **argv) list_totals(); } +#ifndef NDEBUG + coder_free(); + args_free(); +#endif + // If we have got a signal, raise it to kill the program instead // of calling tuklib_exit(). signals_exit(); diff --git a/src/xz/message.c b/src/xz/message.c index 0a7a522f7afa..8a31b00ed89c 100644 --- a/src/xz/message.c +++ b/src/xz/message.c @@ -12,10 +12,6 @@ #include "private.h" -#ifdef HAVE_SYS_TIME_H -# include -#endif - #include @@ -64,9 +60,6 @@ static lzma_stream *progress_strm; /// and estimate remaining time. static uint64_t expected_in_size; -/// Time when we started processing the file -static uint64_t start_time; - // Use alarm() and SIGALRM when they are supported. This has two minor // advantages over the alternative of polling gettimeofday(): @@ -112,16 +105,6 @@ static uint64_t progress_next_update; #endif -/// Get the current time as microseconds since epoch -static uint64_t -my_time(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (uint64_t)(tv.tv_sec) * UINT64_C(1000000) + tv.tv_usec; -} - - extern void message_init(void) { @@ -264,11 +247,10 @@ message_progress_start(lzma_stream *strm, uint64_t in_size) // It is needed to find out the position in the stream. progress_strm = strm; - // Store the processing start time of the file and its expected size. - // If we aren't printing any statistics, then these are unused. But - // since it is possible that the user sends us a signal to show - // statistics, we need to have these available anyway. - start_time = my_time(); + // Store the expected size of the file. If we aren't printing any + // statistics, then is will be unused. But since it is possible + // that the user sends us a signal to show statistics, we need + // to have it available anyway. expected_in_size = in_size; // Indicate that progress info may need to be printed before @@ -290,7 +272,7 @@ message_progress_start(lzma_stream *strm, uint64_t in_size) alarm(1); #else progress_needs_updating = true; - progress_next_update = 1000000; + progress_next_update = 1000; #endif } @@ -364,7 +346,7 @@ progress_speed(uint64_t uncompressed_pos, uint64_t elapsed) { // Don't print the speed immediately, since the early values look // somewhat random. - if (elapsed < 3000000) + if (elapsed < 3000) return ""; static const char unit[][8] = { @@ -377,7 +359,7 @@ progress_speed(uint64_t uncompressed_pos, uint64_t elapsed) // Calculate the speed as KiB/s. double speed = (double)(uncompressed_pos) - / ((double)(elapsed) * (1024.0 / 1e6)); + / ((double)(elapsed) * (1024.0 / 1000.0)); // Adjust the unit of the speed if needed. while (speed > 999.0) { @@ -402,12 +384,12 @@ progress_speed(uint64_t uncompressed_pos, uint64_t elapsed) /// Make a string indicating elapsed or remaining time. The format is either /// M:SS or H:MM:SS depending on if the time is an hour or more. static const char * -progress_time(uint64_t useconds) +progress_time(uint64_t mseconds) { // 9999 hours = 416 days static char buf[sizeof("9999:59:59")]; - uint32_t seconds = useconds / 1000000; + uint32_t seconds = mseconds / 1000; // Don't show anything if the time is zero or ridiculously big. if (seconds == 0 || seconds > ((9999 * 60) + 59) * 60 + 59) @@ -445,14 +427,14 @@ progress_remaining(uint64_t in_pos, uint64_t elapsed) // - Only a few seconds has passed since we started (de)compressing, // so estimate would be too inaccurate. if (expected_in_size == 0 || in_pos > expected_in_size - || in_pos < (UINT64_C(1) << 19) || elapsed < 8000000) + || in_pos < (UINT64_C(1) << 19) || elapsed < 8000) return ""; // Calculate the estimate. Don't give an estimate of zero seconds, // since it is possible that all the input has been already passed // to the library, but there is still quite a bit of output pending. uint32_t remaining = (double)(expected_in_size - in_pos) - * ((double)(elapsed) / 1e6) / (double)(in_pos); + * ((double)(elapsed) / 1000.0) / (double)(in_pos); if (remaining < 1) remaining = 1; @@ -518,28 +500,26 @@ progress_remaining(uint64_t in_pos, uint64_t elapsed) } -/// Calculate the elapsed time as microseconds. -static uint64_t -progress_elapsed(void) -{ - return my_time() - start_time; -} - - -/// Get information about position in the stream. This is currently simple, -/// but it will become more complicated once we have multithreading support. +/// Get how much uncompressed and compressed data has been processed. static void progress_pos(uint64_t *in_pos, uint64_t *compressed_pos, uint64_t *uncompressed_pos) { - *in_pos = progress_strm->total_in; + uint64_t out_pos; + lzma_get_progress(progress_strm, in_pos, &out_pos); + + // It cannot have processed more input than it has been given. + assert(*in_pos <= progress_strm->total_in); + + // It cannot have produced more output than it claims to have ready. + assert(out_pos >= progress_strm->total_out); if (opt_mode == MODE_COMPRESS) { - *compressed_pos = progress_strm->total_out; - *uncompressed_pos = progress_strm->total_in; + *compressed_pos = out_pos; + *uncompressed_pos = *in_pos; } else { - *compressed_pos = progress_strm->total_in; - *uncompressed_pos = progress_strm->total_out; + *compressed_pos = *in_pos; + *uncompressed_pos = out_pos; } return; @@ -553,13 +533,13 @@ message_progress_update(void) return; // Calculate how long we have been processing this file. - const uint64_t elapsed = progress_elapsed(); + const uint64_t elapsed = mytime_get_elapsed(); #ifndef SIGALRM if (progress_next_update > elapsed) return; - progress_next_update = elapsed + 1000000; + progress_next_update = elapsed + 1000; #endif // Get our current position in the stream. @@ -652,7 +632,7 @@ progress_flush(bool finished) progress_active = false; - const uint64_t elapsed = progress_elapsed(); + const uint64_t elapsed = mytime_get_elapsed(); signals_block(); @@ -1122,7 +1102,10 @@ message_help(bool long_help) " -f, --force force overwrite of output file and (de)compress links\n" " -c, --stdout write to standard output and don't delete input files")); - if (long_help) + if (long_help) { + puts(_( +" --single-stream decompress only the first stream, and silently\n" +" ignore possible remaining input data")); puts(_( " --no-sparse do not create sparse files when decompressing\n" " -S, --suffix=.SUF use the suffix `.SUF' on compressed files\n" @@ -1130,6 +1113,7 @@ message_help(bool long_help) " omitted, filenames are read from the standard input;\n" " filenames must be terminated with the newline character\n" " --files0[=FILE] like --files but use the null character as terminator")); + } if (long_help) { puts(_("\n Basic file format and compression options:\n")); @@ -1138,6 +1122,8 @@ message_help(bool long_help) " `auto' (default), `xz', `lzma', and `raw'\n" " -C, --check=CHECK integrity check type: `none' (use with caution),\n" " `crc32', `crc64' (default), or `sha256'")); + puts(_( +" --ignore-check don't verify the integrity check when decompressing")); } puts(_( @@ -1148,7 +1134,25 @@ message_help(bool long_help) " -e, --extreme try to improve compression ratio by using more CPU time;\n" " does not affect decompressor memory requirements")); + puts(_( +" -T, --threads=NUM use at most NUM threads; the default is 1; set to 0\n" +" to use as many threads as there are processor cores")); + if (long_help) { + puts(_( +" --block-size=SIZE\n" +" start a new .xz block after every SIZE bytes of input;\n" +" use this to set the block size for threaded compression")); + puts(_( +" --block-list=SIZES\n" +" start a new .xz block after the given comma-separated\n" +" intervals of uncompressed data")); + puts(_( +" --flush-timeout=TIMEOUT\n" +" when compressing, if more than TIMEOUT milliseconds has\n" +" passed since the previous flush and reading more input\n" +" would block, all pending data is flushed out" + )); puts(_( // xgettext:no-c-format " --memlimit-compress=LIMIT\n" " --memlimit-decompress=LIMIT\n" @@ -1244,5 +1248,10 @@ message_help(bool long_help) PACKAGE_BUGREPORT); printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); +#if LZMA_VERSION_STABILITY != LZMA_VERSION_STABILITY_STABLE + puts(_( +"THIS IS A DEVELOPMENT VERSION NOT INTENDED FOR PRODUCTION USE.")); +#endif + tuklib_exit(E_SUCCESS, E_ERROR, verbosity != V_SILENT); } diff --git a/src/xz/mytime.c b/src/xz/mytime.c new file mode 100644 index 000000000000..4be184fd19da --- /dev/null +++ b/src/xz/mytime.c @@ -0,0 +1,89 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file mytime.c +/// \brief Time handling functions +// +// Author: Lasse Collin +// +// This file has been put into the public domain. +// You can do whatever you want with this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "private.h" + +#if !(defined(HAVE_CLOCK_GETTIME) && HAVE_DECL_CLOCK_MONOTONIC) +# include +#endif + +uint64_t opt_flush_timeout = 0; +bool flush_needed; + +static uint64_t start_time; +static uint64_t next_flush; + + +/// \brief Get the current time as milliseconds +/// +/// It's relative to some point but not necessarily to the UNIX Epoch. +static uint64_t +mytime_now(void) +{ + // NOTE: HAVE_DECL_CLOCK_MONOTONIC is always defined to 0 or 1. +#if defined(HAVE_CLOCK_GETTIME) && HAVE_DECL_CLOCK_MONOTONIC + // If CLOCK_MONOTONIC was available at compile time but for some + // reason isn't at runtime, fallback to CLOCK_REALTIME which + // according to POSIX is mandatory for all implementations. + static clockid_t clk_id = CLOCK_MONOTONIC; + struct timespec tv; + while (clock_gettime(clk_id, &tv)) + clk_id = CLOCK_REALTIME; + + return (uint64_t)(tv.tv_sec) * UINT64_C(1000) + tv.tv_nsec / 1000000; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t)(tv.tv_sec) * UINT64_C(1000) + tv.tv_usec / 1000; +#endif +} + + +extern void +mytime_set_start_time(void) +{ + start_time = mytime_now(); + next_flush = start_time + opt_flush_timeout; + flush_needed = false; + return; +} + + +extern uint64_t +mytime_get_elapsed(void) +{ + return mytime_now() - start_time; +} + + +extern void +mytime_set_flush_time(void) +{ + next_flush = mytime_now() + opt_flush_timeout; + flush_needed = false; + return; +} + + +extern int +mytime_get_flush_timeout(void) +{ + if (opt_flush_timeout == 0 || opt_mode != MODE_COMPRESS) + return -1; + + const uint64_t now = mytime_now(); + if (now >= next_flush) + return 0; + + const uint64_t remaining = next_flush - now; + return remaining > INT_MAX ? INT_MAX : (int)remaining; +} diff --git a/src/xz/mytime.h b/src/xz/mytime.h new file mode 100644 index 000000000000..ea291eed81c7 --- /dev/null +++ b/src/xz/mytime.h @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file mytime.h +/// \brief Time handling functions +// +// Author: Lasse Collin +// +// This file has been put into the public domain. +// You can do whatever you want with this file. +// +/////////////////////////////////////////////////////////////////////////////// + + +/// \brief Number of milliseconds to between LZMA_SYNC_FLUSHes +/// +/// If 0, timed flushing is disabled. Otherwise if no more input is available +/// and not at the end of the file and at least opt_flush_timeout milliseconds +/// has elapsed since the start of compression or the previous flushing +/// (LZMA_SYNC_FLUSH or LZMA_FULL_FLUSH), set LZMA_SYNC_FLUSH to flush +/// the pending data. +extern uint64_t opt_flush_timeout; + + +/// \brief True when flushing is needed due to expired timeout +extern bool flush_needed; + + +/// \brief Store the time when (de)compression was started +/// +/// The start time is also stored as the time of the first flush. +extern void mytime_set_start_time(void); + + +/// \brief Get the number of milliseconds since the operation started +extern uint64_t mytime_get_elapsed(void); + + +/// \brief Store the time of when compressor was flushed +extern void mytime_set_flush_time(void); + + +/// \brief Get the number of milliseconds until the next flush +/// +/// This returns -1 if no timed flushing is used. +/// +/// The return value is inteded for use with poll(). +extern int mytime_get_flush_timeout(void); diff --git a/src/xz/options.c b/src/xz/options.c index f21a0ba51065..f9c7ab9e8535 100644 --- a/src/xz/options.c +++ b/src/xz/options.c @@ -31,8 +31,8 @@ typedef struct { } option_map; -/// Parses option=value pairs that are separated with colons, semicolons, -/// or commas: opt=val:opt=val;opt=val,opt=val +/// Parses option=value pairs that are separated with commas: +/// opt=val,opt=val,opt=val /// /// Each option is a string, that is converted to an integer using the /// index where the option string is in the array. diff --git a/src/xz/private.h b/src/xz/private.h index 6b01e51354e1..4acfa8dc4558 100644 --- a/src/xz/private.h +++ b/src/xz/private.h @@ -12,6 +12,7 @@ #include "sysdefs.h" #include "mythread.h" + #include "lzma.h" #include @@ -45,6 +46,7 @@ #endif #include "main.h" +#include "mytime.h" #include "coder.h" #include "message.h" #include "args.h" diff --git a/src/xz/signals.c b/src/xz/signals.c index 322811f472b5..5387c424e1a5 100644 --- a/src/xz/signals.c +++ b/src/xz/signals.c @@ -41,6 +41,11 @@ signal_handler(int sig) { exit_signal = sig; user_abort = true; + +#ifndef TUKLIB_DOSLIKE + io_write_to_user_abort_pipe(); +#endif + return; } diff --git a/src/xz/suffix.c b/src/xz/suffix.c index 8e331a7022a3..9d4fcd139b8f 100644 --- a/src/xz/suffix.c +++ b/src/xz/suffix.c @@ -12,6 +12,10 @@ #include "private.h" +#ifdef __DJGPP__ +# include +#endif + // For case-insensitive filename suffix on case-insensitive systems #if defined(TUKLIB_DOSLIKE) || defined(__VMS) # define strcmp strcasecmp @@ -45,6 +49,31 @@ has_dir_sep(const char *str) } +#ifdef __DJGPP__ +/// \brief Test for special suffix used for 8.3 short filenames (SFN) +/// +/// \return If str matches *.?- or *.??-, true is returned. Otherwise +/// false is returned. +static bool +has_sfn_suffix(const char *str, size_t len) +{ + if (len >= 4 && str[len - 1] == '-' && str[len - 2] != '.' + && !is_dir_sep(str[len - 2])) { + // *.?- + if (str[len - 3] == '.') + return !is_dir_sep(str[len - 4]); + + // *.??- + if (len >= 5 && !is_dir_sep(str[len - 3]) + && str[len - 4] == '.') + return !is_dir_sep(str[len - 5]); + } + + return false; +} +#endif + + /// \brief Checks if src_name has given compressed_suffix /// /// \param suffix Filename suffix to look for @@ -87,6 +116,9 @@ uncompressed_name(const char *src_name, const size_t src_len) { ".xz", "" }, { ".txz", ".tar" }, // .txz abbreviation for .txt.gz is rare. { ".lzma", "" }, +#ifdef __DJGPP__ + { ".lzm", "" }, +#endif { ".tlz", ".tar" }, // { ".gz", "" }, // { ".tgz", ".tar" }, @@ -112,6 +144,17 @@ uncompressed_name(const char *src_name, const size_t src_len) break; } } + +#ifdef __DJGPP__ + // Support also *.?- -> *.? and *.??- -> *.?? on DOS. + // This is done also when long filenames are available + // to keep it easy to decompress files created when + // long filename support wasn't available. + if (new_len == 0 && has_sfn_suffix(src_name, src_len)) { + new_suffix = ""; + new_len = src_len - 1; + } +#endif } if (new_len == 0 && custom_suffix != NULL) @@ -134,21 +177,35 @@ uncompressed_name(const char *src_name, const size_t src_len) } +/// This message is needed in multiple places in compressed_name(), +/// so the message has been put into its own function. +static void +msg_suffix(const char *src_name, const char *suffix) +{ + message_warning(_("%s: File already has `%s' suffix, skipping"), + src_name, suffix); + return; +} + + /// \brief Appends suffix to src_name /// /// In contrast to uncompressed_name(), we check only suffixes that are valid /// for the specified file format. static char * -compressed_name(const char *src_name, const size_t src_len) +compressed_name(const char *src_name, size_t src_len) { // The order of these must match the order in args.h. - static const char *const all_suffixes[][3] = { + static const char *const all_suffixes[][4] = { { ".xz", ".txz", NULL }, { ".lzma", +#ifdef __DJGPP__ + ".lzm", +#endif ".tlz", NULL /* @@ -170,20 +227,27 @@ compressed_name(const char *src_name, const size_t src_len) const size_t format = opt_format - 1; const char *const *suffixes = all_suffixes[format]; + // Look for known filename suffixes and refuse to compress them. for (size_t i = 0; suffixes[i] != NULL; ++i) { if (test_suffix(suffixes[i], src_name, src_len) != 0) { - message_warning(_("%s: File already has `%s' " - "suffix, skipping"), src_name, - suffixes[i]); + msg_suffix(src_name, suffixes[i]); return NULL; } } +#ifdef __DJGPP__ + // Recognize also the special suffix that is used when long + // filename (LFN) support isn't available. This suffix is + // recognized on LFN systems too. + if (opt_format == FORMAT_XZ && has_sfn_suffix(src_name, src_len)) { + msg_suffix(src_name, "-"); + return NULL; + } +#endif + if (custom_suffix != NULL) { if (test_suffix(custom_suffix, src_name, src_len) != 0) { - message_warning(_("%s: File already has `%s' " - "suffix, skipping"), src_name, - custom_suffix); + msg_suffix(src_name, custom_suffix); return NULL; } } @@ -199,7 +263,101 @@ compressed_name(const char *src_name, const size_t src_len) const char *suffix = custom_suffix != NULL ? custom_suffix : suffixes[0]; - const size_t suffix_len = strlen(suffix); + size_t suffix_len = strlen(suffix); + +#ifdef __DJGPP__ + if (!_use_lfn(src_name)) { + // Long filename (LFN) support isn't available and we are + // limited to 8.3 short filenames (SFN). + // + // Look for suffix separator from the filename, and make sure + // that it is in the filename, not in a directory name. + const char *sufsep = strrchr(src_name, '.'); + if (sufsep == NULL || sufsep[1] == '\0' + || has_dir_sep(sufsep)) { + // src_name has no filename extension. + // + // Examples: + // xz foo -> foo.xz + // xz -F lzma foo -> foo.lzm + // xz -S x foo -> foox + // xz -S x foo. -> foo.x + // xz -S x.y foo -> foox.y + // xz -S .x foo -> foo.x + // xz -S .x foo. -> foo.x + // + // Avoid double dots: + if (sufsep != NULL && sufsep[1] == '\0' + && suffix[0] == '.') + --src_len; + + } else if (custom_suffix == NULL + && strcasecmp(sufsep, ".tar") == 0) { + // ".tar" is handled specially. + // + // Examples: + // xz foo.tar -> foo.txz + // xz -F lzma foo.tar -> foo.tlz + static const char *const tar_suffixes[] = { + ".txz", + ".tlz", + // ".tgz", + }; + suffix = tar_suffixes[format]; + suffix_len = 4; + src_len -= 4; + + } else { + if (custom_suffix == NULL && opt_format == FORMAT_XZ) { + // Instead of the .xz suffix, use a single + // character at the end of the filename + // extension. This is to minimize name + // conflicts when compressing multiple files + // with the same basename. E.g. foo.txt and + // foo.exe become foo.tx- and foo.ex-. Dash + // is rare as the last character of the + // filename extension, so it seems to be + // quite safe choice and it stands out better + // in directory listings than e.g. x. For + // comparison, gzip uses z. + suffix = "-"; + suffix_len = 1; + } + + if (suffix[0] == '.') { + // The first character of the suffix is a dot. + // Throw away the original filename extension + // and replace it with the new suffix. + // + // Examples: + // xz -F lzma foo.txt -> foo.lzm + // xz -S .x foo.txt -> foo.x + src_len = sufsep - src_name; + + } else { + // The first character of the suffix is not + // a dot. Preserve the first 0-2 characters + // of the original filename extension. + // + // Examples: + // xz foo.txt -> foo.tx- + // xz -S x foo.c -> foo.cx + // xz -S ab foo.c -> foo.cab + // xz -S ab foo.txt -> foo.tab + // xz -S abc foo.txt -> foo.abc + // + // Truncate the suffix to three chars: + if (suffix_len > 3) + suffix_len = 3; + + // If needed, overwrite 1-3 characters. + if (strlen(sufsep) > 4 - suffix_len) + src_len = sufsep - src_name + + 4 - suffix_len; + } + } + } +#endif char *dest_name = xmalloc(src_len + suffix_len + 1); diff --git a/src/xz/xz.1 b/src/xz/xz.1 index 363b90cb4e55..75aead3d0439 100644 --- a/src/xz/xz.1 +++ b/src/xz/xz.1 @@ -5,7 +5,7 @@ .\" This file has been put into the public domain. .\" You can do whatever you want with this file. .\" -.TH XZ 1 "2013-06-21" "Tukaani" "XZ Utils" +.TH XZ 1 "2014-12-16" "Tukaani" "XZ Utils" . .SH NAME xz, unxz, xzcat, lzma, unlzma, lzcat \- Compress or decompress .xz and .lzma files @@ -435,6 +435,29 @@ standard output instead of a file. This implies .BR \-\-keep . .TP +.B \-\-single\-stream +Decompress only the first +.B .xz +stream, and +silently ignore possible remaining input data following the stream. +Normally such trailing garbage makes +.B xz +display an error. +.IP "" +.B xz +never decompresses more than one stream from +.B .lzma +files or raw streams, but this option still makes +.B xz +ignore the possible trailing data after the +.B .lzma +file or raw stream. +.IP "" +This option has no effect if the operation mode is not +.B \-\-decompress +or +.BR \-\-test . +.TP .B \-\-no\-sparse Disable creation of sparse files. By default, if decompressing into a regular file, @@ -586,6 +609,25 @@ Integrity of the headers is always verified with CRC32. It is not possible to change or disable it. .TP +.B \-\-ignore\-check +Don't verify the integrity check of the compressed data when decompressing. +The CRC32 values in the +.B .xz +headers will still be verified normally. +.IP "" +.B "Do not use this option unless you know what you are doing." +Possible reasons to use this option: +.RS +.IP \(bu 3 +Trying to recover data from a corrupt .xz file. +.IP \(bu 3 +Speeding up decompression. +This matters mostly with SHA-256 or +with files that have compressed extremely well. +It's recommended to not use this option for this purpose +unless the file integrity is verified externally in some other way. +.RE +.TP .BR \-0 " ... " \-9 Select a compression preset level. The default is @@ -778,6 +820,124 @@ These are provided only for backwards compatibility with LZMA Utils. Avoid using these options. .TP +.BI \-\-block\-size= size +When compressing to the +.B .xz +format, split the input data into blocks of +.I size +bytes. +The blocks are compressed independently from each other, +which helps with multi-threading and +makes limited random-access decompression possible. +This option is typically used to override the default +block size in multi-threaded mode, +but this option can be used in single-threaded mode too. +.IP "" +In multi-threaded mode about three times +.I size +bytes will be allocated in each thread for buffering input and output. +The default +.I size +is three times the LZMA2 dictionary size or 1 MiB, +whichever is more. +Typically a good value is 2\-4 times +the size of the LZMA2 dictionary or at least 1 MiB. +Using +.I size +less than the LZMA2 dictionary size is waste of RAM +because then the LZMA2 dictionary buffer will never get fully used. +The sizes of the blocks are stored in the block headers, +which a future version of +.B xz +will use for multi-threaded decompression. +.IP "" +In single-threaded mode no block splitting is done by default. +Setting this option doesn't affect memory usage. +No size information is stored in block headers, +thus files created in single-threaded mode +won't be identical to files created in multi-threaded mode. +The lack of size information also means that a future version of +.B xz +won't be able decompress the files in multi-threaded mode. +.TP +.BI \-\-block\-list= sizes +When compressing to the +.B .xz +format, start a new block after +the given intervals of uncompressed data. +.IP "" +The uncompressed +.I sizes +of the blocks are specified as a comma-separated list. +Omitting a size (two or more consecutive commas) is a shorthand +to use the size of the previous block. +.IP "" +If the input file is bigger than the sum of +.IR sizes , +the last value in +.I sizes +is repeated until the end of the file. +A special value of +.B 0 +may be used as the last value to indicate that +the rest of the file should be encoded as a single block. +.IP "" +If one specifies +.I sizes +that exceed the encoder's block size +(either the default value in threaded mode or +the value specified with \fB\-\-block\-size=\fIsize\fR), +the encoder will create additional blocks while +keeping the boundaries specified in +.IR sizes . +For example, if one specifies +.B \-\-block\-size=10MiB +.B \-\-block\-list=5MiB,10MiB,8MiB,12MiB,24MiB +and the input file is 80 MiB, +one will get 11 blocks: +5, 10, 8, 10, 2, 10, 10, 4, 10, 10, and 1 MiB. +.IP "" +In multi-threaded mode the sizes of the blocks +are stored in the block headers. +This isn't done in single-threaded mode, +so the encoded output won't be +identical to that of the multi-threaded mode. +.TP +.BI \-\-flush\-timeout= timeout +When compressing, if more than +.I timeout +milliseconds (a positive integer) has passed since the previous flush and +reading more input would block, +all the pending input data is flushed from the encoder and +made available in the output stream. +This can be useful if +.B xz +is used to compress data that is streamed over a network. +Small +.I timeout +values make the data available at the receiving end +with a small delay, but large +.I timeout +values give better compression ratio. +.IP "" +This feature is disabled by default. +If this option is specified more than once, the last one takes effect. +The special +.I timeout +value of +.B 0 +can be used to explicitly disable this feature. +.IP "" +This feature is not available on non-POSIX systems. +.IP "" +.\" FIXME +.B "This feature is still experimental." +Currently +.B xz +is unsuitable for decompressing the stream in real time due to how +.B xz +does buffering. +.TP .BI \-\-memlimit\-compress= limit Set a memory usage limit for compression. If this option is specified multiple times, @@ -876,24 +1036,25 @@ Automatic adjusting is always disabled when creating raw streams .TP \fB\-T\fR \fIthreads\fR, \fB\-\-threads=\fIthreads Specify the number of worker threads to use. +Setting +.I threads +to a special value +.B 0 +makes +.B xz +use as many threads as there are CPU cores on the system. The actual number of threads can be less than .I threads +if the input file is not big enough +for threading with the given settings or if using more threads would exceed the memory usage limit. .IP "" -.B "Multithreaded compression and decompression are not" -.B "implemented yet, so this option has no effect for now." -.IP "" -.B "As of writing (2010-09-27), it hasn't been decided" -.B "if threads will be used by default on multicore systems" -.B "once support for threading has been implemented." -.B "Comments are welcome." -The complicating factor is that using many threads -will increase the memory usage dramatically. -Note that if multithreading will be the default, -it will probably be done so that single-threaded and -multithreaded modes produce the same output, -so compression ratio won't be significantly affected -if threading will be enabled by default. +Currently the only threading method is to split the input into +blocks and compress them independently from each other. +The default block size depends on the compression level and +can be overriden with the +.BI \-\-block\-size= size +option. . .SS "Custom compressor filter chains" A custom filter chain allows specifying @@ -1863,6 +2024,14 @@ or .B no indicating if all block headers have both compressed size and uncompressed size stored in them +.PP +.I Since +.B xz +.I 5.1.2alpha: +.IP 4. 4 +Minimum +.B xz +version required to decompress the file .RE .PD .PP @@ -1913,6 +2082,14 @@ or .B no indicating if all block headers have both compressed size and uncompressed size stored in them +.PP +.I Since +.B xz +.I 5.1.2alpha: +.IP 12. 4 +Minimum +.B xz +version required to decompress the file .RE .PD .PP @@ -2173,7 +2350,9 @@ If there is data left after the first .B .lzma stream, .B xz -considers the file to be corrupt. +considers the file to be corrupt unless +.B \-\-single\-stream +was used. This may break obscure scripts which have assumed that trailing garbage is ignored. . From 6c316535e28ff4150d932e399b3ee3dba3d31339 Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sat, 7 Feb 2015 13:11:45 +0000 Subject: [PATCH 02/75] Remove useless comment. MFC after: 1 month Sponsored by: The FreeBSD Foundation --- lib/libc/sys/setresuid.2 | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/libc/sys/setresuid.2 b/lib/libc/sys/setresuid.2 index 08d07f3b6776..602166f80c38 100644 --- a/lib/libc/sys/setresuid.2 +++ b/lib/libc/sys/setresuid.2 @@ -19,7 +19,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 13, 2001 +.Dd February 7, 2015 .Dt SETRESUID 2 .Os .Sh NAME @@ -90,10 +90,5 @@ was invalid. .Xr setregid 2 , .Xr setreuid 2 , .Xr setuid 2 -.Sh STANDARDS -These system calls are not available on many platforms. -They exist in -.Fx -to support Linux binaries linked against GNU libc2. .Sh HISTORY These functions first appeared in HP-UX. From 057abcb00413010898f3046f7704444b8f537bab Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sat, 7 Feb 2015 13:19:04 +0000 Subject: [PATCH 03/75] Teach ctld(8) to control non-iSCSI CTL ports. This change introduces new target option "port", that assigns current target to specified CTL port. On config application ctld(8) will apply LUN mapping according to target configuration to specified port and bring the port up. On shutdown cltd(8) will remove the mapping and put the port down. This change allows to configure both iSCSI and FibreChannel targets in the same configuration file in alike way. Kernel side support was added earlier at r278037. MFC after: 2 weeks Relnotes: yes Sponsored by: iXsystems, Inc. --- usr.sbin/ctld/ctl.conf.5 | 7 +- usr.sbin/ctld/ctld.c | 101 +++++++++++++++++++++++-- usr.sbin/ctld/ctld.h | 22 +++++- usr.sbin/ctld/kernel.c | 158 ++++++++++++++++++++++++--------------- usr.sbin/ctld/parse.y | 40 +++++++++- usr.sbin/ctld/token.l | 1 + 6 files changed, 257 insertions(+), 72 deletions(-) diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5 index 404699829920..c74e2919b9e1 100644 --- a/usr.sbin/ctld/ctl.conf.5 +++ b/usr.sbin/ctld/ctl.conf.5 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 6, 2015 +.Dd February 7, 2015 .Dt CTL.CONF 5 .Os .Sh NAME @@ -67,6 +67,7 @@ file is: .No target Ar name { .Dl auth-group Ar name .Dl portal-group Ar name Op Ar agname +.Dl port Ar name .Dl lun Ar number Ar name .Dl lun Ar number No { .Dl path Ar path @@ -321,6 +322,10 @@ on TCP port 3260 on all configured IPv4 and IPv6 addresses. Optional second argument specifies auth group name for connections to this specific portal group. If second argument is not specified, target auth group is used. +.It Ic port Ar name +Assign specified CTL port (such as "isp0") to the target. +On startup ctld configures LUN mapping and enables all assigned ports. +Each port can be assigned to only one target. .It Ic redirect Aq Ar address IPv4 or IPv6 address to redirect initiators to. When configured, all initiators attempting to connect to this target diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c index dd864b95d286..0f62ba3f104e 100644 --- a/usr.sbin/ctld/ctld.c +++ b/usr.sbin/ctld/ctld.c @@ -93,6 +93,7 @@ conf_new(void) TAILQ_INIT(&conf->conf_auth_groups); TAILQ_INIT(&conf->conf_ports); TAILQ_INIT(&conf->conf_portal_groups); + TAILQ_INIT(&conf->conf_pports); TAILQ_INIT(&conf->conf_isns); conf->conf_isns_period = 900; @@ -111,6 +112,7 @@ conf_delete(struct conf *conf) struct target *targ, *tmp; struct auth_group *ag, *cagtmp; struct portal_group *pg, *cpgtmp; + struct pport *pp, *pptmp; struct isns *is, *istmp; assert(conf->conf_pidfh == NULL); @@ -123,6 +125,8 @@ conf_delete(struct conf *conf) auth_group_delete(ag); TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp) portal_group_delete(pg); + TAILQ_FOREACH_SAFE(pp, &conf->conf_pports, pp_next, pptmp) + pport_delete(pp); TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp) isns_delete(is); assert(TAILQ_EMPTY(&conf->conf_ports)); @@ -1133,21 +1137,72 @@ valid_iscsi_name(const char *name) return (true); } +struct pport * +pport_new(struct conf *conf, const char *name, uint32_t ctl_port) +{ + struct pport *pp; + + pp = calloc(1, sizeof(*pp)); + if (pp == NULL) + log_err(1, "calloc"); + pp->pp_conf = conf; + pp->pp_name = checked_strdup(name); + pp->pp_ctl_port = ctl_port; + TAILQ_INIT(&pp->pp_ports); + TAILQ_INSERT_TAIL(&conf->conf_pports, pp, pp_next); + return (pp); +} + +struct pport * +pport_find(const struct conf *conf, const char *name) +{ + struct pport *pp; + + TAILQ_FOREACH(pp, &conf->conf_pports, pp_next) { + if (strcasecmp(pp->pp_name, name) == 0) + return (pp); + } + return (NULL); +} + +struct pport * +pport_copy(struct pport *pp, struct conf *conf) +{ + struct pport *ppnew; + + ppnew = pport_new(conf, pp->pp_name, pp->pp_ctl_port); + return (ppnew); +} + +void +pport_delete(struct pport *pp) +{ + struct port *port, *tport; + + TAILQ_FOREACH_SAFE(port, &pp->pp_ports, p_ts, tport) + port_delete(port); + TAILQ_REMOVE(&pp->pp_conf->conf_pports, pp, pp_next); + free(pp->pp_name); + free(pp); +} + struct port * port_new(struct conf *conf, struct target *target, struct portal_group *pg) { struct port *port; + char *name; + asprintf(&name, "%s-%s", pg->pg_name, target->t_name); + if (port_find(conf, name) != NULL) { + log_warnx("duplicate port \"%s\"", name); + free(name); + return (NULL); + } port = calloc(1, sizeof(*port)); if (port == NULL) log_err(1, "calloc"); - asprintf(&port->p_name, "%s-%s", pg->pg_name, target->t_name); - if (port_find(conf, port->p_name) != NULL) { - log_warnx("duplicate port \"%s\"", port->p_name); - free(port); - return (NULL); - } port->p_conf = conf; + port->p_name = name; TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next); TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts); port->p_target = target; @@ -1156,6 +1211,31 @@ port_new(struct conf *conf, struct target *target, struct portal_group *pg) return (port); } +struct port * +port_new_pp(struct conf *conf, struct target *target, struct pport *pp) +{ + struct port *port; + char *name; + + asprintf(&name, "%s-%s", pp->pp_name, target->t_name); + if (port_find(conf, name) != NULL) { + log_warnx("duplicate port \"%s\"", name); + free(name); + return (NULL); + } + port = calloc(1, sizeof(*port)); + if (port == NULL) + log_err(1, "calloc"); + port->p_conf = conf; + port->p_name = name; + TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next); + TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts); + port->p_target = target; + TAILQ_INSERT_TAIL(&pp->pp_ports, port, p_pps); + port->p_pport = pp; + return (port); +} + struct port * port_find(const struct conf *conf, const char *name) { @@ -1188,6 +1268,8 @@ port_delete(struct port *port) if (port->p_portal_group) TAILQ_REMOVE(&port->p_portal_group->pg_ports, port, p_pgs); + if (port->p_pport) + TAILQ_REMOVE(&port->p_pport->pp_ports, port, p_pps); if (port->p_target) TAILQ_REMOVE(&port->p_target->t_ports, port, p_ts); TAILQ_REMOVE(&port->p_conf->conf_ports, port, p_next); @@ -1779,6 +1861,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf) newport = port_find(newconf, oldport->p_name); if (newport != NULL) continue; + log_debugx("removing port \"%s\"", oldport->p_name); error = kernel_port_remove(oldport); if (error != 0) { log_warnx("failed to remove port %s", @@ -1903,8 +1986,10 @@ conf_apply(struct conf *oldconf, struct conf *newconf) oldport = port_find(oldconf, newport->p_name); if (oldport == NULL) { + log_debugx("adding port \"%s\"", newport->p_name); error = kernel_port_add(newport); } else { + log_debugx("updating port \"%s\"", newport->p_name); newport->p_ctl_port = oldport->p_ctl_port; error = kernel_port_update(newport); } @@ -2416,7 +2501,7 @@ main(int argc, char **argv) kernel_init(); oldconf = conf_new_from_kernel(); - newconf = conf_new_from_file(config_path); + newconf = conf_new_from_file(config_path, oldconf); if (newconf == NULL) log_errx(1, "configuration error; exiting"); if (debug > 0) { @@ -2451,7 +2536,7 @@ main(int argc, char **argv) if (sighup_received) { sighup_received = false; log_debugx("received SIGHUP, reloading configuration"); - tmpconf = conf_new_from_file(config_path); + tmpconf = conf_new_from_file(config_path, newconf); if (tmpconf == NULL) { log_warnx("configuration error, " "continuing with old configuration"); diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h index 395b0144ae55..c07c0346a946 100644 --- a/usr.sbin/ctld/ctld.h +++ b/usr.sbin/ctld/ctld.h @@ -125,14 +125,25 @@ struct portal_group { uint16_t pg_tag; }; +struct pport { + TAILQ_ENTRY(pport) pp_next; + TAILQ_HEAD(, port) pp_ports; + struct conf *pp_conf; + char *pp_name; + + uint32_t pp_ctl_port; +}; + struct port { TAILQ_ENTRY(port) p_next; TAILQ_ENTRY(port) p_pgs; + TAILQ_ENTRY(port) p_pps; TAILQ_ENTRY(port) p_ts; struct conf *p_conf; char *p_name; struct auth_group *p_auth_group; struct portal_group *p_portal_group; + struct pport *p_pport; struct target *p_target; uint32_t p_ctl_port; @@ -187,6 +198,7 @@ struct conf { TAILQ_HEAD(, auth_group) conf_auth_groups; TAILQ_HEAD(, port) conf_ports; TAILQ_HEAD(, portal_group) conf_portal_groups; + TAILQ_HEAD(, pport) conf_pports; TAILQ_HEAD(, isns) conf_isns; int conf_isns_period; int conf_isns_timeout; @@ -280,7 +292,7 @@ char *rchap_get_response(struct rchap *rchap); void rchap_delete(struct rchap *rchap); struct conf *conf_new(void); -struct conf *conf_new_from_file(const char *path); +struct conf *conf_new_from_file(const char *path, struct conf *old); struct conf *conf_new_from_kernel(void); void conf_delete(struct conf *conf); int conf_verify(struct conf *conf); @@ -333,8 +345,16 @@ void isns_register(struct isns *isns, struct isns *oldisns); void isns_check(struct isns *isns); void isns_deregister(struct isns *isns); +struct pport *pport_new(struct conf *conf, const char *name, + uint32_t ctl_port); +struct pport *pport_find(const struct conf *conf, const char *name); +struct pport *pport_copy(struct pport *pport, struct conf *conf); +void pport_delete(struct pport *pport); + struct port *port_new(struct conf *conf, struct target *target, struct portal_group *pg); +struct port *port_new_pp(struct conf *conf, struct target *target, + struct pport *pp); struct port *port_find(const struct conf *conf, const char *name); struct port *port_find_in_pg(const struct portal_group *pg, const char *target); diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c index 47dc56aa3be3..dc3c02af16fd 100644 --- a/usr.sbin/ctld/kernel.c +++ b/usr.sbin/ctld/kernel.c @@ -121,6 +121,7 @@ struct cctl_lun { struct cctl_port { uint32_t port_id; + char *port_name; int cfiscsi_state; char *cfiscsi_target; uint16_t cfiscsi_portal_group_tag; @@ -330,7 +331,10 @@ cctl_end_pelement(void *user_data, const char *name) devlist->cur_sb[devlist->level] = NULL; devlist->level--; - if (strcmp(name, "cfiscsi_target") == 0) { + if (strcmp(name, "port_name") == 0) { + cur_port->port_name = str; + str = NULL; + } else if (strcmp(name, "cfiscsi_target") == 0) { cur_port->cfiscsi_target = str; str = NULL; } else if (strcmp(name, "cfiscsi_state") == 0) { @@ -378,6 +382,7 @@ conf_new_from_kernel(void) struct conf *conf = NULL; struct target *targ; struct portal_group *pg; + struct pport *pp; struct port *cp; struct lun *cl; struct lun_option *lo; @@ -498,8 +503,20 @@ conf_new_from_kernel(void) STAILQ_FOREACH(port, &devlist.port_list, links) { if (port->cfiscsi_target == NULL) { - log_debugx("CTL port %ju wasn't managed by ctld; " - "ignoring", (uintmax_t)port->port_id); + log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ", + port->port_id, port->port_name); + pp = pport_find(conf, port->port_name); + if (pp == NULL) { +#if 0 + log_debugx("found new kernel port %u \"%s\"", + port->port_id, port->port_name); +#endif + pp = pport_new(conf, port->port_name, port->port_id); + if (pp == NULL) { + log_warnx("pport_new failed"); + continue; + } + } continue; } if (port->cfiscsi_state != 1) { @@ -880,39 +897,42 @@ kernel_port_add(struct port *port) int error, i, n; /* Create iSCSI port. */ - bzero(&req, sizeof(req)); - strlcpy(req.driver, "iscsi", sizeof(req.driver)); - req.reqtype = CTL_REQ_CREATE; - req.args = malloc(req.num_args * sizeof(*req.args)); - n = 0; - req.args[n].namelen = sizeof("port_id"); - req.args[n].name = __DECONST(char *, "port_id"); - req.args[n].vallen = sizeof(port->p_ctl_port); - req.args[n].value = &port->p_ctl_port; - req.args[n++].flags = CTL_BEARG_WR; - str_arg(&req.args[n++], "cfiscsi_target", targ->t_name); - snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag); - str_arg(&req.args[n++], "cfiscsi_portal_group_tag", tagstr); - if (targ->t_alias) - str_arg(&req.args[n++], "cfiscsi_target_alias", targ->t_alias); - str_arg(&req.args[n++], "ctld_portal_group_name", pg->pg_name); - req.num_args = n; - error = ioctl(ctl_fd, CTL_PORT_REQ, &req); - free(req.args); - if (error != 0) { - log_warn("error issuing CTL_PORT_REQ ioctl"); - return (1); - } - if (req.status == CTL_LUN_ERROR) { - log_warnx("error returned from port creation request: %s", - req.error_str); - return (1); - } - if (req.status != CTL_LUN_OK) { - log_warnx("unknown port creation request status %d", - req.status); - return (1); - } + if (port->p_portal_group) { + bzero(&req, sizeof(req)); + strlcpy(req.driver, "iscsi", sizeof(req.driver)); + req.reqtype = CTL_REQ_CREATE; + req.args = malloc(req.num_args * sizeof(*req.args)); + n = 0; + req.args[n].namelen = sizeof("port_id"); + req.args[n].name = __DECONST(char *, "port_id"); + req.args[n].vallen = sizeof(port->p_ctl_port); + req.args[n].value = &port->p_ctl_port; + req.args[n++].flags = CTL_BEARG_WR; + str_arg(&req.args[n++], "cfiscsi_target", targ->t_name); + snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag); + str_arg(&req.args[n++], "cfiscsi_portal_group_tag", tagstr); + if (targ->t_alias) + str_arg(&req.args[n++], "cfiscsi_target_alias", targ->t_alias); + str_arg(&req.args[n++], "ctld_portal_group_name", pg->pg_name); + req.num_args = n; + error = ioctl(ctl_fd, CTL_PORT_REQ, &req); + free(req.args); + if (error != 0) { + log_warn("error issuing CTL_PORT_REQ ioctl"); + return (1); + } + if (req.status == CTL_LUN_ERROR) { + log_warnx("error returned from port creation request: %s", + req.error_str); + return (1); + } + if (req.status != CTL_LUN_OK) { + log_warnx("unknown port creation request status %d", + req.status); + return (1); + } + } else if (port->p_pport) + port->p_ctl_port = port->p_pport->pp_ctl_port; /* Explicitly enable mapping to block any access except allowed. */ lm.port = port->p_ctl_port; @@ -971,40 +991,58 @@ kernel_port_update(struct port *port) int kernel_port_remove(struct port *port) { + struct ctl_port_entry entry; + struct ctl_lun_map lm; struct ctl_req req; char tagstr[16]; struct target *targ = port->p_target; struct portal_group *pg = port->p_portal_group; int error; - bzero(&req, sizeof(req)); - strlcpy(req.driver, "iscsi", sizeof(req.driver)); - req.reqtype = CTL_REQ_REMOVE; - req.num_args = 2; - req.args = malloc(req.num_args * sizeof(*req.args)); - str_arg(&req.args[0], "cfiscsi_target", targ->t_name); - snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag); - str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr); - - error = ioctl(ctl_fd, CTL_PORT_REQ, &req); - free(req.args); + /* Disable port */ + bzero(&entry, sizeof(entry)); + entry.targ_port = port->p_ctl_port; + error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry); if (error != 0) { - log_warn("error issuing CTL_PORT_REQ ioctl"); - return (1); + log_warn("CTL_DISABLE_PORT ioctl failed"); + return (-1); } - if (req.status == CTL_LUN_ERROR) { - log_warnx("error returned from port removal request: %s", - req.error_str); - return (1); + /* Remove iSCSI port. */ + if (port->p_portal_group) { + bzero(&req, sizeof(req)); + strlcpy(req.driver, "iscsi", sizeof(req.driver)); + req.reqtype = CTL_REQ_REMOVE; + req.num_args = 2; + req.args = malloc(req.num_args * sizeof(*req.args)); + str_arg(&req.args[0], "cfiscsi_target", targ->t_name); + snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag); + str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr); + error = ioctl(ctl_fd, CTL_PORT_REQ, &req); + free(req.args); + if (error != 0) { + log_warn("error issuing CTL_PORT_REQ ioctl"); + return (1); + } + if (req.status == CTL_LUN_ERROR) { + log_warnx("error returned from port removal request: %s", + req.error_str); + return (1); + } + if (req.status != CTL_LUN_OK) { + log_warnx("unknown port removal request status %d", + req.status); + return (1); + } + } else { + /* Disable LUN mapping. */ + lm.port = port->p_ctl_port; + lm.plun = UINT32_MAX; + lm.lun = UINT32_MAX; + error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); + if (error != 0) + log_warn("CTL_LUN_MAP ioctl failed"); } - - if (req.status != CTL_LUN_OK) { - log_warnx("unknown port removal request status %d", - req.status); - return (1); - } - return (0); } diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y index 5eaffe4e324a..a7807eff1434 100644 --- a/usr.sbin/ctld/parse.y +++ b/usr.sbin/ctld/parse.y @@ -61,7 +61,7 @@ extern void yyrestart(FILE *); %token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER %token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT %token LISTEN LISTEN_ISER LUN MAXPROC OFFLOAD OPENING_BRACKET OPTION -%token PATH PIDFILE PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR +%token PATH PIDFILE PORT PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR %token TARGET TIMEOUT %union @@ -467,6 +467,8 @@ target_entry: | target_portal_group | + target_port + | target_redirect | target_lun @@ -721,6 +723,36 @@ target_portal_group: PORTAL_GROUP STR STR } ; +target_port: PORT STR + { + struct pport *pp; + struct port *tp; + + pp = pport_find(conf, $2); + if (pp == NULL) { + log_warnx("unknown port \"%s\" for target \"%s\"", + $2, target->t_name); + free($2); + return (1); + } + if (!TAILQ_EMPTY(&pp->pp_ports)) { + log_warnx("can't link port \"%s\" to target \"%s\", " + "port already linked to some target", + $2, target->t_name); + free($2); + return (1); + } + tp = port_new_pp(conf, target, pp); + if (tp == NULL) { + log_warnx("can't link port \"%s\" to target \"%s\"", + $2, target->t_name); + free($2); + return (1); + } + free($2); + } + ; + target_redirect: REDIRECT STR { int error; @@ -950,16 +982,20 @@ check_perms(const char *path) } struct conf * -conf_new_from_file(const char *path) +conf_new_from_file(const char *path, struct conf *oldconf) { struct auth_group *ag; struct portal_group *pg; + struct pport *pp; int error; log_debugx("obtaining configuration from %s", path); conf = conf_new(); + TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next) + pport_copy(pp, conf); + ag = auth_group_new(conf, "default"); assert(ag != NULL); diff --git a/usr.sbin/ctld/token.l b/usr.sbin/ctld/token.l index fd274983f447..f0cb597bcd07 100644 --- a/usr.sbin/ctld/token.l +++ b/usr.sbin/ctld/token.l @@ -72,6 +72,7 @@ pidfile { return PIDFILE; } isns-server { return ISNS_SERVER; } isns-period { return ISNS_PERIOD; } isns-timeout { return ISNS_TIMEOUT; } +port { return PORT; } portal-group { return PORTAL_GROUP; } redirect { return REDIRECT; } serial { return SERIAL; } From 5aabcd7c4e1fa6dc7290c476e8a995ebc9ab98ce Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sat, 7 Feb 2015 14:15:17 +0000 Subject: [PATCH 04/75] Tidy up; no functional changes. MFC after: 1 month Sponsored by: The FreeBSD Foundation --- sys/dev/iscsi/icl_soft.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/sys/dev/iscsi/icl_soft.c b/sys/dev/iscsi/icl_soft.c index c6107749c14a..da8c926a963b 100644 --- a/sys/dev/iscsi/icl_soft.c +++ b/sys/dev/iscsi/icl_soft.c @@ -29,8 +29,7 @@ */ /* - * iSCSI Common Layer. It's used by both the initiator and target to send - * and receive iSCSI PDUs. + * Software implementation of iSCSI Common Layer kobj(9) interface. */ #include @@ -117,8 +116,6 @@ static kobj_method_t icl_soft_methods[] = { DEFINE_CLASS(icl_soft, icl_soft_methods, sizeof(struct icl_conn)); -static void icl_conn_close(struct icl_conn *ic); - static void icl_conn_fail(struct icl_conn *ic) { @@ -201,6 +198,7 @@ icl_pdu_free(struct icl_pdu *ip) void icl_soft_conn_pdu_free(struct icl_conn *ic, struct icl_pdu *ip) { + icl_pdu_free(ip); } @@ -696,7 +694,7 @@ icl_conn_receive_pdu(struct icl_conn *ic, size_t *availablep) if (error != 0) { /* * Don't free the PDU; it's pointed to by ic->ic_receive_pdu - * and will get freed in icl_conn_close(). + * and will get freed in icl_soft_conn_close(). */ icl_conn_fail(ic); } @@ -1248,7 +1246,7 @@ icl_conn_start(struct icl_conn *ic) error = soreserve(ic->ic_socket, sendspace, recvspace); if (error != 0) { ICL_WARN("soreserve failed with error %d", error); - icl_conn_close(ic); + icl_soft_conn_close(ic); return (error); } ic->ic_socket->so_snd.sb_flags |= SB_AUTOSIZE; @@ -1266,7 +1264,7 @@ icl_conn_start(struct icl_conn *ic) error = sosetopt(ic->ic_socket, &opt); if (error != 0) { ICL_WARN("disabling TCP_NODELAY failed with error %d", error); - icl_conn_close(ic); + icl_soft_conn_close(ic); return (error); } @@ -1277,7 +1275,7 @@ icl_conn_start(struct icl_conn *ic) ic->ic_name); if (error != 0) { ICL_WARN("kthread_add(9) failed with error %d", error); - icl_conn_close(ic); + icl_soft_conn_close(ic); return (error); } @@ -1285,7 +1283,7 @@ icl_conn_start(struct icl_conn *ic) ic->ic_name); if (error != 0) { ICL_WARN("kthread_add(9) failed with error %d", error); - icl_conn_close(ic); + icl_soft_conn_close(ic); return (error); } @@ -1350,7 +1348,7 @@ icl_soft_conn_handoff(struct icl_conn *ic, int fd) } void -icl_conn_close(struct icl_conn *ic) +icl_soft_conn_close(struct icl_conn *ic) { struct icl_pdu *pdu; @@ -1419,13 +1417,6 @@ icl_conn_close(struct icl_conn *ic) ICL_CONN_UNLOCK(ic); } -void -icl_soft_conn_close(struct icl_conn *ic) -{ - - icl_conn_close(ic); -} - bool icl_soft_conn_connected(struct icl_conn *ic) { From 2a0ed0760c9f6a7753d0e997ad4f0ec1c67bc220 Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sat, 7 Feb 2015 14:31:51 +0000 Subject: [PATCH 05/75] Make hccontrol(8) and sdpcontrol(8) appear in "man -k bluetooth" output. MFC after: 1 month Sponsored by: The FreeBSD Foundation --- usr.sbin/bluetooth/hccontrol/hccontrol.8 | 4 ++-- usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/usr.sbin/bluetooth/hccontrol/hccontrol.8 b/usr.sbin/bluetooth/hccontrol/hccontrol.8 index af0a67f1cd86..d8c5263cccfc 100644 --- a/usr.sbin/bluetooth/hccontrol/hccontrol.8 +++ b/usr.sbin/bluetooth/hccontrol/hccontrol.8 @@ -25,12 +25,12 @@ .\" $Id: hccontrol.8,v 1.6 2003/08/06 21:26:38 max Exp $ .\" $FreeBSD$ .\" -.Dd June 14, 2002 +.Dd February 7, 2015 .Dt HCCONTROL 8 .Os .Sh NAME .Nm hccontrol -.Nd HCI configuration utility +.Nd Bluetooth HCI configuration utility .Sh SYNOPSIS .Nm .Op Fl hN diff --git a/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8 b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8 index 89db90b85955..82aafad5d6d3 100644 --- a/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8 +++ b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8 @@ -25,12 +25,12 @@ .\" $Id: sdpcontrol.8,v 1.1 2003/09/08 02:27:27 max Exp $ .\" $FreeBSD$ .\" -.Dd September 7, 2003 +.Dd February 7, 2015 .Dt SDPCONTROL 8 .Os .Sh NAME .Nm sdpcontrol -.Nd SDP query utility +.Nd Bluetooth Service Discovery Protocol query utility .Sh SYNOPSIS .Nm .Fl h From 57fd0bcf035457e8a77962ce33e2951c5310a0d7 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 7 Feb 2015 16:57:32 +0000 Subject: [PATCH 06/75] Back out r278349 and r278350 for now, since this apparently blows up the kernel build in sys/dev/hptmv/hptproc.c for some people. Reported by: sbruno, Matthew Fuller --- contrib/llvm/lib/Target/X86/X86FastISel.cpp | 54 +++--- ...-llvm-r224884-invalid-reg-replacement.diff | 164 ------------------ 2 files changed, 27 insertions(+), 191 deletions(-) delete mode 100644 contrib/llvm/patches/patch-32-llvm-r224884-invalid-reg-replacement.diff diff --git a/contrib/llvm/lib/Target/X86/X86FastISel.cpp b/contrib/llvm/lib/Target/X86/X86FastISel.cpp index 14084c6013f3..ae3eea4943d7 100644 --- a/contrib/llvm/lib/Target/X86/X86FastISel.cpp +++ b/contrib/llvm/lib/Target/X86/X86FastISel.cpp @@ -2699,9 +2699,6 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { TM.Options.GuaranteedTailCallOpt)) return false; - SmallVector OutVTs; - SmallVector ArgRegs; - // If this is a constant i1/i8/i16 argument, promote to i32 to avoid an extra // instruction. This is safe because it is common to all FastISel supported // calling conventions on x86. @@ -2719,34 +2716,28 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { // Passing bools around ends up doing a trunc to i1 and passing it. // Codegen this as an argument + "and 1". - MVT VT; - auto *TI = dyn_cast(Val); - unsigned ResultReg; - if (TI && TI->getType()->isIntegerTy(1) && CLI.CS && - (TI->getParent() == CLI.CS->getInstruction()->getParent()) && - TI->hasOneUse()) { - Value *PrevVal = TI->getOperand(0); - ResultReg = getRegForValue(PrevVal); + if (auto *TI = dyn_cast(Val)) { + if (TI->getType()->isIntegerTy(1) && CLI.CS && + (TI->getParent() == CLI.CS->getInstruction()->getParent()) && + TI->hasOneUse()) { + Val = cast(Val)->getOperand(0); + unsigned ResultReg = getRegForValue(Val); - if (!ResultReg) - return false; + if (!ResultReg) + return false; - if (!isTypeLegal(PrevVal->getType(), VT)) - return false; + MVT ArgVT; + if (!isTypeLegal(Val->getType(), ArgVT)) + return false; - ResultReg = - FastEmit_ri(VT, VT, ISD::AND, ResultReg, hasTrivialKill(PrevVal), 1); + ResultReg = + FastEmit_ri(ArgVT, ArgVT, ISD::AND, ResultReg, Val->hasOneUse(), 1); - if (!ResultReg) - return false; - } else { - if (!isTypeLegal(Val->getType(), VT)) - return false; - ResultReg = getRegForValue(Val); + if (!ResultReg) + return false; + UpdateValueMap(Val, ResultReg); + } } - - ArgRegs.push_back(ResultReg); - OutVTs.push_back(VT); } // Analyze operands of the call, assigning locations to each operand. @@ -2758,6 +2749,13 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { if (IsWin64) CCInfo.AllocateStack(32, 8); + SmallVector OutVTs; + for (auto *Val : OutVals) { + MVT VT; + if (!isTypeLegal(Val->getType(), VT)) + return false; + OutVTs.push_back(VT); + } CCInfo.AnalyzeCallOperands(OutVTs, OutFlags, CC_X86); // Get a count of how many bytes are to be pushed on the stack. @@ -2779,7 +2777,9 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { if (ArgVT == MVT::x86mmx) return false; - unsigned ArgReg = ArgRegs[VA.getValNo()]; + unsigned ArgReg = getRegForValue(ArgVal); + if (!ArgReg) + return false; // Promote the value if needed. switch (VA.getLocInfo()) { diff --git a/contrib/llvm/patches/patch-32-llvm-r224884-invalid-reg-replacement.diff b/contrib/llvm/patches/patch-32-llvm-r224884-invalid-reg-replacement.diff deleted file mode 100644 index dc39636201b2..000000000000 --- a/contrib/llvm/patches/patch-32-llvm-r224884-invalid-reg-replacement.diff +++ /dev/null @@ -1,164 +0,0 @@ -Pull in r224884 from upstream llvm trunk (by Keno Fischer): - - [FastIsel][X86] Fix invalid register replacement for bool args - - Summary: - Consider the following IR: - - %3 = load i8* undef - %4 = trunc i8 %3 to i1 - %5 = call %jl_value_t.0* @foo(..., i1 %4, ...) - ret %jl_value_t.0* %5 - - Bools (that are the result of direct truncs) are lowered as whatever - the argument to the trunc was and a "and 1", causing the part of the - MBB responsible for this argument to look something like this: - - %vreg8 = AND8ri %vreg7, 1, %EFLAGS; GR8:%vreg8,%vreg7 - - Later, when the load is lowered, it will insert - - %vreg15 = MOV8rm %vreg14, 1, %noreg, 0, %noreg; mem:LD1[undef] GR8:%vreg15 GR64:%vreg14 - - but remember to (at the end of isel) replace vreg7 by vreg15. Now for - the bug. In fast isel lowering, we mistakenly mark vreg8 as the result - of the load instead of the trunc. This adds a fixup to have - vreg8 replaced by whatever the result of the load is as well, so - we end up with - - %vreg15 = AND8ri %vreg15, 1, %EFLAGS; GR8:%vreg15 - - which is an SSA violation and causes problems later down the road. - - This fixes PR21557. - - Test Plan: Test test case from PR21557 is added to the test suite. - - Reviewers: ributzka - - Reviewed By: ributzka - - Subscribers: llvm-commits - - Differential Revision: http://reviews.llvm.org/D6245 - -This fixes a possible assertion failure when compiling toolbox.cxx from -LibreOffice 4.3.5. - -Introduced here: http://svnweb.freebsd.org/changeset/base/278349 - -Index: lib/Target/X86/X86FastISel.cpp -=================================================================== ---- lib/Target/X86/X86FastISel.cpp -+++ lib/Target/X86/X86FastISel.cpp -@@ -2699,6 +2699,9 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo & - TM.Options.GuaranteedTailCallOpt)) - return false; - -+ SmallVector OutVTs; -+ SmallVector ArgRegs; -+ - // If this is a constant i1/i8/i16 argument, promote to i32 to avoid an extra - // instruction. This is safe because it is common to all FastISel supported - // calling conventions on x86. -@@ -2716,28 +2719,34 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo & - - // Passing bools around ends up doing a trunc to i1 and passing it. - // Codegen this as an argument + "and 1". -- if (auto *TI = dyn_cast(Val)) { -- if (TI->getType()->isIntegerTy(1) && CLI.CS && -- (TI->getParent() == CLI.CS->getInstruction()->getParent()) && -- TI->hasOneUse()) { -- Val = cast(Val)->getOperand(0); -- unsigned ResultReg = getRegForValue(Val); -+ MVT VT; -+ auto *TI = dyn_cast(Val); -+ unsigned ResultReg; -+ if (TI && TI->getType()->isIntegerTy(1) && CLI.CS && -+ (TI->getParent() == CLI.CS->getInstruction()->getParent()) && -+ TI->hasOneUse()) { -+ Value *PrevVal = TI->getOperand(0); -+ ResultReg = getRegForValue(PrevVal); - -- if (!ResultReg) -- return false; -+ if (!ResultReg) -+ return false; - -- MVT ArgVT; -- if (!isTypeLegal(Val->getType(), ArgVT)) -- return false; -+ if (!isTypeLegal(PrevVal->getType(), VT)) -+ return false; - -- ResultReg = -- FastEmit_ri(ArgVT, ArgVT, ISD::AND, ResultReg, Val->hasOneUse(), 1); -+ ResultReg = -+ FastEmit_ri(VT, VT, ISD::AND, ResultReg, hasTrivialKill(PrevVal), 1); - -- if (!ResultReg) -- return false; -- UpdateValueMap(Val, ResultReg); -- } -+ if (!ResultReg) -+ return false; -+ } else { -+ if (!isTypeLegal(Val->getType(), VT)) -+ return false; -+ ResultReg = getRegForValue(Val); - } -+ -+ ArgRegs.push_back(ResultReg); -+ OutVTs.push_back(VT); - } - - // Analyze operands of the call, assigning locations to each operand. -@@ -2749,13 +2758,6 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo & - if (IsWin64) - CCInfo.AllocateStack(32, 8); - -- SmallVector OutVTs; -- for (auto *Val : OutVals) { -- MVT VT; -- if (!isTypeLegal(Val->getType(), VT)) -- return false; -- OutVTs.push_back(VT); -- } - CCInfo.AnalyzeCallOperands(OutVTs, OutFlags, CC_X86); - - // Get a count of how many bytes are to be pushed on the stack. -@@ -2777,9 +2779,7 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo & - if (ArgVT == MVT::x86mmx) - return false; - -- unsigned ArgReg = getRegForValue(ArgVal); -- if (!ArgReg) -- return false; -+ unsigned ArgReg = ArgRegs[VA.getValNo()]; - - // Promote the value if needed. - switch (VA.getLocInfo()) { -Index: test/CodeGen/X86/fast-isel-call-bool.ll -=================================================================== ---- test/CodeGen/X86/fast-isel-call-bool.ll -+++ test/CodeGen/X86/fast-isel-call-bool.ll -@@ -0,0 +1,19 @@ -+; RUN: llc < %s -fast-isel -mcpu=core2 -O1 | FileCheck %s -+; See PR21557 -+ -+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -+target triple = "x86_64-apple-darwin14.0.0" -+ -+declare i64 @bar(i1) -+ -+define i64 @foo(i8* %arg) { -+; CHECK-LABEL: foo: -+top: -+ %0 = load i8* %arg -+; CHECK: movb -+ %1 = trunc i8 %0 to i1 -+; CHECK: andb $1, -+ %2 = call i64 @bar(i1 %1) -+; CHECK: callq -+ ret i64 %2 -+} From d5a6319ac7849a7191e8b6b2b129400be89d032c Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sat, 7 Feb 2015 17:53:47 +0000 Subject: [PATCH 07/75] Fix couple issues in ctlstat header printing. MFC after: 1 week --- usr.bin/ctlstat/ctlstat.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/usr.bin/ctlstat/ctlstat.c b/usr.bin/ctlstat/ctlstat.c index e04aa5405bb1..3bfb24884357 100644 --- a/usr.bin/ctlstat/ctlstat.c +++ b/usr.bin/ctlstat/ctlstat.c @@ -449,7 +449,7 @@ ctlstat_standard(struct ctlstat_context *ctx) { (F_LUNVAL(ctx) != 0) ? " " : "", (F_LUNVAL(ctx) != 0) ? " " : "", (F_LUNVAL(ctx) != 0) ? " " : "", - (F_CPU(ctx) == 0) ? " CPU" : ""); + (F_CPU(ctx)) ? " CPU" : ""); hdr_devs = 3; } else { if (F_CPU(ctx)) @@ -468,8 +468,9 @@ ctlstat_standard(struct ctlstat_context *ctx) { if (bit_test(ctx->lun_mask, lun) == 0) continue; - fprintf(stdout, "%15.6s%d ", - "lun", lun); + fprintf(stdout, "%15.6s%d %s", + "lun", lun, + (F_LUNVAL(ctx) != 0) ? " " : ""); hdr_devs++; } fprintf(stdout, "\n"); From eb77fbdcec0b6f4bb396c0a8ce20f17687d1c7fa Mon Sep 17 00:00:00 2001 From: "Pedro F. Giffuni" Date: Sat, 7 Feb 2015 19:51:34 +0000 Subject: [PATCH 08/75] Protect uninitialized scalar variable from being accessed In a couple of cases a variable "stayopen" can be checked unitialized. This is of no danger as the complementary condition is false but prevent the access by switching the checks. CID: 1018729 CID: 1018732 --- lib/libc/gen/getgrent.c | 2 +- lib/libc/gen/getpwent.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c index f9480c3a22fc..caa5ad5ef2e7 100644 --- a/lib/libc/gen/getgrent.c +++ b/lib/libc/gen/getgrent.c @@ -896,7 +896,7 @@ files_group(void *retval, void *mdata, va_list ap) break; pos = ftello(st->fp); } - if (!stayopen && st->fp != NULL) { + if (st->fp != NULL && !stayopen) { fclose(st->fp); st->fp = NULL; } diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c index f729cdf1d417..7cf7f47941e3 100644 --- a/lib/libc/gen/getpwent.c +++ b/lib/libc/gen/getpwent.c @@ -921,7 +921,7 @@ files_passwd(void *retval, void *mdata, va_list ap) errnop); } while (how == nss_lt_all && !(rv & NS_TERMINATE)); fin: - if (!stayopen && st->db != NULL) { + if (st->db != NULL && !stayopen) { (void)st->db->close(st->db); st->db = NULL; } From ee3a7d2fb7c7f79aa6c81c607374eef4dc4fe05a Mon Sep 17 00:00:00 2001 From: Enji Cooper Date: Sat, 7 Feb 2015 21:29:17 +0000 Subject: [PATCH 09/75] Remove kdb_backtrace extern; get the definition for kdb_backtrace from instead Fix whitespace in WARN_ON macro definition MFC after: 1 week Reviewed by: np Differential Revision: https://reviews.freebsd.org/D1799 Sponsored by: EMC / Isilon Storage Division --- sys/dev/cxgb/cxgb_osdep.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/dev/cxgb/cxgb_osdep.h b/sys/dev/cxgb/cxgb_osdep.h index 15f7d133f5eb..ddef730426aa 100644 --- a/sys/dev/cxgb/cxgb_osdep.h +++ b/sys/dev/cxgb/cxgb_osdep.h @@ -39,6 +39,8 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include + #include #ifndef _CXGB_OSDEP_H_ @@ -128,10 +130,8 @@ void prefetch(void *x) #define smp_mb() mb() #define L1_CACHE_BYTES 128 -extern void kdb_backtrace(void); - #define WARN_ON(condition) do { \ - if (__predict_false((condition)!=0)) { \ + if (__predict_false((condition)!=0)) { \ log(LOG_WARNING, "BUG: warning at %s:%d/%s()\n", __FILE__, __LINE__, __FUNCTION__); \ kdb_backtrace(); \ } \ From 84ac51d88396a62745778ea2e32c050bd569f51f Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sat, 7 Feb 2015 23:09:03 +0000 Subject: [PATCH 10/75] Add WPI_DEBUG option. PR: kern/197143 Submitted by: Andriy Voskoboinyk --- sys/conf/options | 3 +++ sys/modules/wpi/Makefile | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/conf/options b/sys/conf/options index d0037278db80..bf157677db10 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -847,6 +847,9 @@ MWL_TX_NODROP opt_mwl.h # Options for the Intel 802.11n wireless driver IWN_DEBUG opt_iwn.h +# Options for the Intel 3945ABG wireless driver +WPI_DEBUG opt_wpi.h + # dcons options DCONS_BUF_SIZE opt_dcons.h DCONS_POLL_HZ opt_dcons.h diff --git a/sys/modules/wpi/Makefile b/sys/modules/wpi/Makefile index 1e2383ff1ab8..2e0da73b1894 100644 --- a/sys/modules/wpi/Makefile +++ b/sys/modules/wpi/Makefile @@ -3,6 +3,6 @@ .PATH: ${.CURDIR}/../../dev/wpi KMOD = if_wpi -SRCS = if_wpi.c device_if.h bus_if.h pci_if.h opt_wlan.h +SRCS = if_wpi.c device_if.h bus_if.h pci_if.h opt_wpi.h opt_wlan.h .include From 692ad7ca94f8fc4471a2627f02d72dc7b807132e Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sat, 7 Feb 2015 23:11:38 +0000 Subject: [PATCH 11/75] Big wpi(4) overhaul! Not by me! This is a sync against iwn(4) and openbsd. - Add power management support; - Add background scanning support; - Fix few LORs; - Handle rfkill switch state changes properly; - Fix recovering after firmware failure; - Add more error checking; - Cleanup & disable by default debug output; - Update macroses names; - Other various fixes; - Add IBSS support: - don't set data_ntries field for management frames; - Add AHDEMO support: - fix padding; - Sync eeprom functions; - Use CMD_RXON_ASSOC where possible; - Enable HW CCMP encryption/decryption for pairwise keys; - Fix filter flags for CMD_RXON. Tested (by submitter) - iwn 3945 NIC. I have one somewhere; I'll validate this later on and revert it if it's a problem. Thanks! PR: 197143 Submitted by: Andriy Voskoboinyk --- sys/dev/wpi/if_wpi.c | 6466 +++++++++++++++++++++--------------- sys/dev/wpi/if_wpi_debug.h | 98 + sys/dev/wpi/if_wpireg.h | 955 ++++-- sys/dev/wpi/if_wpivar.h | 112 +- 4 files changed, 4600 insertions(+), 3031 deletions(-) create mode 100644 sys/dev/wpi/if_wpi_debug.h diff --git a/sys/dev/wpi/if_wpi.c b/sys/dev/wpi/if_wpi.c index accb46c34bfc..52846ddf3b54 100644 --- a/sys/dev/wpi/if_wpi.c +++ b/sys/dev/wpi/if_wpi.c @@ -16,8 +16,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define VERSION "20071127" - #include __FBSDID("$FreeBSD$"); @@ -60,6 +58,7 @@ __FBSDID("$FreeBSD$"); */ #include "opt_wlan.h" +#include "opt_wpi.h" #include #include @@ -93,51 +92,20 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include +#include +#include +#include + #include #include #include #include -#include -#include -#include -#include -#include - #include #include - -#define WPI_DEBUG - -#ifdef WPI_DEBUG -#define DPRINTF(x) do { if (wpi_debug != 0) printf x; } while (0) -#define DPRINTFN(n, x) do { if (wpi_debug & n) printf x; } while (0) -#define WPI_DEBUG_SET (wpi_debug != 0) - -enum { - WPI_DEBUG_UNUSED = 0x00000001, /* Unused */ - WPI_DEBUG_HW = 0x00000002, /* Stage 1 (eeprom) debugging */ - WPI_DEBUG_TX = 0x00000004, /* Stage 2 TX intrp debugging*/ - WPI_DEBUG_RX = 0x00000008, /* Stage 2 RX intrp debugging */ - WPI_DEBUG_CMD = 0x00000010, /* Stage 2 CMD intrp debugging*/ - WPI_DEBUG_FIRMWARE = 0x00000020, /* firmware(9) loading debug */ - WPI_DEBUG_DMA = 0x00000040, /* DMA (de)allocations/syncs */ - WPI_DEBUG_SCANNING = 0x00000080, /* Stage 2 Scanning debugging */ - WPI_DEBUG_NOTIFY = 0x00000100, /* State 2 Noftif intr debug */ - WPI_DEBUG_TEMP = 0x00000200, /* TXPower/Temp Calibration */ - WPI_DEBUG_OPS = 0x00000400, /* wpi_ops taskq debug */ - WPI_DEBUG_WATCHDOG = 0x00000800, /* Watch dog debug */ - WPI_DEBUG_ANY = 0xffffffff -}; - -static int wpi_debug; -SYSCTL_INT(_debug, OID_AUTO, wpi, CTLFLAG_RWTUN, &wpi_debug, 0, "wpi debug level"); - -#else -#define DPRINTF(x) -#define DPRINTFN(n, x) -#define WPI_DEBUG_SET 0 -#endif +#include struct wpi_ident { uint16_t vendor; @@ -158,99 +126,138 @@ static const struct wpi_ident wpi_ident_table[] = { { 0, 0, 0, NULL } }; +static int wpi_probe(device_t); +static int wpi_attach(device_t); +static void wpi_radiotap_attach(struct wpi_softc *); +static void wpi_sysctlattach(struct wpi_softc *); static struct ieee80211vap *wpi_vap_create(struct ieee80211com *, const char [IFNAMSIZ], int, enum ieee80211_opmode, int, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void wpi_vap_delete(struct ieee80211vap *); -static int wpi_dma_contig_alloc(struct wpi_softc *, struct wpi_dma_info *, - void **, bus_size_t, bus_size_t, int); -static void wpi_dma_contig_free(struct wpi_dma_info *); +static int wpi_detach(device_t); +static int wpi_shutdown(device_t); +static int wpi_suspend(device_t); +static int wpi_resume(device_t); +static int wpi_nic_lock(struct wpi_softc *); +static int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); static void wpi_dma_map_addr(void *, bus_dma_segment_t *, int, int); +static int wpi_dma_contig_alloc(struct wpi_softc *, struct wpi_dma_info *, + void **, bus_size_t, bus_size_t); +static void wpi_dma_contig_free(struct wpi_dma_info *); static int wpi_alloc_shared(struct wpi_softc *); static void wpi_free_shared(struct wpi_softc *); -static int wpi_alloc_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); -static void wpi_reset_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); -static void wpi_free_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); -static int wpi_alloc_tx_ring(struct wpi_softc *, struct wpi_tx_ring *, - int, int); -static void wpi_reset_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); -static void wpi_free_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); -static int wpi_newstate(struct ieee80211vap *, enum ieee80211_state, int); -static void wpi_mem_lock(struct wpi_softc *); -static void wpi_mem_unlock(struct wpi_softc *); -static uint32_t wpi_mem_read(struct wpi_softc *, uint16_t); -static void wpi_mem_write(struct wpi_softc *, uint16_t, uint32_t); -static void wpi_mem_write_region_4(struct wpi_softc *, uint16_t, - const uint32_t *, int); -static uint16_t wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); static int wpi_alloc_fwmem(struct wpi_softc *); static void wpi_free_fwmem(struct wpi_softc *); -static int wpi_load_firmware(struct wpi_softc *); -static void wpi_unload_firmware(struct wpi_softc *); -static int wpi_load_microcode(struct wpi_softc *, const uint8_t *, int); -static void wpi_rx_intr(struct wpi_softc *, struct wpi_rx_desc *, +static int wpi_alloc_rx_ring(struct wpi_softc *); +static void wpi_update_rx_ring(struct wpi_softc *); +static void wpi_reset_rx_ring(struct wpi_softc *); +static void wpi_free_rx_ring(struct wpi_softc *); +static int wpi_alloc_tx_ring(struct wpi_softc *, struct wpi_tx_ring *, + int); +static void wpi_update_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); +static void wpi_reset_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); +static void wpi_free_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); +static int wpi_read_eeprom(struct wpi_softc *, + uint8_t macaddr[IEEE80211_ADDR_LEN]); +static uint32_t wpi_eeprom_channel_flags(struct wpi_eeprom_chan *); +static void wpi_read_eeprom_band(struct wpi_softc *, int); +static int wpi_read_eeprom_channels(struct wpi_softc *, int); +static struct wpi_eeprom_chan *wpi_find_eeprom_channel(struct wpi_softc *, + struct ieee80211_channel *); +static int wpi_setregdomain(struct ieee80211com *, + struct ieee80211_regdomain *, int, + struct ieee80211_channel[]); +static int wpi_read_eeprom_group(struct wpi_softc *, int); +static void wpi_node_free(struct ieee80211_node *); +static struct ieee80211_node *wpi_node_alloc(struct ieee80211vap *, + const uint8_t mac[IEEE80211_ADDR_LEN]); +static int wpi_newstate(struct ieee80211vap *, enum ieee80211_state, int); +static void wpi_calib_timeout(void *); +static void wpi_rx_done(struct wpi_softc *, struct wpi_rx_desc *, struct wpi_rx_data *); -static void wpi_tx_intr(struct wpi_softc *, struct wpi_rx_desc *); -static void wpi_cmd_intr(struct wpi_softc *, struct wpi_rx_desc *); +static void wpi_rx_statistics(struct wpi_softc *, struct wpi_rx_desc *, + struct wpi_rx_data *); +static void wpi_tx_done(struct wpi_softc *, struct wpi_rx_desc *); +static void wpi_cmd_done(struct wpi_softc *, struct wpi_rx_desc *); static void wpi_notif_intr(struct wpi_softc *); +static void wpi_wakeup_intr(struct wpi_softc *); +static void wpi_fatal_intr(struct wpi_softc *); static void wpi_intr(void *); -static uint8_t wpi_plcp_signal(int); -static void wpi_watchdog(void *); +static int wpi_cmd2(struct wpi_softc *, struct wpi_buf *); static int wpi_tx_data(struct wpi_softc *, struct mbuf *, - struct ieee80211_node *, int); -static void wpi_start(struct ifnet *); -static void wpi_start_locked(struct ifnet *); + struct ieee80211_node *); +static int wpi_tx_data_raw(struct wpi_softc *, struct mbuf *, + struct ieee80211_node *, + const struct ieee80211_bpf_params *); static int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); +static void wpi_start(struct ifnet *); +static void wpi_start_locked(struct ifnet *); +static void wpi_watchdog_rfkill(void *); +static void wpi_watchdog(void *); +static int wpi_ioctl(struct ifnet *, u_long, caddr_t); +static int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); +static int wpi_mrr_setup(struct wpi_softc *); +static int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); +static int wpi_add_broadcast_node(struct wpi_softc *, int); +static int wpi_add_ibss_node(struct wpi_softc *, struct ieee80211_node *); +static void wpi_del_node(struct wpi_softc *, struct ieee80211_node *); +static int wpi_updateedca(struct ieee80211com *); +static void wpi_set_promisc(struct wpi_softc *); +static void wpi_update_promisc(struct ifnet *); +static void wpi_update_mcast(struct ifnet *); +static void wpi_set_led(struct wpi_softc *, uint8_t, uint8_t, uint8_t); +static int wpi_set_timing(struct wpi_softc *, struct ieee80211_node *); +static void wpi_power_calibration(struct wpi_softc *); +static int wpi_set_txpower(struct wpi_softc *, int); +static int wpi_get_power_index(struct wpi_softc *, + struct wpi_power_group *, struct ieee80211_channel *, int); +static int wpi_set_pslevel(struct wpi_softc *, uint8_t, int, int); +static int wpi_send_btcoex(struct wpi_softc *); +static int wpi_send_rxon(struct wpi_softc *, int, int); +static int wpi_config(struct wpi_softc *); +static uint16_t wpi_get_active_dwell_time(struct wpi_softc *, + struct ieee80211_channel *, uint8_t); +static uint16_t wpi_limit_dwell(struct wpi_softc *, uint16_t); +static uint16_t wpi_get_passive_dwell_time(struct wpi_softc *, + struct ieee80211_channel *); +static int wpi_scan(struct wpi_softc *, struct ieee80211_channel *); +static int wpi_auth(struct wpi_softc *, struct ieee80211vap *); +static void wpi_update_beacon(struct ieee80211vap *, int); +static int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *); +static int wpi_run(struct wpi_softc *, struct ieee80211vap *); +static int wpi_key_alloc(struct ieee80211vap *, struct ieee80211_key *, + ieee80211_keyix *, ieee80211_keyix *); +static int wpi_key_set(struct ieee80211vap *, + const struct ieee80211_key *, + const uint8_t mac[IEEE80211_ADDR_LEN]); +static int wpi_key_delete(struct ieee80211vap *, + const struct ieee80211_key *); +static int wpi_post_alive(struct wpi_softc *); +static int wpi_load_bootcode(struct wpi_softc *, const uint8_t *, int); +static int wpi_load_firmware(struct wpi_softc *); +static int wpi_read_firmware(struct wpi_softc *); +static void wpi_unload_firmware(struct wpi_softc *); +static int wpi_clock_wait(struct wpi_softc *); +static int wpi_apm_init(struct wpi_softc *); +static void wpi_apm_stop_master(struct wpi_softc *); +static void wpi_apm_stop(struct wpi_softc *); +static void wpi_nic_config(struct wpi_softc *); +static int wpi_hw_init(struct wpi_softc *); +static void wpi_hw_stop(struct wpi_softc *); +static void wpi_radio_on(void *, int); +static void wpi_radio_off(void *, int); +static void wpi_init_locked(struct wpi_softc *); +static void wpi_init(void *); +static void wpi_stop_locked(struct wpi_softc *); +static void wpi_stop(struct wpi_softc *); static void wpi_scan_start(struct ieee80211com *); static void wpi_scan_end(struct ieee80211com *); static void wpi_set_channel(struct ieee80211com *); static void wpi_scan_curchan(struct ieee80211_scan_state *, unsigned long); static void wpi_scan_mindwell(struct ieee80211_scan_state *); -static int wpi_ioctl(struct ifnet *, u_long, caddr_t); -static void wpi_read_eeprom(struct wpi_softc *, - uint8_t macaddr[IEEE80211_ADDR_LEN]); -static void wpi_read_eeprom_channels(struct wpi_softc *, int); -static void wpi_read_eeprom_group(struct wpi_softc *, int); -static int wpi_cmd(struct wpi_softc *, int, const void *, int, int); -static int wpi_wme_update(struct ieee80211com *); -static int wpi_mrr_setup(struct wpi_softc *); -static void wpi_set_led(struct wpi_softc *, uint8_t, uint8_t, uint8_t); -static void wpi_enable_tsf(struct wpi_softc *, struct ieee80211_node *); -#if 0 -static int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *); -#endif -static int wpi_auth(struct wpi_softc *, struct ieee80211vap *); -static int wpi_run(struct wpi_softc *, struct ieee80211vap *); -static int wpi_scan(struct wpi_softc *); -static int wpi_config(struct wpi_softc *); -static void wpi_stop_master(struct wpi_softc *); -static int wpi_power_up(struct wpi_softc *); -static int wpi_reset(struct wpi_softc *); -static void wpi_hwreset(void *, int); -static void wpi_rfreset(void *, int); -static void wpi_hw_config(struct wpi_softc *); -static void wpi_init(void *); -static void wpi_init_locked(struct wpi_softc *, int); -static void wpi_stop(struct wpi_softc *); -static void wpi_stop_locked(struct wpi_softc *); - -static int wpi_set_txpower(struct wpi_softc *, struct ieee80211_channel *, - int); -static void wpi_calib_timeout(void *); -static void wpi_power_calibration(struct wpi_softc *, int); -static int wpi_get_power_index(struct wpi_softc *, - struct wpi_power_group *, struct ieee80211_channel *, int); -#ifdef WPI_DEBUG -static const char *wpi_cmd_str(int); -#endif -static int wpi_probe(device_t); -static int wpi_attach(device_t); -static int wpi_detach(device_t); -static int wpi_shutdown(device_t); -static int wpi_suspend(device_t); -static int wpi_resume(device_t); +static void wpi_hw_reset(void *, int); static device_method_t wpi_methods[] = { /* Device interface */ @@ -269,25 +276,15 @@ static driver_t wpi_driver = { wpi_methods, sizeof (struct wpi_softc) }; - static devclass_t wpi_devclass; DRIVER_MODULE(wpi, pci, wpi_driver, wpi_devclass, NULL, NULL); MODULE_VERSION(wpi, 1); -static const uint8_t wpi_ridx_to_plcp[] = { - /* OFDM: IEEE Std 802.11a-1999, pp. 14 Table 80 */ - /* R1-R4 (ral/ural is R4-R1) */ - 0xd, 0xf, 0x5, 0x7, 0x9, 0xb, 0x1, 0x3, - /* CCK: device-dependent */ - 10, 20, 55, 110 -}; - -static const uint8_t wpi_ridx_to_rate[] = { - 12, 18, 24, 36, 48, 72, 96, 108, /* OFDM */ - 2, 4, 11, 22 /*CCK */ -}; +MODULE_DEPEND(wpi, pci, 1, 1, 1); +MODULE_DEPEND(wpi, wlan, 1, 1, 1); +MODULE_DEPEND(wpi, firmware, 1, 1, 1); static int wpi_probe(device_t dev) @@ -304,202 +301,38 @@ wpi_probe(device_t dev) return ENXIO; } -/** - * Load the firmare image from disk to the allocated dma buffer. - * we also maintain the reference to the firmware pointer as there - * is times where we may need to reload the firmware but we are not - * in a context that can access the filesystem (ie taskq cause by restart) - * - * @return 0 on success, an errno on failure - */ -static int -wpi_load_firmware(struct wpi_softc *sc) -{ - const struct firmware *fp; - struct wpi_dma_info *dma = &sc->fw_dma; - const struct wpi_firmware_hdr *hdr; - const uint8_t *itext, *idata, *rtext, *rdata, *btext; - uint32_t itextsz, idatasz, rtextsz, rdatasz, btextsz; - int error; - - DPRINTFN(WPI_DEBUG_FIRMWARE, - ("Attempting Loading Firmware from wpi_fw module\n")); - - WPI_UNLOCK(sc); - - if (sc->fw_fp == NULL && (sc->fw_fp = firmware_get("wpifw")) == NULL) { - device_printf(sc->sc_dev, - "could not load firmware image 'wpifw'\n"); - error = ENOENT; - WPI_LOCK(sc); - goto fail; - } - - fp = sc->fw_fp; - - WPI_LOCK(sc); - - /* Validate the firmware is minimum a particular version */ - if (fp->version < WPI_FW_MINVERSION) { - device_printf(sc->sc_dev, - "firmware version is too old. Need %d, got %d\n", - WPI_FW_MINVERSION, - fp->version); - error = ENXIO; - goto fail; - } - - if (fp->datasize < sizeof (struct wpi_firmware_hdr)) { - device_printf(sc->sc_dev, - "firmware file too short: %zu bytes\n", fp->datasize); - error = ENXIO; - goto fail; - } - - hdr = (const struct wpi_firmware_hdr *)fp->data; - - /* | RUNTIME FIRMWARE | INIT FIRMWARE | BOOT FW | - |HDR|<--TEXT-->|<--DATA-->|<--TEXT-->|<--DATA-->|<--TEXT-->| */ - - rtextsz = le32toh(hdr->rtextsz); - rdatasz = le32toh(hdr->rdatasz); - itextsz = le32toh(hdr->itextsz); - idatasz = le32toh(hdr->idatasz); - btextsz = le32toh(hdr->btextsz); - - /* check that all firmware segments are present */ - if (fp->datasize < sizeof (struct wpi_firmware_hdr) + - rtextsz + rdatasz + itextsz + idatasz + btextsz) { - device_printf(sc->sc_dev, - "firmware file too short: %zu bytes\n", fp->datasize); - error = ENXIO; /* XXX appropriate error code? */ - goto fail; - } - - /* get pointers to firmware segments */ - rtext = (const uint8_t *)(hdr + 1); - rdata = rtext + rtextsz; - itext = rdata + rdatasz; - idata = itext + itextsz; - btext = idata + idatasz; - - DPRINTFN(WPI_DEBUG_FIRMWARE, - ("Firmware Version: Major %d, Minor %d, Driver %d, \n" - "runtime (text: %u, data: %u) init (text: %u, data %u) boot (text %u)\n", - (le32toh(hdr->version) & 0xff000000) >> 24, - (le32toh(hdr->version) & 0x00ff0000) >> 16, - (le32toh(hdr->version) & 0x0000ffff), - rtextsz, rdatasz, - itextsz, idatasz, btextsz)); - - DPRINTFN(WPI_DEBUG_FIRMWARE,("rtext 0x%x\n", *(const uint32_t *)rtext)); - DPRINTFN(WPI_DEBUG_FIRMWARE,("rdata 0x%x\n", *(const uint32_t *)rdata)); - DPRINTFN(WPI_DEBUG_FIRMWARE,("itext 0x%x\n", *(const uint32_t *)itext)); - DPRINTFN(WPI_DEBUG_FIRMWARE,("idata 0x%x\n", *(const uint32_t *)idata)); - DPRINTFN(WPI_DEBUG_FIRMWARE,("btext 0x%x\n", *(const uint32_t *)btext)); - - /* sanity checks */ - if (rtextsz > WPI_FW_MAIN_TEXT_MAXSZ || - rdatasz > WPI_FW_MAIN_DATA_MAXSZ || - itextsz > WPI_FW_INIT_TEXT_MAXSZ || - idatasz > WPI_FW_INIT_DATA_MAXSZ || - btextsz > WPI_FW_BOOT_TEXT_MAXSZ || - (btextsz & 3) != 0) { - device_printf(sc->sc_dev, "firmware invalid\n"); - error = EINVAL; - goto fail; - } - - /* copy initialization images into pre-allocated DMA-safe memory */ - memcpy(dma->vaddr, idata, idatasz); - memcpy(dma->vaddr + WPI_FW_INIT_DATA_MAXSZ, itext, itextsz); - - bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); - - /* tell adapter where to find initialization images */ - wpi_mem_lock(sc); - wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr); - wpi_mem_write(sc, WPI_MEM_DATA_SIZE, idatasz); - wpi_mem_write(sc, WPI_MEM_TEXT_BASE, - dma->paddr + WPI_FW_INIT_DATA_MAXSZ); - wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, itextsz); - wpi_mem_unlock(sc); - - /* load firmware boot code */ - if ((error = wpi_load_microcode(sc, btext, btextsz)) != 0) { - device_printf(sc->sc_dev, "Failed to load microcode\n"); - goto fail; - } - - /* now press "execute" */ - WPI_WRITE(sc, WPI_RESET, 0); - - /* wait at most one second for the first alive notification */ - if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { - device_printf(sc->sc_dev, - "timeout waiting for adapter to initialize\n"); - goto fail; - } - - /* copy runtime images into pre-allocated DMA-sage memory */ - memcpy(dma->vaddr, rdata, rdatasz); - memcpy(dma->vaddr + WPI_FW_MAIN_DATA_MAXSZ, rtext, rtextsz); - bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); - - /* tell adapter where to find runtime images */ - wpi_mem_lock(sc); - wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr); - wpi_mem_write(sc, WPI_MEM_DATA_SIZE, rdatasz); - wpi_mem_write(sc, WPI_MEM_TEXT_BASE, - dma->paddr + WPI_FW_MAIN_DATA_MAXSZ); - wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, WPI_FW_UPDATED | rtextsz); - wpi_mem_unlock(sc); - - /* wait at most one second for the first alive notification */ - if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { - device_printf(sc->sc_dev, - "timeout waiting for adapter to initialize2\n"); - goto fail; - } - - DPRINTFN(WPI_DEBUG_FIRMWARE, - ("Firmware loaded to driver successfully\n")); - return error; -fail: - wpi_unload_firmware(sc); - return error; -} - -/** - * Free the referenced firmware image - */ -static void -wpi_unload_firmware(struct wpi_softc *sc) -{ - - if (sc->fw_fp) { - WPI_UNLOCK(sc); - firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); - WPI_LOCK(sc); - sc->fw_fp = NULL; - } -} - static int wpi_attach(device_t dev) { - struct wpi_softc *sc = device_get_softc(dev); - struct ifnet *ifp; + struct wpi_softc *sc = (struct wpi_softc *)device_get_softc(dev); struct ieee80211com *ic; - int ac, error, rid, supportsa = 1; - uint32_t tmp; + struct ifnet *ifp; + int i, error, rid, supportsa = 1; const struct wpi_ident *ident; uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; - if (bootverbose || WPI_DEBUG_SET) - device_printf(sc->sc_dev,"Driver Revision %s\n", VERSION); +#ifdef WPI_DEBUG + error = resource_int_value(device_get_name(sc->sc_dev), + device_get_unit(sc->sc_dev), "debug", &(sc->sc_debug)); + if (error != 0) + sc->sc_debug = 0; +#else + sc->sc_debug = 0; +#endif + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + /* + * Get the offset of the PCI Express Capability Structure in PCI + * Configuration Space. + */ + error = pci_find_cap(dev, PCIY_EXPRESS, &sc->sc_cap_off); + if (error != 0) { + device_printf(dev, "PCIe capability structure not found!\n"); + return error; + } /* * Some card's only support 802.11b/g not a, check to see if @@ -514,131 +347,118 @@ wpi_attach(device_t dev) } } - /* Create the tasks that can be queued */ - TASK_INIT(&sc->sc_restarttask, 0, wpi_hwreset, sc); - TASK_INIT(&sc->sc_radiotask, 0, wpi_rfreset, sc); - - WPI_LOCK_INIT(sc); - - callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); - callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); - - /* disable the retry timeout register */ + /* Clear device-specific "PCI retry timeout" register (41h). */ pci_write_config(dev, 0x41, 0, 1); - /* enable bus-mastering */ + /* Enable bus-mastering. */ pci_enable_busmaster(dev); rid = PCIR_BAR(0); sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem == NULL) { - device_printf(dev, "could not allocate memory resource\n"); + device_printf(dev, "can't map mem space\n"); error = ENOMEM; - goto fail; + return error; } - sc->sc_st = rman_get_bustag(sc->mem); sc->sc_sh = rman_get_bushandle(sc->mem); + i = 1; rid = 0; - sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE | RF_SHAREABLE); + if (pci_alloc_msi(dev, &i) == 0) + rid = 1; + /* Install interrupt handler. */ + sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | + (rid != 0 ? 0 : RF_SHAREABLE)); if (sc->irq == NULL) { - device_printf(dev, "could not allocate interrupt resource\n"); + device_printf(dev, "can't map interrupt\n"); error = ENOMEM; goto fail; } - /* - * Allocate DMA memory for firmware transfers. - */ + WPI_LOCK_INIT(sc); + + sc->sc_unr = new_unrhdr(WPI_ID_IBSS_MIN, WPI_ID_IBSS_MAX, &sc->sc_mtx); + + /* Allocate DMA memory for firmware transfers. */ if ((error = wpi_alloc_fwmem(sc)) != 0) { - printf(": could not allocate firmware memory\n"); - error = ENOMEM; + device_printf(dev, + "could not allocate memory for firmware, error %d\n", + error); goto fail; } - /* - * Put adapter into a known state. - */ - if ((error = wpi_reset(sc)) != 0) { - device_printf(dev, "could not reset adapter\n"); - goto fail; - } - - wpi_mem_lock(sc); - tmp = wpi_mem_read(sc, WPI_MEM_PCIDEV); - if (bootverbose || WPI_DEBUG_SET) - device_printf(sc->sc_dev, "Hardware Revision (0x%X)\n", tmp); - - wpi_mem_unlock(sc); - - /* Allocate shared page */ + /* Allocate shared page. */ if ((error = wpi_alloc_shared(sc)) != 0) { device_printf(dev, "could not allocate shared page\n"); goto fail; } - /* tx data queues - 4 for QoS purposes */ - for (ac = 0; ac < WME_NUM_AC; ac++) { - error = wpi_alloc_tx_ring(sc, &sc->txq[ac], WPI_TX_RING_COUNT, ac); - if (error != 0) { - device_printf(dev, "could not allocate Tx ring %d\n",ac); - goto fail; + /* Allocate TX rings - 4 for QoS purposes, 1 for commands. */ + for (i = 0; i < WPI_NTXQUEUES; i++) { + if ((error = wpi_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) { + device_printf(dev, + "could not allocate TX ring %d, error %d\n", i, + error); + goto fail; } } - /* command queue to talk to the card's firmware */ - error = wpi_alloc_tx_ring(sc, &sc->cmdq, WPI_CMD_RING_COUNT, 4); - if (error != 0) { - device_printf(dev, "could not allocate command ring\n"); + /* Allocate RX ring. */ + if ((error = wpi_alloc_rx_ring(sc)) != 0) { + device_printf(dev, "could not allocate RX ring, error %d\n", + error); goto fail; } - /* receive data queue */ - error = wpi_alloc_rx_ring(sc, &sc->rxq); - if (error != 0) { - device_printf(dev, "could not allocate Rx ring\n"); - goto fail; - } + /* Clear pending interrupts. */ + WPI_WRITE(sc, WPI_INT, 0xffffffff); ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); if (ifp == NULL) { - device_printf(dev, "can not if_alloc()\n"); - error = ENOMEM; + device_printf(dev, "can not allocate ifnet structure\n"); goto fail; } - ic = ifp->if_l2com; + ic = ifp->if_l2com; ic->ic_ifp = ifp; ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ - /* set device capabilities */ + /* Set device capabilities. */ ic->ic_caps = IEEE80211_C_STA /* station mode supported */ + | IEEE80211_C_IBSS /* IBSS mode supported */ | IEEE80211_C_MONITOR /* monitor mode supported */ + | IEEE80211_C_AHDEMO /* adhoc demo mode */ + | IEEE80211_C_BGSCAN /* capable of bg scanning */ | IEEE80211_C_TXPMGT /* tx power management */ | IEEE80211_C_SHSLOT /* short slot time supported */ - | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | IEEE80211_C_WPA /* 802.11i */ -/* XXX looks like WME is partly supported? */ + | IEEE80211_C_SHPREAMBLE /* short preamble supported */ #if 0 - | IEEE80211_C_IBSS /* IBSS mode support */ - | IEEE80211_C_BGSCAN /* capable of bg scanning */ - | IEEE80211_C_WME /* 802.11e */ | IEEE80211_C_HOSTAP /* Host access point mode */ #endif + | IEEE80211_C_WME /* 802.11e */ + | IEEE80211_C_PMGT /* Station-side power mgmt */ ; + ic->ic_cryptocaps = + IEEE80211_CRYPTO_AES_CCM; + /* * Read in the eeprom and also setup the channels for * net80211. We don't set the rates as net80211 does this for us */ - wpi_read_eeprom(sc, macaddr); + if ((error = wpi_read_eeprom(sc, macaddr)) != 0) { + device_printf(dev, "could not read EEPROM, error %d\n", + error); + goto fail; + } - if (bootverbose || WPI_DEBUG_SET) { +#ifdef WPI_DEBUG + if (bootverbose) { device_printf(sc->sc_dev, "Regulatory Domain: %.4s\n", sc->domain); device_printf(sc->sc_dev, "Hardware Type: %c\n", sc->type > 1 ? 'B': '?'); @@ -650,6 +470,7 @@ wpi_attach(device_t dev) /* XXX hw_config uses the PCIDEV for the Hardware rev. Must check what sc->rev really represents - benjsc 20070615 */ } +#endif if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_softc = sc; @@ -662,98 +483,89 @@ wpi_attach(device_t dev) IFQ_SET_READY(&ifp->if_snd); ieee80211_ifattach(ic, macaddr); - /* override default methods */ + ic->ic_vap_create = wpi_vap_create; + ic->ic_vap_delete = wpi_vap_delete; ic->ic_raw_xmit = wpi_raw_xmit; - ic->ic_wme.wme_update = wpi_wme_update; + ic->ic_node_alloc = wpi_node_alloc; + sc->sc_node_free = ic->ic_node_free; + ic->ic_node_free = wpi_node_free; + ic->ic_wme.wme_update = wpi_updateedca; + ic->ic_update_promisc = wpi_update_promisc; + ic->ic_update_mcast = wpi_update_mcast; ic->ic_scan_start = wpi_scan_start; ic->ic_scan_end = wpi_scan_end; ic->ic_set_channel = wpi_set_channel; + sc->sc_scan_curchan = ic->ic_scan_curchan; ic->ic_scan_curchan = wpi_scan_curchan; ic->ic_scan_mindwell = wpi_scan_mindwell; + ic->ic_setregdomain = wpi_setregdomain; - ic->ic_vap_create = wpi_vap_create; - ic->ic_vap_delete = wpi_vap_delete; + wpi_radiotap_attach(sc); - ieee80211_radiotap_attach(ic, - &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), - WPI_TX_RADIOTAP_PRESENT, - &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), - WPI_RX_RADIOTAP_PRESENT); + callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); + callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); + callout_init_mtx(&sc->watchdog_rfkill, &sc->sc_mtx, 0); + TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); + TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); + TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); + + wpi_sysctlattach(sc); /* * Hook our interrupt after all initialization is complete. */ - error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET |INTR_MPSAFE, + error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, wpi_intr, sc, &sc->sc_ih); if (error != 0) { - device_printf(dev, "could not set up interrupt\n"); + device_printf(dev, "can't establish interrupt, error %d\n", + error); goto fail; } if (bootverbose) ieee80211_announce(ic); -#ifdef XXX_DEBUG - ieee80211_announce_channels(ic); + +#ifdef WPI_DEBUG + if (sc->sc_debug & WPI_DEBUG_HW) + ieee80211_announce_channels(ic); #endif + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); return 0; fail: wpi_detach(dev); - return ENXIO; + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); + return error; } -static int -wpi_detach(device_t dev) +/* + * Attach the interface to 802.11 radiotap. + */ +static void +wpi_radiotap_attach(struct wpi_softc *sc) { - struct wpi_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic; - int ac; + struct ieee80211com *ic = ifp->if_l2com; + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + WPI_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + WPI_RX_RADIOTAP_PRESENT); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); +} - if (sc->irq != NULL) - bus_teardown_intr(dev, sc->irq, sc->sc_ih); +static void +wpi_sysctlattach(struct wpi_softc *sc) +{ +#ifdef WPI_DEBUG + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); + struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); - if (ifp != NULL) { - ic = ifp->if_l2com; - - ieee80211_draintask(ic, &sc->sc_restarttask); - ieee80211_draintask(ic, &sc->sc_radiotask); - wpi_stop(sc); - callout_drain(&sc->watchdog_to); - callout_drain(&sc->calib_to); - ieee80211_ifdetach(ic); - } - - WPI_LOCK(sc); - if (sc->txq[0].data_dmat) { - for (ac = 0; ac < WME_NUM_AC; ac++) - wpi_free_tx_ring(sc, &sc->txq[ac]); - - wpi_free_tx_ring(sc, &sc->cmdq); - wpi_free_rx_ring(sc, &sc->rxq); - wpi_free_shared(sc); - } - - if (sc->fw_fp != NULL) { - wpi_unload_firmware(sc); - } - - if (sc->fw_dma.tag) - wpi_free_fwmem(sc); - WPI_UNLOCK(sc); - - if (sc->irq != NULL) - bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), - sc->irq); - if (sc->mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - rman_get_rid(sc->mem), sc->mem); - - if (ifp != NULL) - if_free(ifp); - - WPI_LOCK_DESTROY(sc); - - return 0; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "debug", CTLFLAG_RW, &sc->sc_debug, sc->sc_debug, + "control debugging printfs"); +#endif } static struct ieee80211vap * @@ -763,22 +575,32 @@ wpi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, const uint8_t mac[IEEE80211_ADDR_LEN]) { struct wpi_vap *wvp; + struct wpi_buf *bcn; struct ieee80211vap *vap; if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; + wvp = (struct wpi_vap *) malloc(sizeof(struct wpi_vap), M_80211_VAP, M_NOWAIT | M_ZERO); if (wvp == NULL) return NULL; vap = &wvp->vap; ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); - /* override with driver methods */ + + bcn = &wvp->wv_bcbuf; + bcn->data = NULL; + + /* Override with driver methods. */ wvp->newstate = vap->iv_newstate; + vap->iv_key_alloc = wpi_key_alloc; + vap->iv_key_set = wpi_key_set; + vap->iv_key_delete = wpi_key_delete; vap->iv_newstate = wpi_newstate; + vap->iv_update_beacon = wpi_update_beacon; ieee80211_ratectl_init(vap); - /* complete setup */ + /* Complete setup. */ ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); ic->ic_opmode = opmode; return vap; @@ -788,414 +610,72 @@ static void wpi_vap_delete(struct ieee80211vap *vap) { struct wpi_vap *wvp = WPI_VAP(vap); + struct wpi_buf *bcn = &wvp->wv_bcbuf; ieee80211_ratectl_deinit(vap); ieee80211_vap_detach(vap); + + if (bcn->data != NULL) + free(bcn->data, M_DEVBUF); free(wvp, M_80211_VAP); } -static void -wpi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) -{ - if (error != 0) - return; - - KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); - - *(bus_addr_t *)arg = segs[0].ds_addr; -} - -/* - * Allocates a contiguous block of dma memory of the requested size and - * alignment. Due to limitations of the FreeBSD dma subsystem as of 20071217, - * allocations greater than 4096 may fail. Hence if the requested alignment is - * greater we allocate 'alignment' size extra memory and shift the vaddr and - * paddr after the dma load. This bypasses the problem at the cost of a little - * more memory. - */ static int -wpi_dma_contig_alloc(struct wpi_softc *sc, struct wpi_dma_info *dma, - void **kvap, bus_size_t size, bus_size_t alignment, int flags) +wpi_detach(device_t dev) { - int error; - bus_size_t align; - bus_size_t reqsize; + struct wpi_softc *sc = device_get_softc(dev); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic; + int qid; - DPRINTFN(WPI_DEBUG_DMA, - ("Size: %zd - alignment %zd\n", size, alignment)); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - dma->size = size; - dma->tag = NULL; + if (ifp != NULL) { + ic = ifp->if_l2com; - if (alignment > 4096) { - align = PAGE_SIZE; - reqsize = size + alignment; - } else { - align = alignment; - reqsize = size; - } - error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), align, - 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, - NULL, NULL, reqsize, - 1, reqsize, flags, - NULL, NULL, &dma->tag); - if (error != 0) { - device_printf(sc->sc_dev, - "could not create shared page DMA tag\n"); - goto fail; - } - error = bus_dmamem_alloc(dma->tag, (void **)&dma->vaddr_start, - flags | BUS_DMA_ZERO, &dma->map); - if (error != 0) { - device_printf(sc->sc_dev, - "could not allocate shared page DMA memory\n"); - goto fail; + ieee80211_draintask(ic, &sc->sc_reinittask); + ieee80211_draintask(ic, &sc->sc_radiooff_task); + + wpi_stop(sc); + + callout_drain(&sc->watchdog_to); + callout_drain(&sc->watchdog_rfkill); + callout_drain(&sc->calib_to); + ieee80211_ifdetach(ic); } - error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr_start, - reqsize, wpi_dma_map_addr, &dma->paddr_start, flags); - - /* Save the original pointers so we can free all the memory */ - dma->paddr = dma->paddr_start; - dma->vaddr = dma->vaddr_start; - - /* - * Check the alignment and increment by 4096 until we get the - * requested alignment. Fail if can't obtain the alignment - * we requested. - */ - if ((dma->paddr & (alignment -1 )) != 0) { - int i; - - for (i = 0; i < alignment / 4096; i++) { - if ((dma->paddr & (alignment - 1 )) == 0) - break; - dma->paddr += 4096; - dma->vaddr += 4096; - } - if (i == alignment / 4096) { - device_printf(sc->sc_dev, - "alignment requirement was not satisfied\n"); - goto fail; - } + /* Uninstall interrupt handler. */ + if (sc->irq != NULL) { + bus_teardown_intr(dev, sc->irq, sc->sc_ih); + bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), + sc->irq); + pci_release_msi(dev); } - if (error != 0) { - device_printf(sc->sc_dev, - "could not load shared page DMA map\n"); - goto fail; + if (sc->txq[0].data_dmat) { + /* Free DMA resources. */ + for (qid = 0; qid < WPI_NTXQUEUES; qid++) + wpi_free_tx_ring(sc, &sc->txq[qid]); + + wpi_free_rx_ring(sc); + wpi_free_shared(sc); } - if (kvap != NULL) - *kvap = dma->vaddr; + if (sc->fw_dma.tag) + wpi_free_fwmem(sc); + + if (sc->mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, + rman_get_rid(sc->mem), sc->mem); + if (ifp != NULL) + if_free(ifp); + + delete_unrhdr(sc->sc_unr); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + WPI_LOCK_DESTROY(sc); return 0; - -fail: - wpi_dma_contig_free(dma); - return error; -} - -static void -wpi_dma_contig_free(struct wpi_dma_info *dma) -{ - if (dma->tag) { - if (dma->vaddr_start != NULL) { - if (dma->paddr_start != 0) { - bus_dmamap_sync(dma->tag, dma->map, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(dma->tag, dma->map); - } - bus_dmamem_free(dma->tag, dma->vaddr_start, dma->map); - } - bus_dma_tag_destroy(dma->tag); - } -} - -/* - * Allocate a shared page between host and NIC. - */ -static int -wpi_alloc_shared(struct wpi_softc *sc) -{ - int error; - - error = wpi_dma_contig_alloc(sc, &sc->shared_dma, - (void **)&sc->shared, sizeof (struct wpi_shared), - PAGE_SIZE, - BUS_DMA_NOWAIT); - - if (error != 0) { - device_printf(sc->sc_dev, - "could not allocate shared area DMA memory\n"); - } - - return error; -} - -static void -wpi_free_shared(struct wpi_softc *sc) -{ - wpi_dma_contig_free(&sc->shared_dma); -} - -static int -wpi_alloc_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) -{ - - int i, error; - - ring->cur = 0; - - error = wpi_dma_contig_alloc(sc, &ring->desc_dma, - (void **)&ring->desc, WPI_RX_RING_COUNT * sizeof (uint32_t), - WPI_RING_DMA_ALIGN, BUS_DMA_NOWAIT); - - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not allocate rx ring DMA memory, error %d\n", - __func__, error); - goto fail; - } - - error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, - BUS_SPACE_MAXADDR, NULL, NULL, MJUMPAGESIZE, 1, - MJUMPAGESIZE, BUS_DMA_NOWAIT, NULL, NULL, &ring->data_dmat); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: bus_dma_tag_create_failed, error %d\n", - __func__, error); - goto fail; - } - - /* - * Setup Rx buffers. - */ - for (i = 0; i < WPI_RX_RING_COUNT; i++) { - struct wpi_rx_data *data = &ring->data[i]; - struct mbuf *m; - bus_addr_t paddr; - - error = bus_dmamap_create(ring->data_dmat, 0, &data->map); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: bus_dmamap_create failed, error %d\n", - __func__, error); - goto fail; - } - m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); - if (m == NULL) { - device_printf(sc->sc_dev, - "%s: could not allocate rx mbuf\n", __func__); - error = ENOMEM; - goto fail; - } - /* map page */ - error = bus_dmamap_load(ring->data_dmat, data->map, - mtod(m, caddr_t), MJUMPAGESIZE, - wpi_dma_map_addr, &paddr, BUS_DMA_NOWAIT); - if (error != 0 && error != EFBIG) { - device_printf(sc->sc_dev, - "%s: bus_dmamap_load failed, error %d\n", - __func__, error); - m_freem(m); - error = ENOMEM; /* XXX unique code */ - goto fail; - } - bus_dmamap_sync(ring->data_dmat, data->map, - BUS_DMASYNC_PREWRITE); - - data->m = m; - ring->desc[i] = htole32(paddr); - } - bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, - BUS_DMASYNC_PREWRITE); - return 0; -fail: - wpi_free_rx_ring(sc, ring); - return error; -} - -static void -wpi_reset_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) -{ - int ntries; - - wpi_mem_lock(sc); - - WPI_WRITE(sc, WPI_RX_CONFIG, 0); - - for (ntries = 0; ntries < 100; ntries++) { - if (WPI_READ(sc, WPI_RX_STATUS) & WPI_RX_IDLE) - break; - DELAY(10); - } - - wpi_mem_unlock(sc); - -#ifdef WPI_DEBUG - if (ntries == 100 && wpi_debug > 0) - device_printf(sc->sc_dev, "timeout resetting Rx ring\n"); -#endif - - ring->cur = 0; -} - -static void -wpi_free_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) -{ - int i; - - wpi_dma_contig_free(&ring->desc_dma); - - for (i = 0; i < WPI_RX_RING_COUNT; i++) { - struct wpi_rx_data *data = &ring->data[i]; - - if (data->m != NULL) { - bus_dmamap_sync(ring->data_dmat, data->map, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(ring->data_dmat, data->map); - m_freem(data->m); - } - if (data->map != NULL) - bus_dmamap_destroy(ring->data_dmat, data->map); - } -} - -static int -wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int count, - int qid) -{ - struct wpi_tx_data *data; - int i, error; - - ring->qid = qid; - ring->count = count; - ring->queued = 0; - ring->cur = 0; - ring->data = NULL; - - error = wpi_dma_contig_alloc(sc, &ring->desc_dma, - (void **)&ring->desc, count * sizeof (struct wpi_tx_desc), - WPI_RING_DMA_ALIGN, BUS_DMA_NOWAIT); - - if (error != 0) { - device_printf(sc->sc_dev, "could not allocate tx dma memory\n"); - goto fail; - } - - /* update shared page with ring's base address */ - sc->shared->txbase[qid] = htole32(ring->desc_dma.paddr); - - error = wpi_dma_contig_alloc(sc, &ring->cmd_dma, (void **)&ring->cmd, - count * sizeof (struct wpi_tx_cmd), WPI_RING_DMA_ALIGN, - BUS_DMA_NOWAIT); - - if (error != 0) { - device_printf(sc->sc_dev, - "could not allocate tx command DMA memory\n"); - goto fail; - } - - ring->data = malloc(count * sizeof (struct wpi_tx_data), M_DEVBUF, - M_NOWAIT | M_ZERO); - if (ring->data == NULL) { - device_printf(sc->sc_dev, - "could not allocate tx data slots\n"); - goto fail; - } - - error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, - WPI_MAX_SCATTER - 1, MCLBYTES, BUS_DMA_NOWAIT, NULL, NULL, - &ring->data_dmat); - if (error != 0) { - device_printf(sc->sc_dev, "could not create data DMA tag\n"); - goto fail; - } - - for (i = 0; i < count; i++) { - data = &ring->data[i]; - - error = bus_dmamap_create(ring->data_dmat, 0, &data->map); - if (error != 0) { - device_printf(sc->sc_dev, - "could not create tx buf DMA map\n"); - goto fail; - } - bus_dmamap_sync(ring->data_dmat, data->map, - BUS_DMASYNC_PREWRITE); - } - - return 0; - -fail: - wpi_free_tx_ring(sc, ring); - return error; -} - -static void -wpi_reset_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) -{ - struct wpi_tx_data *data; - int i, ntries; - - wpi_mem_lock(sc); - - WPI_WRITE(sc, WPI_TX_CONFIG(ring->qid), 0); - for (ntries = 0; ntries < 100; ntries++) { - if (WPI_READ(sc, WPI_TX_STATUS) & WPI_TX_IDLE(ring->qid)) - break; - DELAY(10); - } -#ifdef WPI_DEBUG - if (ntries == 100 && wpi_debug > 0) - device_printf(sc->sc_dev, "timeout resetting Tx ring %d\n", - ring->qid); -#endif - wpi_mem_unlock(sc); - - for (i = 0; i < ring->count; i++) { - data = &ring->data[i]; - - if (data->m != NULL) { - bus_dmamap_unload(ring->data_dmat, data->map); - m_freem(data->m); - data->m = NULL; - } - } - - ring->queued = 0; - ring->cur = 0; -} - -static void -wpi_free_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) -{ - struct wpi_tx_data *data; - int i; - - wpi_dma_contig_free(&ring->desc_dma); - wpi_dma_contig_free(&ring->cmd_dma); - - if (ring->data != NULL) { - for (i = 0; i < ring->count; i++) { - data = &ring->data[i]; - - if (data->m != NULL) { - bus_dmamap_sync(ring->data_dmat, data->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(ring->data_dmat, data->map); - m_freem(data->m); - data->m = NULL; - } - } - free(ring->data, M_DEVBUF); - } - - if (ring->data_dmat != NULL) - bus_dma_tag_destroy(ring->data_dmat); } static int @@ -1203,11 +683,7 @@ wpi_shutdown(device_t dev) { struct wpi_softc *sc = device_get_softc(dev); - WPI_LOCK(sc); - wpi_stop_locked(sc); - wpi_unload_firmware(sc); - WPI_UNLOCK(sc); - + wpi_stop(sc); return 0; } @@ -1227,12 +703,831 @@ wpi_resume(device_t dev) struct wpi_softc *sc = device_get_softc(dev); struct ieee80211com *ic = sc->sc_ifp->if_l2com; + /* Clear device-specific "PCI retry timeout" register (41h). */ pci_write_config(dev, 0x41, 0, 1); ieee80211_resume_all(ic); return 0; } +/* + * Grab exclusive access to NIC memory. + */ +static int +wpi_nic_lock(struct wpi_softc *sc) +{ + int ntries; + + /* Request exclusive access to NIC. */ + WPI_SETBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); + + /* Spin until we actually get the lock. */ + for (ntries = 0; ntries < 1000; ntries++) { + if ((WPI_READ(sc, WPI_GP_CNTRL) & + (WPI_GP_CNTRL_MAC_ACCESS_ENA | WPI_GP_CNTRL_SLEEP)) == + WPI_GP_CNTRL_MAC_ACCESS_ENA) + return 0; + DELAY(10); + } + + device_printf(sc->sc_dev, "could not lock memory\n"); + + return ETIMEDOUT; +} + +/* + * Release lock on NIC memory. + */ +static __inline void +wpi_nic_unlock(struct wpi_softc *sc) +{ + WPI_CLRBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); +} + +static __inline uint32_t +wpi_prph_read(struct wpi_softc *sc, uint32_t addr) +{ + WPI_WRITE(sc, WPI_PRPH_RADDR, WPI_PRPH_DWORD | addr); + WPI_BARRIER_READ_WRITE(sc); + return WPI_READ(sc, WPI_PRPH_RDATA); +} + +static __inline void +wpi_prph_write(struct wpi_softc *sc, uint32_t addr, uint32_t data) +{ + WPI_WRITE(sc, WPI_PRPH_WADDR, WPI_PRPH_DWORD | addr); + WPI_BARRIER_WRITE(sc); + WPI_WRITE(sc, WPI_PRPH_WDATA, data); +} + +static __inline void +wpi_prph_setbits(struct wpi_softc *sc, uint32_t addr, uint32_t mask) +{ + wpi_prph_write(sc, addr, wpi_prph_read(sc, addr) | mask); +} + +static __inline void +wpi_prph_clrbits(struct wpi_softc *sc, uint32_t addr, uint32_t mask) +{ + wpi_prph_write(sc, addr, wpi_prph_read(sc, addr) & ~mask); +} + +static __inline void +wpi_prph_write_region_4(struct wpi_softc *sc, uint32_t addr, + const uint32_t *data, int count) +{ + for (; count > 0; count--, data++, addr += 4) + wpi_prph_write(sc, addr, *data); +} + +static __inline uint32_t +wpi_mem_read(struct wpi_softc *sc, uint32_t addr) +{ + WPI_WRITE(sc, WPI_MEM_RADDR, addr); + WPI_BARRIER_READ_WRITE(sc); + return WPI_READ(sc, WPI_MEM_RDATA); +} + +static __inline void +wpi_mem_read_region_4(struct wpi_softc *sc, uint32_t addr, uint32_t *data, + int count) +{ + for (; count > 0; count--, addr += 4) + *data++ = wpi_mem_read(sc, addr); +} + +static int +wpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int count) +{ + uint8_t *out = data; + uint32_t val; + int error, ntries; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + if ((error = wpi_nic_lock(sc)) != 0) + return error; + + for (; count > 0; count -= 2, addr++) { + WPI_WRITE(sc, WPI_EEPROM, addr << 2); + for (ntries = 0; ntries < 10; ntries++) { + val = WPI_READ(sc, WPI_EEPROM); + if (val & WPI_EEPROM_READ_VALID) + break; + DELAY(5); + } + if (ntries == 10) { + device_printf(sc->sc_dev, + "timeout reading ROM at 0x%x\n", addr); + return ETIMEDOUT; + } + *out++= val >> 16; + if (count > 1) + *out ++= val >> 24; + } + + wpi_nic_unlock(sc); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return 0; +} + +static void +wpi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + if (error != 0) + return; + KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); + *(bus_addr_t *)arg = segs[0].ds_addr; +} + +/* + * Allocates a contiguous block of dma memory of the requested size and + * alignment. + */ +static int +wpi_dma_contig_alloc(struct wpi_softc *sc, struct wpi_dma_info *dma, + void **kvap, bus_size_t size, bus_size_t alignment) +{ + int error; + + dma->tag = NULL; + dma->size = size; + + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), alignment, + 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size, + 1, size, BUS_DMA_NOWAIT, NULL, NULL, &dma->tag); + if (error != 0) + goto fail; + + error = bus_dmamem_alloc(dma->tag, (void **)&dma->vaddr, + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, &dma->map); + if (error != 0) + goto fail; + + error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr, size, + wpi_dma_map_addr, &dma->paddr, BUS_DMA_NOWAIT); + if (error != 0) + goto fail; + + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); + + if (kvap != NULL) + *kvap = dma->vaddr; + + return 0; + +fail: wpi_dma_contig_free(dma); + return error; +} + +static void +wpi_dma_contig_free(struct wpi_dma_info *dma) +{ + if (dma->vaddr != NULL) { + bus_dmamap_sync(dma->tag, dma->map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(dma->tag, dma->map); + bus_dmamem_free(dma->tag, dma->vaddr, dma->map); + dma->vaddr = NULL; + } + if (dma->tag != NULL) { + bus_dma_tag_destroy(dma->tag); + dma->tag = NULL; + } +} + +/* + * Allocate a shared page between host and NIC. + */ +static int +wpi_alloc_shared(struct wpi_softc *sc) +{ + /* Shared buffer must be aligned on a 4KB boundary. */ + return wpi_dma_contig_alloc(sc, &sc->shared_dma, + (void **)&sc->shared, sizeof (struct wpi_shared), 4096); +} + +static void +wpi_free_shared(struct wpi_softc *sc) +{ + wpi_dma_contig_free(&sc->shared_dma); +} + +/* + * Allocate DMA-safe memory for firmware transfer. + */ +static int +wpi_alloc_fwmem(struct wpi_softc *sc) +{ + /* Must be aligned on a 16-byte boundary. */ + return wpi_dma_contig_alloc(sc, &sc->fw_dma, NULL, + WPI_FW_TEXT_MAXSZ + WPI_FW_DATA_MAXSZ, 16); +} + +static void +wpi_free_fwmem(struct wpi_softc *sc) +{ + wpi_dma_contig_free(&sc->fw_dma); +} + +static int +wpi_alloc_rx_ring(struct wpi_softc *sc) +{ + struct wpi_rx_ring *ring = &sc->rxq; + bus_size_t size; + int i, error; + + ring->cur = 0; + ring->update = 0; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + /* Allocate RX descriptors (16KB aligned.) */ + size = WPI_RX_RING_COUNT * sizeof (uint32_t); + error = wpi_dma_contig_alloc(sc, &ring->desc_dma, + (void **)&ring->desc, size, WPI_RING_DMA_ALIGN); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not allocate RX ring DMA memory, error %d\n", + __func__, error); + goto fail; + } + + /* Create RX buffer DMA tag. */ + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + MJUMPAGESIZE, 1, MJUMPAGESIZE, BUS_DMA_NOWAIT, NULL, NULL, + &ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not create RX buf DMA tag, error %d\n", + __func__, error); + goto fail; + } + + /* + * Allocate and map RX buffers. + */ + for (i = 0; i < WPI_RX_RING_COUNT; i++) { + struct wpi_rx_data *data = &ring->data[i]; + bus_addr_t paddr; + + error = bus_dmamap_create(ring->data_dmat, 0, &data->map); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not create RX buf DMA map, error %d\n", + __func__, error); + goto fail; + } + + data->m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); + if (data->m == NULL) { + device_printf(sc->sc_dev, + "%s: could not allocate RX mbuf\n", __func__); + error = ENOBUFS; + goto fail; + } + + error = bus_dmamap_load(ring->data_dmat, data->map, + mtod(data->m, void *), MJUMPAGESIZE, wpi_dma_map_addr, + &paddr, BUS_DMA_NOWAIT); + if (error != 0 && error != EFBIG) { + device_printf(sc->sc_dev, + "%s: can't map mbuf (error %d)\n", __func__, + error); + goto fail; + } + + /* Set physical address of RX buffer. */ + ring->desc[i] = htole32(paddr); + } + + bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, + BUS_DMASYNC_PREWRITE); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return 0; + +fail: wpi_free_rx_ring(sc); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); + + return error; +} + +static void +wpi_update_rx_ring(struct wpi_softc *sc) +{ + struct wpi_rx_ring *ring = &sc->rxq; + + if (WPI_READ(sc, WPI_UCODE_GP1) & WPI_UCODE_GP1_MAC_SLEEP) { + DPRINTF(sc, WPI_DEBUG_PWRSAVE, "%s: wakeup request\n", + __func__); + + WPI_SETBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); + ring->update = 1; + } else + WPI_WRITE(sc, WPI_FH_RX_WPTR, ring->cur & ~7); +} + +static void +wpi_reset_rx_ring(struct wpi_softc *sc) +{ + struct wpi_rx_ring *ring = &sc->rxq; + int ntries; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + if (wpi_nic_lock(sc) == 0) { + WPI_WRITE(sc, WPI_FH_RX_CONFIG, 0); + for (ntries = 0; ntries < 1000; ntries++) { + if (WPI_READ(sc, WPI_FH_RX_STATUS) & + WPI_FH_RX_STATUS_IDLE) + break; + DELAY(10); + } +#ifdef WPI_DEBUG + if (ntries == 1000) { + device_printf(sc->sc_dev, + "timeout resetting Rx ring\n"); + } +#endif + wpi_nic_unlock(sc); + } + + ring->cur = 0; + ring->update = 0; +} + +static void +wpi_free_rx_ring(struct wpi_softc *sc) +{ + struct wpi_rx_ring *ring = &sc->rxq; + int i; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + wpi_dma_contig_free(&ring->desc_dma); + + for (i = 0; i < WPI_RX_RING_COUNT; i++) { + struct wpi_rx_data *data = &ring->data[i]; + + if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(ring->data_dmat, data->map); + m_freem(data->m); + data->m = NULL; + } + if (data->map != NULL) + bus_dmamap_destroy(ring->data_dmat, data->map); + } + if (ring->data_dmat != NULL) { + bus_dma_tag_destroy(ring->data_dmat); + ring->data_dmat = NULL; + } +} + +static int +wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int qid) +{ + bus_addr_t paddr; + bus_size_t size; + int i, error; + + ring->qid = qid; + ring->queued = 0; + ring->cur = 0; + ring->update = 0; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + /* Allocate TX descriptors (16KB aligned.) */ + size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_desc); + error = wpi_dma_contig_alloc(sc, &ring->desc_dma, (void **)&ring->desc, + size, WPI_RING_DMA_ALIGN); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not allocate TX ring DMA memory, error %d\n", + __func__, error); + goto fail; + } + + /* Update shared area with ring physical address. */ + sc->shared->txbase[qid] = htole32(ring->desc_dma.paddr); + bus_dmamap_sync(sc->shared_dma.tag, sc->shared_dma.map, + BUS_DMASYNC_PREWRITE); + + /* + * We only use rings 0 through 4 (4 EDCA + cmd) so there is no need + * to allocate commands space for other rings. + * XXX Do we really need to allocate descriptors for other rings? + */ + if (qid > 4) + return 0; + + size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_cmd); + error = wpi_dma_contig_alloc(sc, &ring->cmd_dma, (void **)&ring->cmd, + size, 4); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not allocate TX cmd DMA memory, error %d\n", + __func__, error); + goto fail; + } + + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, + WPI_MAX_SCATTER - 1, MCLBYTES, BUS_DMA_NOWAIT, NULL, NULL, + &ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not create TX buf DMA tag, error %d\n", + __func__, error); + goto fail; + } + + paddr = ring->cmd_dma.paddr; + for (i = 0; i < WPI_TX_RING_COUNT; i++) { + struct wpi_tx_data *data = &ring->data[i]; + + data->cmd_paddr = paddr; + paddr += sizeof (struct wpi_tx_cmd); + + error = bus_dmamap_create(ring->data_dmat, 0, &data->map); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not create TX buf DMA map, error %d\n", + __func__, error); + goto fail; + } + } + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return 0; + +fail: wpi_free_tx_ring(sc, ring); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); + return error; +} + +static void +wpi_update_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) +{ + if (WPI_READ(sc, WPI_UCODE_GP1) & WPI_UCODE_GP1_MAC_SLEEP) { + DPRINTF(sc, WPI_DEBUG_PWRSAVE, "%s (%d): requesting wakeup\n", + __func__, ring->qid); + + WPI_SETBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); + ring->update = 1; + } else + WPI_WRITE(sc, WPI_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); +} + +static void +wpi_reset_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) +{ + int i; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + for (i = 0; i < WPI_TX_RING_COUNT; i++) { + struct wpi_tx_data *data = &ring->data[i]; + + if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + m_freem(data->m); + data->m = NULL; + } + } + /* Clear TX descriptors. */ + memset(ring->desc, 0, ring->desc_dma.size); + bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, + BUS_DMASYNC_PREWRITE); + sc->qfullmsk &= ~(1 << ring->qid); + ring->queued = 0; + ring->cur = 0; + ring->update = 0; +} + +static void +wpi_free_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) +{ + int i; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + wpi_dma_contig_free(&ring->desc_dma); + wpi_dma_contig_free(&ring->cmd_dma); + + for (i = 0; i < WPI_TX_RING_COUNT; i++) { + struct wpi_tx_data *data = &ring->data[i]; + + if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + m_freem(data->m); + } + if (data->map != NULL) + bus_dmamap_destroy(ring->data_dmat, data->map); + } + if (ring->data_dmat != NULL) { + bus_dma_tag_destroy(ring->data_dmat); + ring->data_dmat = NULL; + } +} + +/* + * Extract various information from EEPROM. + */ +static int +wpi_read_eeprom(struct wpi_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) +{ +#define WPI_CHK(res) do { \ + if ((error = res) != 0) \ + goto fail; \ +} while (0) + int error, i; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + /* Adapter has to be powered on for EEPROM access to work. */ + if ((error = wpi_apm_init(sc)) != 0) { + device_printf(sc->sc_dev, + "%s: could not power ON adapter, error %d\n", __func__, + error); + return error; + } + + if ((WPI_READ(sc, WPI_EEPROM_GP) & 0x6) == 0) { + device_printf(sc->sc_dev, "bad EEPROM signature\n"); + error = EIO; + goto fail; + } + /* Clear HW ownership of EEPROM. */ + WPI_CLRBITS(sc, WPI_EEPROM_GP, WPI_EEPROM_GP_IF_OWNER); + + /* Read the hardware capabilities, revision and SKU type. */ + WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_SKU_CAP, &sc->cap, + sizeof(sc->cap))); + WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_REVISION, &sc->rev, + sizeof(sc->rev))); + WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_TYPE, &sc->type, + sizeof(sc->type))); + + DPRINTF(sc, WPI_DEBUG_EEPROM, "cap=%x rev=%x type=%x\n", sc->cap, le16toh(sc->rev), + sc->type); + + /* Read the regulatory domain (4 ASCII characters.) */ + WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_DOMAIN, sc->domain, + sizeof(sc->domain))); + + /* Read MAC address. */ + WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_MAC, macaddr, + IEEE80211_ADDR_LEN)); + + /* Read the list of authorized channels. */ + for (i = 0; i < WPI_CHAN_BANDS_COUNT; i++) + WPI_CHK(wpi_read_eeprom_channels(sc, i)); + + /* Read the list of TX power groups. */ + for (i = 0; i < WPI_POWER_GROUPS_COUNT; i++) + WPI_CHK(wpi_read_eeprom_group(sc, i)); + +fail: wpi_apm_stop(sc); /* Power OFF adapter. */ + + DPRINTF(sc, WPI_DEBUG_TRACE, error ? TRACE_STR_END_ERR : TRACE_STR_END, + __func__); + + return error; +#undef WPI_CHK +} + +/* + * Translate EEPROM flags to net80211. + */ +static uint32_t +wpi_eeprom_channel_flags(struct wpi_eeprom_chan *channel) +{ + uint32_t nflags; + + nflags = 0; + if ((channel->flags & WPI_EEPROM_CHAN_ACTIVE) == 0) + nflags |= IEEE80211_CHAN_PASSIVE; + if ((channel->flags & WPI_EEPROM_CHAN_IBSS) == 0) + nflags |= IEEE80211_CHAN_NOADHOC; + if (channel->flags & WPI_EEPROM_CHAN_RADAR) { + nflags |= IEEE80211_CHAN_DFS; + /* XXX apparently IBSS may still be marked */ + nflags |= IEEE80211_CHAN_NOADHOC; + } + + return nflags; +} + +static void +wpi_read_eeprom_band(struct wpi_softc *sc, int n) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct wpi_eeprom_chan *channels = sc->eeprom_channels[n]; + const struct wpi_chan_band *band = &wpi_bands[n]; + struct ieee80211_channel *c; + uint8_t chan; + int i, nflags; + + for (i = 0; i < band->nchan; i++) { + if (!(channels[i].flags & WPI_EEPROM_CHAN_VALID)) { + DPRINTF(sc, WPI_DEBUG_HW, + "Channel Not Valid: %d, band %d\n", + band->chan[i],n); + continue; + } + + chan = band->chan[i]; + nflags = wpi_eeprom_channel_flags(&channels[i]); + + c = &ic->ic_channels[ic->ic_nchans++]; + c->ic_ieee = chan; + c->ic_maxregpower = channels[i].maxpwr; + c->ic_maxpower = 2*c->ic_maxregpower; + + if (n == 0) { /* 2GHz band */ + c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_G); + /* G =>'s B is supported */ + c->ic_flags = IEEE80211_CHAN_B | nflags; + c = &ic->ic_channels[ic->ic_nchans++]; + c[0] = c[-1]; + c->ic_flags = IEEE80211_CHAN_G | nflags; + } else { /* 5GHz band */ + c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_A); + c->ic_flags = IEEE80211_CHAN_A | nflags; + } + + /* Save maximum allowed TX power for this channel. */ + sc->maxpwr[chan] = channels[i].maxpwr; + + DPRINTF(sc, WPI_DEBUG_EEPROM, + "adding chan %d (%dMHz) flags=0x%x maxpwr=%d passive=%d," + " offset %d\n", chan, c->ic_freq, + channels[i].flags, sc->maxpwr[chan], + (c->ic_flags & IEEE80211_CHAN_PASSIVE) != 0, + ic->ic_nchans); + } +} + +/** + * Read the eeprom to find out what channels are valid for the given + * band and update net80211 with what we find. + */ +static int +wpi_read_eeprom_channels(struct wpi_softc *sc, int n) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + const struct wpi_chan_band *band = &wpi_bands[n]; + int error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + error = wpi_read_prom_data(sc, band->addr, &sc->eeprom_channels[n], + band->nchan * sizeof (struct wpi_eeprom_chan)); + if (error != 0) { + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); + return error; + } + + wpi_read_eeprom_band(sc, n); + + ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return 0; +} + +static struct wpi_eeprom_chan * +wpi_find_eeprom_channel(struct wpi_softc *sc, struct ieee80211_channel *c) +{ + int i, j; + + for (j = 0; j < WPI_CHAN_BANDS_COUNT; j++) + for (i = 0; i < wpi_bands[j].nchan; i++) + if (wpi_bands[j].chan[i] == c->ic_ieee) + return &sc->eeprom_channels[j][i]; + + return NULL; +} + +/* + * Enforce flags read from EEPROM. + */ +static int +wpi_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, + int nchan, struct ieee80211_channel chans[]) +{ + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; + int i; + + for (i = 0; i < nchan; i++) { + struct ieee80211_channel *c = &chans[i]; + struct wpi_eeprom_chan *channel; + + channel = wpi_find_eeprom_channel(sc, c); + if (channel == NULL) { + if_printf(ic->ic_ifp, + "%s: invalid channel %u freq %u/0x%x\n", + __func__, c->ic_ieee, c->ic_freq, c->ic_flags); + return EINVAL; + } + c->ic_flags |= wpi_eeprom_channel_flags(channel); + } + + return 0; +} + +static int +wpi_read_eeprom_group(struct wpi_softc *sc, int n) +{ + struct wpi_power_group *group = &sc->groups[n]; + struct wpi_eeprom_group rgroup; + int i, error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + if ((error = wpi_read_prom_data(sc, WPI_EEPROM_POWER_GRP + n * 32, + &rgroup, sizeof rgroup)) != 0) { + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); + return error; + } + + /* Save TX power group information. */ + group->chan = rgroup.chan; + group->maxpwr = rgroup.maxpwr; + /* Retrieve temperature at which the samples were taken. */ + group->temp = (int16_t)le16toh(rgroup.temp); + + DPRINTF(sc, WPI_DEBUG_EEPROM, + "power group %d: chan=%d maxpwr=%d temp=%d\n", n, group->chan, + group->maxpwr, group->temp); + + for (i = 0; i < WPI_SAMPLES_COUNT; i++) { + group->samples[i].index = rgroup.samples[i].index; + group->samples[i].power = rgroup.samples[i].power; + + DPRINTF(sc, WPI_DEBUG_EEPROM, + "\tsample %d: index=%d power=%d\n", i, + group->samples[i].index, group->samples[i].power); + } + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return 0; +} + +static struct ieee80211_node * +wpi_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct wpi_node *wn; + + wn = malloc(sizeof (struct wpi_node), M_80211_NODE, + M_NOWAIT | M_ZERO); + + if (wn == NULL) + return NULL; + + wn->id = WPI_ID_UNDEFINED; + + return &wn->ni; +} + +static void +wpi_node_free(struct ieee80211_node *ni) +{ + struct ieee80211com *ic = ni->ni_ic; + struct wpi_softc *sc = ic->ic_ifp->if_softc; + struct wpi_node *wn = (struct wpi_node *)ni; + + if (wn->id >= WPI_ID_IBSS_MIN && wn->id <= WPI_ID_IBSS_MAX) { + free_unr(sc->sc_unr, wn->id); + + WPI_LOCK(sc); + if (sc->rxon.filter & htole32(WPI_FILTER_BSS)) + wpi_del_node(sc, ni); + WPI_UNLOCK(sc); + } + + sc->sc_node_free(ni); +} + /** * Called by net80211 when ever there is a change to 80211 state machine */ @@ -1243,396 +1538,376 @@ wpi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = ic->ic_ifp; struct wpi_softc *sc = ifp->if_softc; - int error; + int error = 0; - DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__, + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + DPRINTF(sc, WPI_DEBUG_STATE, "%s: %s -> %s\n", __func__, ieee80211_state_name[vap->iv_state], - ieee80211_state_name[nstate], sc->flags)); + ieee80211_state_name[nstate]); IEEE80211_UNLOCK(ic); WPI_LOCK(sc); - if (nstate == IEEE80211_S_SCAN && vap->iv_state != IEEE80211_S_INIT) { - /* - * On !INIT -> SCAN transitions, we need to clear any possible - * knowledge about associations. - */ - error = wpi_config(sc); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: device config failed, error %d\n", - __func__, error); + switch (nstate) { + case IEEE80211_S_SCAN: + if ((vap->iv_opmode == IEEE80211_M_IBSS || + vap->iv_opmode == IEEE80211_M_AHDEMO) && + (sc->rxon.filter & htole32(WPI_FILTER_BSS))) { + sc->rxon.filter &= ~htole32(WPI_FILTER_BSS); + if ((error = wpi_send_rxon(sc, 0, 1)) != 0) { + device_printf(sc->sc_dev, + "%s: could not send RXON\n", __func__); + } } - } - if (nstate == IEEE80211_S_AUTH || - (nstate == IEEE80211_S_ASSOC && vap->iv_state == IEEE80211_S_RUN)) { + break; + + case IEEE80211_S_ASSOC: + if (vap->iv_state != IEEE80211_S_RUN) + break; + /* FALLTHROUGH */ + case IEEE80211_S_AUTH: /* * The node must be registered in the firmware before auth. * Also the associd must be cleared on RUN -> ASSOC * transitions. */ - error = wpi_auth(sc, vap); - if (error != 0) { + if ((error = wpi_auth(sc, vap)) != 0) { device_printf(sc->sc_dev, - "%s: could not move to auth state, error %d\n", + "%s: could not move to AUTH state, error %d\n", __func__, error); } - } - if (nstate == IEEE80211_S_RUN && vap->iv_state != IEEE80211_S_RUN) { - error = wpi_run(sc, vap); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not move to run state, error %d\n", - __func__, error); + break; + + case IEEE80211_S_RUN: + /* + * RUN -> RUN transition; Just restart the timers. + */ + if (vap->iv_state == IEEE80211_S_RUN) { + wpi_calib_timeout(sc); + break; } - } - if (nstate == IEEE80211_S_RUN) { - /* RUN -> RUN transition; just restart the timers */ - wpi_calib_timeout(sc); - /* XXX split out rate control timer */ + + /* + * !RUN -> RUN requires setting the association id + * which is done with a firmware cmd. We also defer + * starting the timers until that work is done. + */ + if ((error = wpi_run(sc, vap)) != 0) { + device_printf(sc->sc_dev, + "%s: could not move to RUN state\n", __func__); + } + break; + + default: + break; } WPI_UNLOCK(sc); IEEE80211_LOCK(ic); + if (error != 0) { + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); + return error; + } + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + return wvp->newstate(vap, nstate, arg); } -/* - * Grab exclusive access to NIC memory. - */ static void -wpi_mem_lock(struct wpi_softc *sc) +wpi_calib_timeout(void *arg) { - int ntries; - uint32_t tmp; + struct wpi_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - tmp = WPI_READ(sc, WPI_GPIO_CTL); - WPI_WRITE(sc, WPI_GPIO_CTL, tmp | WPI_GPIO_MAC); + if (vap->iv_state != IEEE80211_S_RUN) + return; - /* spin until we actually get the lock */ - for (ntries = 0; ntries < 100; ntries++) { - if ((WPI_READ(sc, WPI_GPIO_CTL) & - (WPI_GPIO_CLOCK | WPI_GPIO_SLEEP)) == WPI_GPIO_CLOCK) - break; - DELAY(10); + wpi_power_calibration(sc); + + callout_reset(&sc->calib_to, 60*hz, wpi_calib_timeout, sc); +} + +static __inline uint8_t +rate2plcp(const uint8_t rate) +{ + switch (rate) { + case 12: return 0xd; + case 18: return 0xf; + case 24: return 0x5; + case 36: return 0x7; + case 48: return 0x9; + case 72: return 0xb; + case 96: return 0x1; + case 108: return 0x3; + case 2: return 10; + case 4: return 20; + case 11: return 55; + case 22: return 110; + default: return 0; } - if (ntries == 100) - device_printf(sc->sc_dev, "could not lock memory\n"); } -/* - * Release lock on NIC memory. - */ -static void -wpi_mem_unlock(struct wpi_softc *sc) +static __inline uint8_t +plcp2rate(const uint8_t plcp) { - uint32_t tmp = WPI_READ(sc, WPI_GPIO_CTL); - WPI_WRITE(sc, WPI_GPIO_CTL, tmp & ~WPI_GPIO_MAC); -} - -static uint32_t -wpi_mem_read(struct wpi_softc *sc, uint16_t addr) -{ - WPI_WRITE(sc, WPI_READ_MEM_ADDR, WPI_MEM_4 | addr); - return WPI_READ(sc, WPI_READ_MEM_DATA); -} - -static void -wpi_mem_write(struct wpi_softc *sc, uint16_t addr, uint32_t data) -{ - WPI_WRITE(sc, WPI_WRITE_MEM_ADDR, WPI_MEM_4 | addr); - WPI_WRITE(sc, WPI_WRITE_MEM_DATA, data); -} - -static void -wpi_mem_write_region_4(struct wpi_softc *sc, uint16_t addr, - const uint32_t *data, int wlen) -{ - for (; wlen > 0; wlen--, data++, addr+=4) - wpi_mem_write(sc, addr, *data); -} - -/* - * Read data from the EEPROM. We access EEPROM through the MAC instead of - * using the traditional bit-bang method. Data is read up until len bytes have - * been obtained. - */ -static uint16_t -wpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int len) -{ - int ntries; - uint32_t val; - uint8_t *out = data; - - wpi_mem_lock(sc); - - for (; len > 0; len -= 2, addr++) { - WPI_WRITE(sc, WPI_EEPROM_CTL, addr << 2); - - for (ntries = 0; ntries < 10; ntries++) { - if ((val = WPI_READ(sc, WPI_EEPROM_CTL)) & WPI_EEPROM_READY) - break; - DELAY(5); - } - - if (ntries == 10) { - device_printf(sc->sc_dev, "could not read EEPROM\n"); - return ETIMEDOUT; - } - - *out++= val >> 16; - if (len > 1) - *out ++= val >> 24; + switch (plcp) { + case 0xd: return 12; + case 0xf: return 18; + case 0x5: return 24; + case 0x7: return 36; + case 0x9: return 48; + case 0xb: return 72; + case 0x1: return 96; + case 0x3: return 108; + case 10: return 2; + case 20: return 4; + case 55: return 11; + case 110: return 22; + default: return 0; } - - wpi_mem_unlock(sc); - - return 0; } -/* - * The firmware text and data segments are transferred to the NIC using DMA. - * The driver just copies the firmware into DMA-safe memory and tells the NIC - * where to find it. Once the NIC has copied the firmware into its internal - * memory, we can free our local copy in the driver. - */ -static int -wpi_load_microcode(struct wpi_softc *sc, const uint8_t *fw, int size) -{ - int error, ntries; - - DPRINTFN(WPI_DEBUG_HW,("Loading microcode size 0x%x\n", size)); - - size /= sizeof(uint32_t); - - wpi_mem_lock(sc); - - wpi_mem_write_region_4(sc, WPI_MEM_UCODE_BASE, - (const uint32_t *)fw, size); - - wpi_mem_write(sc, WPI_MEM_UCODE_SRC, 0); - wpi_mem_write(sc, WPI_MEM_UCODE_DST, WPI_FW_TEXT); - wpi_mem_write(sc, WPI_MEM_UCODE_SIZE, size); - - /* run microcode */ - wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_RUN); - - /* wait while the adapter is busy copying the firmware */ - for (error = 0, ntries = 0; ntries < 1000; ntries++) { - uint32_t status = WPI_READ(sc, WPI_TX_STATUS); - DPRINTFN(WPI_DEBUG_HW, - ("firmware status=0x%x, val=0x%x, result=0x%x\n", status, - WPI_TX_IDLE(6), status & WPI_TX_IDLE(6))); - if (status & WPI_TX_IDLE(6)) { - DPRINTFN(WPI_DEBUG_HW, - ("Status Match! - ntries = %d\n", ntries)); - break; - } - DELAY(10); - } - if (ntries == 1000) { - device_printf(sc->sc_dev, "timeout transferring firmware\n"); - error = ETIMEDOUT; - } - - /* start the microcode executing */ - wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_ENABLE); - - wpi_mem_unlock(sc); - - return (error); -} +/* Quickly determine if a given rate is CCK or OFDM. */ +#define WPI_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) static void -wpi_rx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc, - struct wpi_rx_data *data) +wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, + struct wpi_rx_data *data) { struct ifnet *ifp = sc->sc_ifp; + const struct ieee80211_cipher *cip = NULL; struct ieee80211com *ic = ifp->if_l2com; struct wpi_rx_ring *ring = &sc->rxq; struct wpi_rx_stat *stat; struct wpi_rx_head *head; struct wpi_rx_tail *tail; + struct ieee80211_frame *wh; struct ieee80211_node *ni; - struct mbuf *m, *mnew; + struct mbuf *m, *m1; bus_addr_t paddr; + uint32_t flags; + uint16_t len; int error; stat = (struct wpi_rx_stat *)(desc + 1); if (stat->len > WPI_STAT_MAXLEN) { - device_printf(sc->sc_dev, "invalid rx statistic header\n"); + device_printf(sc->sc_dev, "invalid RX statistic header\n"); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); head = (struct wpi_rx_head *)((caddr_t)(stat + 1) + stat->len); - tail = (struct wpi_rx_tail *)((caddr_t)(head + 1) + le16toh(head->len)); + len = le16toh(head->len); + tail = (struct wpi_rx_tail *)((caddr_t)(head + 1) + len); + flags = le32toh(tail->flags); - DPRINTFN(WPI_DEBUG_RX, ("rx intr: idx=%d len=%d stat len=%d rssi=%d " - "rate=%x chan=%d tstamp=%ju\n", ring->cur, le32toh(desc->len), - le16toh(head->len), (int8_t)stat->rssi, head->rate, head->chan, - (uintmax_t)le64toh(tail->tstamp))); + DPRINTF(sc, WPI_DEBUG_RECV, "%s: idx %d len %d stat len %u rssi %d" + " rate %x chan %d tstamp %ju\n", __func__, ring->cur, + le32toh(desc->len), len, (int8_t)stat->rssi, + head->plcp, head->chan, (uintmax_t)le64toh(tail->tstamp)); - /* discard Rx frames with bad CRC early */ - if ((le32toh(tail->flags) & WPI_RX_NOERROR) != WPI_RX_NOERROR) { - DPRINTFN(WPI_DEBUG_RX, ("%s: rx flags error %x\n", __func__, - le32toh(tail->flags))); + /* Discard frames with a bad FCS early. */ + if ((flags & WPI_RX_NOERROR) != WPI_RX_NOERROR) { + DPRINTF(sc, WPI_DEBUG_RECV, "%s: RX flags error %x\n", + __func__, flags); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } - if (le16toh(head->len) < sizeof (struct ieee80211_frame)) { - DPRINTFN(WPI_DEBUG_RX, ("%s: frame too short: %d\n", __func__, - le16toh(head->len))); + /* Discard frames that are too short. */ + if (len < sizeof (*wh)) { + DPRINTF(sc, WPI_DEBUG_RECV, "%s: frame too short: %d\n", + __func__, len); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } - /* XXX don't need mbuf, just dma buffer */ - mnew = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); - if (mnew == NULL) { - DPRINTFN(WPI_DEBUG_RX, ("%s: no mbuf to restock ring\n", - __func__)); + m1 = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); + if (m1 == NULL) { + DPRINTF(sc, WPI_DEBUG_ANY, "%s: no mbuf to restock ring\n", + __func__); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } bus_dmamap_unload(ring->data_dmat, data->map); - error = bus_dmamap_load(ring->data_dmat, data->map, - mtod(mnew, caddr_t), MJUMPAGESIZE, - wpi_dma_map_addr, &paddr, BUS_DMA_NOWAIT); + error = bus_dmamap_load(ring->data_dmat, data->map, mtod(m1, void *), + MJUMPAGESIZE, wpi_dma_map_addr, &paddr, BUS_DMA_NOWAIT); if (error != 0 && error != EFBIG) { device_printf(sc->sc_dev, "%s: bus_dmamap_load failed, error %d\n", __func__, error); - m_freem(mnew); + m_freem(m1); + + /* Try to reload the old mbuf. */ + error = bus_dmamap_load(ring->data_dmat, data->map, + mtod(data->m, void *), MJUMPAGESIZE, wpi_dma_map_addr, + &paddr, BUS_DMA_NOWAIT); + if (error != 0 && error != EFBIG) { + panic("%s: could not load old RX mbuf", __func__); + } + /* Physical address may have changed. */ + ring->desc[ring->cur] = htole32(paddr); + bus_dmamap_sync(ring->data_dmat, ring->desc_dma.map, + BUS_DMASYNC_PREWRITE); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } - bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); - /* finalize mbuf and swap in new one */ m = data->m; + data->m = m1; + /* Update RX descriptor. */ + ring->desc[ring->cur] = htole32(paddr); + bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, + BUS_DMASYNC_PREWRITE); + + /* Finalize mbuf. */ m->m_pkthdr.rcvif = ifp; m->m_data = (caddr_t)(head + 1); - m->m_pkthdr.len = m->m_len = le16toh(head->len); + m->m_pkthdr.len = m->m_len = len; - data->m = mnew; - /* update Rx descriptor */ - ring->desc[ring->cur] = htole32(paddr); + /* Grab a reference to the source node. */ + wh = mtod(m, struct ieee80211_frame *); + ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); + + if (ni != NULL) + cip = ni->ni_ucastkey.wk_cipher; + if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && + !IEEE80211_IS_MULTICAST(wh->i_addr1) && + cip != NULL && cip->ic_cipher == IEEE80211_CIPHER_AES_CCM) { + if ((flags & WPI_RX_CIPHER_MASK) != WPI_RX_CIPHER_CCMP) { + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + m_freem(m); + return; + } + /* Check whether decryption was successful or not. */ + if ((flags & WPI_RX_DECRYPT_MASK) != WPI_RX_DECRYPT_OK) { + DPRINTF(sc, WPI_DEBUG_RECV, + "CCMP decryption failed 0x%x\n", flags); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + m_freem(m); + return; + } + m->m_flags |= M_WEP; + } if (ieee80211_radiotap_active(ic)) { struct wpi_rx_radiotap_header *tap = &sc->sc_rxtap; tap->wr_flags = 0; - tap->wr_chan_freq = - htole16(ic->ic_channels[head->chan].ic_freq); - tap->wr_chan_flags = - htole16(ic->ic_channels[head->chan].ic_flags); + if (head->flags & htole16(WPI_STAT_FLAG_SHPREAMBLE)) + tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; tap->wr_dbm_antsignal = (int8_t)(stat->rssi - WPI_RSSI_OFFSET); tap->wr_dbm_antnoise = (int8_t)le16toh(stat->noise); tap->wr_tsft = tail->tstamp; tap->wr_antenna = (le16toh(head->flags) >> 4) & 0xf; - switch (head->rate) { - /* CCK rates */ - case 10: tap->wr_rate = 2; break; - case 20: tap->wr_rate = 4; break; - case 55: tap->wr_rate = 11; break; - case 110: tap->wr_rate = 22; break; - /* OFDM rates */ - case 0xd: tap->wr_rate = 12; break; - case 0xf: tap->wr_rate = 18; break; - case 0x5: tap->wr_rate = 24; break; - case 0x7: tap->wr_rate = 36; break; - case 0x9: tap->wr_rate = 48; break; - case 0xb: tap->wr_rate = 72; break; - case 0x1: tap->wr_rate = 96; break; - case 0x3: tap->wr_rate = 108; break; - /* unknown rate: should not happen */ - default: tap->wr_rate = 0; - } - if (le16toh(head->flags) & 0x4) - tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + tap->wr_rate = plcp2rate(head->plcp); } WPI_UNLOCK(sc); - ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); + /* Send the frame to the 802.11 layer. */ if (ni != NULL) { - (void) ieee80211_input(ni, m, stat->rssi, 0); + (void)ieee80211_input(ni, m, stat->rssi, -WPI_RSSI_OFFSET); + /* Node is no longer needed. */ ieee80211_free_node(ni); } else - (void) ieee80211_input_all(ic, m, stat->rssi, 0); + (void)ieee80211_input_all(ic, m, stat->rssi, -WPI_RSSI_OFFSET); WPI_LOCK(sc); } static void -wpi_tx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc) +wpi_rx_statistics(struct wpi_softc *sc, struct wpi_rx_desc *desc, + struct wpi_rx_data *data) { - struct ifnet *ifp = sc->sc_ifp; - struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; - struct wpi_tx_data *txdata = &ring->data[desc->idx]; - struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); - struct ieee80211_node *ni = txdata->ni; - struct ieee80211vap *vap = ni->ni_vap; - int retrycnt = 0; - - DPRINTFN(WPI_DEBUG_TX, ("tx done: qid=%d idx=%d retries=%d nkill=%d " - "rate=%x duration=%d status=%x\n", desc->qid, desc->idx, - stat->ntries, stat->nkill, stat->rate, le32toh(stat->duration), - le32toh(stat->status))); - - /* - * Update rate control statistics for the node. - * XXX we should not count mgmt frames since they're always sent at - * the lowest available bit-rate. - * XXX frames w/o ACK shouldn't be used either - */ - if (stat->ntries > 0) { - DPRINTFN(WPI_DEBUG_TX, ("%d retries\n", stat->ntries)); - retrycnt = 1; - } - ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, - &retrycnt, NULL); - - /* XXX oerrors should only count errors !maxtries */ - if ((le32toh(stat->status) & 0xff) != 1) - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - else - if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); - - bus_dmamap_sync(ring->data_dmat, txdata->map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(ring->data_dmat, txdata->map); - /* XXX handle M_TXCB? */ - m_freem(txdata->m); - txdata->m = NULL; - ieee80211_free_node(txdata->ni); - txdata->ni = NULL; - - ring->queued--; - - sc->sc_tx_timer = 0; - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - wpi_start_locked(ifp); + /* Ignore */ } static void -wpi_cmd_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc) +wpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) { - struct wpi_tx_ring *ring = &sc->cmdq; + struct ifnet *ifp = sc->sc_ifp; + struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; + struct wpi_tx_data *data = &ring->data[desc->idx]; + struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); + struct mbuf *m; + struct ieee80211_node *ni; + struct ieee80211vap *vap; + int status = le32toh(stat->status); + + KASSERT(data->ni != NULL, ("no node")); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + DPRINTF(sc, WPI_DEBUG_XMIT, "%s: " + "qid %d idx %d retries %d btkillcnt %d rate %x duration %d " + "status %x\n", __func__, desc->qid, desc->idx, stat->ackfailcnt, + stat->btkillcnt, stat->rate, le32toh(stat->duration), status); + + /* Unmap and free mbuf. */ + bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + m = data->m, data->m = NULL; + ni = data->ni, data->ni = NULL; + vap = ni->ni_vap; + + /* + * Update rate control statistics for the node. + */ + WPI_UNLOCK(sc); + if ((status & 0xff) != 1) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_FAILURE, &stat->ackfailcnt, NULL); + } else { + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, &stat->ackfailcnt, NULL); + } + + ieee80211_tx_complete(ni, m, (status & 0xff) != 1); + WPI_LOCK(sc); + + sc->sc_tx_timer = 0; + if (--ring->queued < WPI_TX_RING_LOMARK) { + sc->qfullmsk &= ~(1 << ring->qid); + if (sc->qfullmsk == 0 && + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + wpi_start_locked(ifp); + } + } + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); +} + +/* + * Process a "command done" firmware notification. This is where we wakeup + * processes waiting for a synchronous command completion. + */ +static void +wpi_cmd_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) +{ + struct wpi_tx_ring *ring = &sc->txq[4]; struct wpi_tx_data *data; - DPRINTFN(WPI_DEBUG_CMD, ("cmd notification qid=%x idx=%d flags=%x " - "type=%s len=%d\n", desc->qid, desc->idx, - desc->flags, wpi_cmd_str(desc->type), - le32toh(desc->len))); + DPRINTF(sc, WPI_DEBUG_CMD, "cmd notification qid=%x idx=%d flags=%x " + "type=%s len=%d\n", desc->qid, desc->idx, + desc->flags, wpi_cmd_str(desc->type), + le32toh(desc->len)); if ((desc->qid & 7) != 4) - return; /* not a command ack */ + return; /* Not a command ack. */ data = &ring->data[desc->idx]; - /* if the command was mapped in a mbuf, free it */ + /* If the command was mapped in an mbuf, free it. */ if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; @@ -1647,374 +1922,710 @@ wpi_notif_intr(struct wpi_softc *sc) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct wpi_rx_desc *desc; - struct wpi_rx_data *data; - uint32_t hw; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + int hw; bus_dmamap_sync(sc->shared_dma.tag, sc->shared_dma.map, BUS_DMASYNC_POSTREAD); hw = le32toh(sc->shared->next); - while (sc->rxq.cur != hw) { - data = &sc->rxq.data[sc->rxq.cur]; + hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1; + + if (sc->rxq.cur == hw) + return; + + do { + sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT; + + struct wpi_rx_data *data = &sc->rxq.data[sc->rxq.cur]; + struct wpi_rx_desc *desc; bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); - desc = (void *)data->m->m_ext.ext_buf; + desc = mtod(data->m, struct wpi_rx_desc *); - DPRINTFN(WPI_DEBUG_NOTIFY, - ("notify qid=%x idx=%d flags=%x type=%d len=%d\n", - desc->qid, - desc->idx, - desc->flags, - desc->type, - le32toh(desc->len))); + DPRINTF(sc, WPI_DEBUG_NOTIFY, + "%s: cur=%d; qid %x idx %d flags %x type %d(%s) len %d\n", + __func__, sc->rxq.cur, desc->qid, desc->idx, desc->flags, + desc->type, wpi_cmd_str(desc->type), le32toh(desc->len)); - if (!(desc->qid & 0x80)) /* reply to a command */ - wpi_cmd_intr(sc, desc); + if (!(desc->qid & 0x80)) /* Reply to a command. */ + wpi_cmd_done(sc, desc); switch (desc->type) { case WPI_RX_DONE: - /* a 802.11 frame was received */ - wpi_rx_intr(sc, desc, data); + /* An 802.11 frame has been received. */ + wpi_rx_done(sc, desc, data); break; case WPI_TX_DONE: - /* a 802.11 frame has been transmitted */ - wpi_tx_intr(sc, desc); + /* An 802.11 frame has been transmitted. */ + wpi_tx_done(sc, desc); break; + case WPI_RX_STATISTICS: + case WPI_BEACON_STATISTICS: + wpi_rx_statistics(sc, desc, data); + break; + + case WPI_BEACON_MISSED: + { + struct wpi_beacon_missed *miss = + (struct wpi_beacon_missed *)(desc + 1); + int misses; + + bus_dmamap_sync(sc->rxq.data_dmat, data->map, + BUS_DMASYNC_POSTREAD); + misses = le32toh(miss->consecutive); + + DPRINTF(sc, WPI_DEBUG_STATE, + "%s: beacons missed %d/%d\n", __func__, misses, + le32toh(miss->total)); + + if (vap->iv_state == IEEE80211_S_RUN && + (ic->ic_flags & IEEE80211_S_SCAN) == 0) { + if (misses >= vap->iv_bmissthreshold) { + WPI_UNLOCK(sc); + ieee80211_beacon_miss(ic); + WPI_LOCK(sc); + } + } + break; + } case WPI_UC_READY: { struct wpi_ucode_info *uc = - (struct wpi_ucode_info *)(desc + 1); + (struct wpi_ucode_info *)(desc + 1); - /* the microcontroller is ready */ - DPRINTF(("microcode alive notification version %x " - "alive %x\n", le32toh(uc->version), - le32toh(uc->valid))); + /* The microcontroller is ready. */ + bus_dmamap_sync(sc->rxq.data_dmat, data->map, + BUS_DMASYNC_POSTREAD); + DPRINTF(sc, WPI_DEBUG_RESET, + "microcode alive notification version=%d.%d " + "subtype=%x alive=%x\n", uc->major, uc->minor, + uc->subtype, le32toh(uc->valid)); if (le32toh(uc->valid) != 1) { device_printf(sc->sc_dev, "microcontroller initialization failed\n"); wpi_stop_locked(sc); } + /* Save the address of the error log in SRAM. */ + sc->errptr = le32toh(uc->errptr); break; } case WPI_STATE_CHANGED: { + bus_dmamap_sync(sc->rxq.data_dmat, data->map, + BUS_DMASYNC_POSTREAD); + uint32_t *status = (uint32_t *)(desc + 1); - - /* enabled/disabled notification */ - DPRINTF(("state changed to %x\n", le32toh(*status))); - +#ifdef WPI_DEBUG + DPRINTF(sc, WPI_DEBUG_STATE, "state changed to %x\n", + le32toh(*status)); +#endif if (le32toh(*status) & 1) { - device_printf(sc->sc_dev, - "Radio transmitter is switched off\n"); - sc->flags |= WPI_FLAG_HW_RADIO_OFF; - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - /* Disable firmware commands */ - WPI_WRITE(sc, WPI_UCODE_SET, WPI_DISABLE_CMD); + ieee80211_runtask(ic, &sc->sc_radiooff_task); + return; } break; } case WPI_START_SCAN: { + bus_dmamap_sync(sc->rxq.data_dmat, data->map, + BUS_DMASYNC_POSTREAD); #ifdef WPI_DEBUG struct wpi_start_scan *scan = - (struct wpi_start_scan *)(desc + 1); + (struct wpi_start_scan *)(desc + 1); + DPRINTF(sc, WPI_DEBUG_SCAN, + "%s: scanning channel %d status %x\n", + __func__, scan->chan, le32toh(scan->status)); #endif - - DPRINTFN(WPI_DEBUG_SCANNING, - ("scanning channel %d status %x\n", - scan->chan, le32toh(scan->status))); break; } case WPI_STOP_SCAN: { + bus_dmamap_sync(sc->rxq.data_dmat, data->map, + BUS_DMASYNC_POSTREAD); #ifdef WPI_DEBUG struct wpi_stop_scan *scan = - (struct wpi_stop_scan *)(desc + 1); + (struct wpi_stop_scan *)(desc + 1); + DPRINTF(sc, WPI_DEBUG_SCAN, + "scan finished nchan=%d status=%d chan=%d\n", + scan->nchan, scan->status, scan->chan); #endif - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - DPRINTFN(WPI_DEBUG_SCANNING, - ("scan finished nchan=%d status=%d chan=%d\n", - scan->nchan, scan->status, scan->chan)); - sc->sc_scan_timer = 0; + WPI_UNLOCK(sc); ieee80211_scan_next(vap); - break; - } - case WPI_MISSED_BEACON: - { - struct wpi_missed_beacon *beacon = - (struct wpi_missed_beacon *)(desc + 1); - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - if (le32toh(beacon->consecutive) >= - vap->iv_bmissthreshold) { - DPRINTF(("Beacon miss: %u >= %u\n", - le32toh(beacon->consecutive), - vap->iv_bmissthreshold)); - ieee80211_beacon_miss(ic); - } + WPI_LOCK(sc); break; } } + } while (sc->rxq.cur != hw); - sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT; + /* Tell the firmware what we have processed. */ + wpi_update_rx_ring(sc); +} + +/* + * Process an INT_WAKEUP interrupt raised when the microcontroller wakes up + * from power-down sleep mode. + */ +static void +wpi_wakeup_intr(struct wpi_softc *sc) +{ + int qid; + + DPRINTF(sc, WPI_DEBUG_PWRSAVE, + "%s: ucode wakeup from power-down sleep\n", __func__); + + /* Wakeup RX and TX rings. */ + if (sc->rxq.update) { + wpi_update_rx_ring(sc); + sc->rxq.update = 0; + } + for (qid = 0; qid < WPI_NTXQUEUES; qid++) { + struct wpi_tx_ring *ring = &sc->txq[qid]; + + if (ring->update) { + wpi_update_tx_ring(sc, ring); + ring->update = 0; + } } - /* tell the firmware what we have processed */ - hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1; - WPI_WRITE(sc, WPI_RX_WIDX, hw & ~7); + WPI_CLRBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); +} + +/* + * Dump the error log of the firmware when a firmware panic occurs. Although + * we can't debug the firmware because it is neither open source nor free, it + * can help us to identify certain classes of problems. + */ +static void +wpi_fatal_intr(struct wpi_softc *sc) +{ + struct wpi_fw_dump dump; + uint32_t i, offset, count; + const uint32_t size_errmsg = + (sizeof (wpi_fw_errmsg) / sizeof ((wpi_fw_errmsg)[0])); + + /* Check that the error log address is valid. */ + if (sc->errptr < WPI_FW_DATA_BASE || + sc->errptr + sizeof (dump) > + WPI_FW_DATA_BASE + WPI_FW_DATA_MAXSZ) { + printf("%s: bad firmware error log address 0x%08x\n", __func__, + sc->errptr); + return; + } + if (wpi_nic_lock(sc) != 0) { + printf("%s: could not read firmware error log\n", __func__); + return; + } + /* Read number of entries in the log. */ + count = wpi_mem_read(sc, sc->errptr); + if (count == 0 || count * sizeof (dump) > WPI_FW_DATA_MAXSZ) { + printf("%s: invalid count field (count = %u)\n", __func__, + count); + wpi_nic_unlock(sc); + return; + } + /* Skip "count" field. */ + offset = sc->errptr + sizeof (uint32_t); + printf("firmware error log (count = %u):\n", count); + for (i = 0; i < count; i++) { + wpi_mem_read_region_4(sc, offset, (uint32_t *)&dump, + sizeof (dump) / sizeof (uint32_t)); + + printf(" error type = \"%s\" (0x%08X)\n", + (dump.desc < size_errmsg) ? + wpi_fw_errmsg[dump.desc] : "UNKNOWN", + dump.desc); + printf(" error data = 0x%08X\n", + dump.data); + printf(" branch link = 0x%08X%08X\n", + dump.blink[0], dump.blink[1]); + printf(" interrupt link = 0x%08X%08X\n", + dump.ilink[0], dump.ilink[1]); + printf(" time = %u\n", dump.time); + + offset += sizeof (dump); + } + wpi_nic_unlock(sc); + /* Dump driver status (TX and RX rings) while we're here. */ + printf("driver status:\n"); + for (i = 0; i < WPI_NTXQUEUES; i++) { + struct wpi_tx_ring *ring = &sc->txq[i]; + printf(" tx ring %2d: qid=%-2d cur=%-3d queued=%-3d\n", + i, ring->qid, ring->cur, ring->queued); + } + printf(" rx ring: cur=%d\n", sc->rxq.cur); } static void wpi_intr(void *arg) { struct wpi_softc *sc = arg; - uint32_t r; + struct ifnet *ifp = sc->sc_ifp; + uint32_t r1, r2; WPI_LOCK(sc); - r = WPI_READ(sc, WPI_INTR); - if (r == 0 || r == 0xffffffff) { + /* Disable interrupts. */ + WPI_WRITE(sc, WPI_INT_MASK, 0); + + r1 = WPI_READ(sc, WPI_INT); + + if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) { WPI_UNLOCK(sc); - return; + return; /* Hardware gone! */ } - /* disable interrupts */ - WPI_WRITE(sc, WPI_MASK, 0); - /* ack interrupts */ - WPI_WRITE(sc, WPI_INTR, r); + r2 = WPI_READ(sc, WPI_FH_INT); - if (r & (WPI_SW_ERROR | WPI_HW_ERROR)) { - struct ifnet *ifp = sc->sc_ifp; + DPRINTF(sc, WPI_DEBUG_INTR, "%s: reg1=0x%08x reg2=0x%08x\n", __func__, + r1, r2); + + if (r1 == 0 && r2 == 0) + goto done; /* Interrupt not for us. */ + + /* Acknowledge interrupts. */ + WPI_WRITE(sc, WPI_INT, r1); + WPI_WRITE(sc, WPI_FH_INT, r2); + + if (r1 & (WPI_INT_SW_ERR | WPI_INT_HW_ERR)) { struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); device_printf(sc->sc_dev, "fatal firmware error\n"); - DPRINTFN(6,("(%s)\n", (r & WPI_SW_ERROR) ? "(Software Error)" : - "(Hardware Error)")); - if (vap != NULL) - ieee80211_cancel_scan(vap); - ieee80211_runtask(ic, &sc->sc_restarttask); + wpi_fatal_intr(sc); + DPRINTF(sc, WPI_DEBUG_HW, + "(%s)\n", (r1 & WPI_INT_SW_ERR) ? "(Software Error)" : + "(Hardware Error)"); + ieee80211_runtask(ic, &sc->sc_reinittask); sc->flags &= ~WPI_FLAG_BUSY; WPI_UNLOCK(sc); return; } - if (r & WPI_RX_INTR) + if ((r1 & (WPI_INT_FH_RX | WPI_INT_SW_RX)) || + (r2 & WPI_FH_INT_RX)) wpi_notif_intr(sc); - if (r & WPI_ALIVE_INTR) /* firmware initialized */ - wakeup(sc); + if (r1 & WPI_INT_ALIVE) + wakeup(sc); /* Firmware is alive. */ - /* re-enable interrupts */ - if (sc->sc_ifp->if_flags & IFF_UP) - WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK); + if (r1 & WPI_INT_WAKEUP) + wpi_wakeup_intr(sc); + +done: + /* Re-enable interrupts. */ + if (ifp->if_flags & IFF_UP) + WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); WPI_UNLOCK(sc); } -static uint8_t -wpi_plcp_signal(int rate) -{ - switch (rate) { - /* CCK rates (returned values are device-dependent) */ - case 2: return 10; - case 4: return 20; - case 11: return 55; - case 22: return 110; - - /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ - /* R1-R4 (ral/ural is R4-R1) */ - case 12: return 0xd; - case 18: return 0xf; - case 24: return 0x5; - case 36: return 0x7; - case 48: return 0x9; - case 72: return 0xb; - case 96: return 0x1; - case 108: return 0x3; - - /* unsupported rates (should not get there) */ - default: return 0; - } -} - -/* quickly determine if a given rate is CCK or OFDM */ -#define WPI_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) - -/* - * Construct the data packet for a transmit buffer and acutally put - * the buffer onto the transmit ring, kicking the card to process the - * the buffer. - */ static int -wpi_tx_data(struct wpi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, - int ac) +wpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) { - struct ieee80211vap *vap = ni->ni_vap; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams; - struct wpi_tx_ring *ring = &sc->txq[ac]; - struct wpi_tx_desc *desc; - struct wpi_tx_data *data; - struct wpi_tx_cmd *cmd; - struct wpi_cmd_data *tx; struct ieee80211_frame *wh; - const struct ieee80211_txparam *tp; - struct ieee80211_key *k; - struct mbuf *mnew; - int i, error, nsegs, rate, hdrlen, ismcast; - bus_dma_segment_t segs[WPI_MAX_SCATTER]; + struct wpi_tx_cmd *cmd; + struct wpi_tx_data *data; + struct wpi_tx_desc *desc; + struct wpi_tx_ring *ring; + struct mbuf *m1; + bus_dma_segment_t *seg, segs[WPI_MAX_SCATTER]; + u_int hdrlen; + int error, i, nsegs, pad, totlen; + WPI_LOCK_ASSERT(sc); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + wh = mtod(buf->m, struct ieee80211_frame *); + hdrlen = ieee80211_anyhdrsize(wh); + totlen = buf->m->m_pkthdr.len; + + if (hdrlen & 3) { + /* First segment length must be a multiple of 4. */ + pad = 4 - (hdrlen & 3); + } else + pad = 0; + + ring = &sc->txq[buf->ac]; desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; - wh = mtod(m0, struct ieee80211_frame *); - - hdrlen = ieee80211_hdrsize(wh); - ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); - - if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { - k = ieee80211_crypto_encap(ni, m0); - if (k == NULL) { - m_freem(m0); - return ENOBUFS; - } - /* packet header may have moved, reset our local pointer */ - wh = mtod(m0, struct ieee80211_frame *); - } - + /* Prepare TX firmware command. */ cmd = &ring->cmd[ring->cur]; - cmd->code = WPI_CMD_TX_DATA; + cmd->code = buf->code; cmd->flags = 0; cmd->qid = ring->qid; cmd->idx = ring->cur; - tx = (struct wpi_cmd_data *)cmd->data; - tx->flags = htole32(WPI_TX_AUTO_SEQ); - tx->timeout = htole16(0); - tx->ofdm_mask = 0xff; - tx->cck_mask = 0x0f; - tx->lifetime = htole32(WPI_LIFETIME_INFINITE); - tx->id = ismcast ? WPI_ID_BROADCAST : WPI_ID_BSS; - tx->len = htole16(m0->m_pkthdr.len); + memcpy(cmd->data, buf->data, buf->size); - if (!ismcast) { - if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0 || - !cap->cap_wmeParams[ac].wmep_noackPolicy) - tx->flags |= htole32(WPI_TX_NEED_ACK); - if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) { - tx->flags |= htole32(WPI_TX_NEED_RTS|WPI_TX_FULL_TXOP); - tx->rts_ntries = 7; - } - } - /* pick a rate */ - tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; - if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) { - uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; - /* tell h/w to set timestamp in probe responses */ - if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) - tx->flags |= htole32(WPI_TX_INSERT_TSTAMP); - if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || - subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) - tx->timeout = htole16(3); - else - tx->timeout = htole16(2); - rate = tp->mgmtrate; - } else if (ismcast) { - rate = tp->mcastrate; - } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { - rate = tp->ucastrate; - } else { - (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; - } - tx->rate = wpi_plcp_signal(rate); + /* Save and trim IEEE802.11 header. */ + memcpy((uint8_t *)(cmd->data + buf->size), wh, hdrlen); + m_adj(buf->m, hdrlen); - /* be very persistant at sending frames out */ -#if 0 - tx->data_ntries = tp->maxretry; -#else - tx->data_ntries = 15; /* XXX way too high */ -#endif - - if (ieee80211_radiotap_active_vap(vap)) { - struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; - tap->wt_flags = 0; - tap->wt_rate = rate; - tap->wt_hwqueue = ac; - if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) - tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; - - ieee80211_radiotap_tx(vap, m0); - } - - /* save and trim IEEE802.11 header */ - m_copydata(m0, 0, hdrlen, (caddr_t)&tx->wh); - m_adj(m0, hdrlen); - - error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m0, segs, - &nsegs, BUS_DMA_NOWAIT); + error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, buf->m, + segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0 && error != EFBIG) { - device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", - error); - m_freem(m0); + device_printf(sc->sc_dev, + "%s: can't map mbuf (error %d)\n", __func__, error); + m_freem(buf->m); return error; } if (error != 0) { - /* XXX use m_collapse */ - mnew = m_defrag(m0, M_NOWAIT); - if (mnew == NULL) { + /* Too many DMA segments, linearize mbuf. */ + m1 = m_collapse(buf->m, M_NOWAIT, WPI_MAX_SCATTER); + if (m1 == NULL) { device_printf(sc->sc_dev, - "could not defragment mbuf\n"); - m_freem(m0); + "%s: could not defrag mbuf\n", __func__); + m_freem(buf->m); return ENOBUFS; } - m0 = mnew; + buf->m = m1; error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, - m0, segs, &nsegs, BUS_DMA_NOWAIT); + buf->m, segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { device_printf(sc->sc_dev, - "could not map mbuf (error %d)\n", error); - m_freem(m0); + "%s: can't map mbuf (error %d)\n", __func__, error); + m_freem(buf->m); return error; } } - data->m = m0; - data->ni = ni; + data->m = buf->m; + data->ni = buf->ni; - DPRINTFN(WPI_DEBUG_TX, ("sending data: qid=%d idx=%d len=%d nsegs=%d\n", - ring->qid, ring->cur, m0->m_pkthdr.len, nsegs)); + DPRINTF(sc, WPI_DEBUG_XMIT, "%s: qid %d idx %d len %d nsegs %d\n", + __func__, ring->qid, ring->cur, totlen, nsegs); - /* first scatter/gather segment is used by the tx data command */ - desc->flags = htole32(WPI_PAD32(m0->m_pkthdr.len) << 28 | - (1 + nsegs) << 24); - desc->segs[0].addr = htole32(ring->cmd_dma.paddr + - ring->cur * sizeof (struct wpi_tx_cmd)); - desc->segs[0].len = htole32(4 + sizeof (struct wpi_cmd_data)); + /* Fill TX descriptor. */ + desc->nsegs = WPI_PAD32(totlen + pad) << 4 | (1 + nsegs); + /* First DMA segment is used by the TX command. */ + desc->segs[0].addr = htole32(data->cmd_paddr); + desc->segs[0].len = htole32(4 + buf->size + hdrlen + pad); + /* Other DMA segments are for data payload. */ + seg = &segs[0]; for (i = 1; i <= nsegs; i++) { - desc->segs[i].addr = htole32(segs[i - 1].ds_addr); - desc->segs[i].len = htole32(segs[i - 1].ds_len); + desc->segs[i].addr = htole32(seg->ds_addr); + desc->segs[i].len = htole32(seg->ds_len); + seg++; } bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(ring->data_dmat, ring->cmd_dma.map, + BUS_DMASYNC_PREWRITE); bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); - ring->queued++; - - /* kick ring */ + /* Kick TX ring. */ ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; - WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); + wpi_update_tx_ring(sc, ring); + + /* Mark TX ring as full if we reach a certain threshold. */ + if (++ring->queued > WPI_TX_RING_HIMARK) + sc->qfullmsk |= 1 << ring->qid; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return 0; +} + +/* + * Construct the data packet for a transmit buffer. + */ +static int +wpi_tx_data(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni) +{ + const struct ieee80211_txparam *tp; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + struct wpi_node *wn = (void *)ni; + struct ieee80211_channel *chan; + struct ieee80211_frame *wh; + struct ieee80211_key *k = NULL; + struct wpi_cmd_data tx; + struct wpi_buf tx_data; + uint32_t flags; + uint16_t qos; + uint8_t tid, type; + int ac, error, rate, ismcast, totlen; + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + + /* Select EDCA Access Category and TX ring for this frame. */ + if (IEEE80211_QOS_HAS_SEQ(wh)) { + qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; + tid = qos & IEEE80211_QOS_TID; + } else { + qos = 0; + tid = 0; + } + ac = M_WME_GETAC(m); + + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? + ni->ni_chan : ic->ic_curchan; + tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; + + /* Choose a TX rate index. */ + if (type == IEEE80211_FC0_TYPE_MGT) + rate = tp->mgmtrate; + else if (ismcast) + rate = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) + rate = tp->ucastrate; + else if (m->m_flags & M_EAPOL) + rate = tp->mgmtrate; + else { + /* XXX pass pktlen */ + (void) ieee80211_ratectl_rate(ni, NULL, 0); + rate = ni->ni_txrate; + } + + /* Encrypt the frame if need be. */ + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + /* Retrieve key for TX. */ + k = ieee80211_crypto_encap(ni, m); + if (k == NULL) { + error = ENOBUFS; + goto fail; + } + /* 802.11 header may have moved. */ + wh = mtod(m, struct ieee80211_frame *); + } + totlen = m->m_pkthdr.len; + + if (ieee80211_radiotap_active_vap(vap)) { + struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; + + tap->wt_flags = 0; + tap->wt_rate = rate; + if (k != NULL) + tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; + + ieee80211_radiotap_tx(vap, m); + } + + flags = 0; + if (!ismcast) { + /* Unicast frame, check if an ACK is expected. */ + if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != + IEEE80211_QOS_ACKPOLICY_NOACK) + flags |= WPI_TX_NEED_ACK; + } + + /* Check if frame must be protected using RTS/CTS or CTS-to-self. */ + if (!ismcast) { + /* NB: Group frames are sent using CCK in 802.11b/g. */ + if (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) { + flags |= WPI_TX_NEED_RTS; + } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && + WPI_RATE_IS_OFDM(rate)) { + if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) + flags |= WPI_TX_NEED_CTS; + else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) + flags |= WPI_TX_NEED_RTS; + } + + if (flags & (WPI_TX_NEED_RTS | WPI_TX_NEED_CTS)) + flags |= WPI_TX_FULL_TXOP; + } + + memset(&tx, 0, sizeof (struct wpi_cmd_data)); + if (type == IEEE80211_FC0_TYPE_MGT) { + uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + /* Tell HW to set timestamp in probe responses. */ + if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) + flags |= WPI_TX_INSERT_TSTAMP; + if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || + subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) + tx.timeout = htole16(3); + else + tx.timeout = htole16(2); + } + + if (ismcast || type != IEEE80211_FC0_TYPE_DATA) + tx.id = WPI_ID_BROADCAST; + else { + if (wn->id == WPI_ID_UNDEFINED && + (vap->iv_opmode == IEEE80211_M_IBSS || + vap->iv_opmode == IEEE80211_M_AHDEMO)) { + error = wpi_add_ibss_node(sc, ni); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not add IBSS node, error %d\n", + __func__, error); + goto fail; + } + } + + if (wn->id == WPI_ID_UNDEFINED) { + device_printf(sc->sc_dev, + "%s: undefined node id\n", __func__); + error = EINVAL; + goto fail; + } + + tx.id = wn->id; + } + + if (type != IEEE80211_FC0_TYPE_MGT) + tx.data_ntries = tp->maxretry; + + tx.len = htole16(totlen); + tx.flags = htole32(flags); + tx.plcp = rate2plcp(rate); + tx.tid = tid; + tx.lifetime = htole32(WPI_LIFETIME_INFINITE); + tx.ofdm_mask = 0xff; + tx.cck_mask = 0x0f; + tx.rts_ntries = 7; + + if (k != NULL && k->wk_cipher->ic_cipher == IEEE80211_CIPHER_AES_CCM) { + if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { + tx.security = WPI_CIPHER_CCMP; + memcpy(tx.key, k->wk_key, k->wk_keylen); + } + } + + tx_data.data = &tx; + tx_data.ni = ni; + tx_data.m = m; + tx_data.size = sizeof(tx); + tx_data.code = WPI_CMD_TX_DATA; + tx_data.ac = ac; + + return wpi_cmd2(sc, &tx_data); + +fail: m_freem(m); + return error; +} + +static int +wpi_tx_data_raw(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_frame *wh; + struct wpi_cmd_data tx; + struct wpi_buf tx_data; + uint32_t flags; + uint8_t type; + int ac, rate, totlen; + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + totlen = m->m_pkthdr.len; + + ac = params->ibp_pri & 3; + + /* Choose a TX rate index. */ + rate = params->ibp_rate0; + + flags = 0; + if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) + flags |= WPI_TX_NEED_ACK; + if (params->ibp_flags & IEEE80211_BPF_RTS) + flags |= WPI_TX_NEED_RTS; + if (params->ibp_flags & IEEE80211_BPF_CTS) + flags |= WPI_TX_NEED_CTS; + if (flags & (WPI_TX_NEED_RTS | WPI_TX_NEED_CTS)) + flags |= WPI_TX_FULL_TXOP; + + if (ieee80211_radiotap_active_vap(vap)) { + struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; + + tap->wt_flags = 0; + tap->wt_rate = rate; + + ieee80211_radiotap_tx(vap, m); + } + + memset(&tx, 0, sizeof (struct wpi_cmd_data)); + if (type == IEEE80211_FC0_TYPE_MGT) { + uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + /* Tell HW to set timestamp in probe responses. */ + if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) + flags |= WPI_TX_INSERT_TSTAMP; + if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || + subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) + tx.timeout = htole16(3); + else + tx.timeout = htole16(2); + } + + tx.len = htole16(totlen); + tx.flags = htole32(flags); + tx.plcp = rate2plcp(rate); + tx.id = WPI_ID_BROADCAST; + tx.lifetime = htole32(WPI_LIFETIME_INFINITE); + tx.rts_ntries = params->ibp_try1; + tx.data_ntries = params->ibp_try0; + + tx_data.data = &tx; + tx_data.ni = ni; + tx_data.m = m; + tx_data.size = sizeof(tx); + tx_data.code = WPI_CMD_TX_DATA; + tx_data.ac = ac; + + return wpi_cmd2(sc, &tx_data); +} + +static int +wpi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; + int error = 0; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + ieee80211_free_node(ni); + m_freem(m); + return ENETDOWN; + } + + WPI_LOCK(sc); + if (params == NULL) { + /* + * Legacy path; interpret frame contents to decide + * precisely how to send the frame. + */ + error = wpi_tx_data(sc, m, ni); + } else { + /* + * Caller supplied explicit parameters to use in + * sending the frame. + */ + error = wpi_tx_data_raw(sc, m, ni, params); + } + WPI_UNLOCK(sc); + + if (error != 0) { + /* NB: m is reclaimed on tx failure */ + ieee80211_free_node(ni); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); + + return error; + } + + sc->sc_tx_timer = 5; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); return 0; } @@ -2038,72 +2649,86 @@ wpi_start_locked(struct ifnet *ifp) struct wpi_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m; - int ac; WPI_LOCK_ASSERT(sc); - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || + (ifp->if_drv_flags & IFF_DRV_OACTIVE)) return; for (;;) { - IFQ_DRV_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) - break; - ac = M_WME_GETAC(m); - if (sc->txq[ac].queued > sc->txq[ac].count - 8) { - /* there is no place left in this ring */ - IFQ_DRV_PREPEND(&ifp->if_snd, m); + if (sc->qfullmsk != 0) { ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } - ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; - if (wpi_tx_data(sc, m, ni, ac) != 0) { - ieee80211_free_node(ni); - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) break; - } - sc->sc_tx_timer = 5; + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + if (wpi_tx_data(sc, m, ni) != 0) { + WPI_UNLOCK(sc); + ieee80211_free_node(ni); + WPI_LOCK(sc); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + } else + sc->sc_tx_timer = 5; } + + DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); } -static int -wpi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, - const struct ieee80211_bpf_params *params) +static void +wpi_watchdog_rfkill(void *arg) { - struct ieee80211com *ic = ni->ni_ic; - struct ifnet *ifp = ic->ic_ifp; - struct wpi_softc *sc = ifp->if_softc; + struct wpi_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; - /* prevent management frames from being sent if we're not ready */ - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - m_freem(m); - ieee80211_free_node(ni); - return ENETDOWN; - } - WPI_LOCK(sc); + DPRINTF(sc, WPI_DEBUG_WATCHDOG, "RFkill Watchdog: tick\n"); - /* management frames go into ring 0 */ - if (sc->txq[0].queued > sc->txq[0].count - 8) { - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - m_freem(m); - WPI_UNLOCK(sc); - ieee80211_free_node(ni); - return ENOBUFS; /* XXX */ + /* No need to lock firmware memory. */ + if ((wpi_prph_read(sc, WPI_APMG_RFKILL) & 0x1) == 0) { + /* Radio kill switch is still off. */ + callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, + sc); + } else + ieee80211_runtask(ic, &sc->sc_radioon_task); +} + +/** + * Called every second, wpi_watchdog used by the watch dog timer + * to check that the card is still alive + */ +static void +wpi_watchdog(void *arg) +{ + struct wpi_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + DPRINTF(sc, WPI_DEBUG_WATCHDOG, "Watchdog: tick\n"); + + if (sc->sc_tx_timer > 0) { + if (--sc->sc_tx_timer == 0) { + if_printf(ifp, "device timeout\n"); + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + ieee80211_runtask(ic, &sc->sc_reinittask); + } } - if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); - if (wpi_tx_data(sc, m, ni, 0) != 0) - goto bad; - sc->sc_tx_timer = 5; - callout_reset(&sc->watchdog_to, hz, wpi_watchdog, sc); + if (sc->sc_scan_timer > 0) { + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + if (--sc->sc_scan_timer == 0 && vap != NULL) { + if_printf(ifp, "scan timeout\n"); + ieee80211_cancel_scan(vap); + ieee80211_runtask(ic, &sc->sc_reinittask); + } + } - WPI_UNLOCK(sc); - return 0; -bad: - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - WPI_UNLOCK(sc); - ieee80211_free_node(ni); - return EIO; /* XXX */ + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + callout_reset(&sc->watchdog_to, hz, wpi_watchdog, sc); } static int @@ -2111,30 +2736,36 @@ wpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct wpi_softc *sc = ifp->if_softc; struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ifreq *ifr = (struct ifreq *) data; - int error = 0, startall = 0; + int error = 0, startall = 0, stop = 0; switch (cmd) { + case SIOCGIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; case SIOCSIFFLAGS: WPI_LOCK(sc); - if ((ifp->if_flags & IFF_UP)) { + if (ifp->if_flags & IFF_UP) { if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - wpi_init_locked(sc, 0); - startall = 1; + wpi_init_locked(sc); + if (WPI_READ(sc, WPI_GP_CNTRL) & + WPI_GP_CNTRL_RFKILL) + startall = 1; + else + stop = 1; } - } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) || - (sc->flags & WPI_FLAG_HW_RADIO_OFF)) + } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) wpi_stop_locked(sc); WPI_UNLOCK(sc); if (startall) ieee80211_start_all(ic); + else if (vap != NULL && stop) + ieee80211_stop(vap); break; case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); break; - case SIOCGIFADDR: - error = ether_ioctl(ifp, cmd, data); - break; default: error = EINVAL; break; @@ -2142,65 +2773,59 @@ wpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return error; } -/* - * Extract various information from EEPROM. - */ -static void -wpi_read_eeprom(struct wpi_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) -{ - int i; - - /* read the hardware capabilities, revision and SKU type */ - wpi_read_prom_data(sc, WPI_EEPROM_CAPABILITIES, &sc->cap,1); - wpi_read_prom_data(sc, WPI_EEPROM_REVISION, &sc->rev,2); - wpi_read_prom_data(sc, WPI_EEPROM_TYPE, &sc->type, 1); - - /* read the regulatory domain */ - wpi_read_prom_data(sc, WPI_EEPROM_DOMAIN, sc->domain, 4); - - /* read in the hw MAC address */ - wpi_read_prom_data(sc, WPI_EEPROM_MAC, macaddr, 6); - - /* read the list of authorized channels */ - for (i = 0; i < WPI_CHAN_BANDS_COUNT; i++) - wpi_read_eeprom_channels(sc,i); - - /* read the power level calibration info for each group */ - for (i = 0; i < WPI_POWER_GROUPS_COUNT; i++) - wpi_read_eeprom_group(sc,i); -} - /* * Send a command to the firmware. */ static int -wpi_cmd(struct wpi_softc *sc, int code, const void *buf, int size, int async) +wpi_cmd(struct wpi_softc *sc, int code, const void *buf, size_t size, + int async) { - struct wpi_tx_ring *ring = &sc->cmdq; + struct wpi_tx_ring *ring = &sc->txq[4]; struct wpi_tx_desc *desc; + struct wpi_tx_data *data; struct wpi_tx_cmd *cmd; + struct mbuf *m; + bus_addr_t paddr; + int totlen, error; -#ifdef WPI_DEBUG - if (!async) { + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + if (async == 0) WPI_LOCK_ASSERT(sc); - } -#endif - DPRINTFN(WPI_DEBUG_CMD,("wpi_cmd %d size %d async %d\n", code, size, - async)); + DPRINTF(sc, WPI_DEBUG_CMD, "wpi_cmd %s size %zu async %d\n", + wpi_cmd_str(code), size, async); if (sc->flags & WPI_FLAG_BUSY) { device_printf(sc->sc_dev, "%s: cmd %d not sent, busy\n", __func__, code); return EAGAIN; } - sc->flags|= WPI_FLAG_BUSY; - - KASSERT(size <= sizeof cmd->data, ("command %d too large: %d bytes", - code, size)); + sc->flags |= WPI_FLAG_BUSY; desc = &ring->desc[ring->cur]; - cmd = &ring->cmd[ring->cur]; + data = &ring->data[ring->cur]; + totlen = 4 + size; + + if (size > sizeof cmd->data) { + /* Command is too large to fit in a descriptor. */ + if (totlen > MCLBYTES) + return EINVAL; + m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); + if (m == NULL) + return ENOMEM; + cmd = mtod(m, struct wpi_tx_cmd *); + error = bus_dmamap_load(ring->data_dmat, data->map, cmd, + totlen, wpi_dma_map_addr, &paddr, BUS_DMA_NOWAIT); + if (error != 0) { + m_freem(m); + return error; + } + data->m = m; + } else { + cmd = &ring->cmd[ring->cur]; + paddr = data->cmd_paddr; + } cmd->code = code; cmd->flags = 0; @@ -2208,56 +2833,36 @@ wpi_cmd(struct wpi_softc *sc, int code, const void *buf, int size, int async) cmd->idx = ring->cur; memcpy(cmd->data, buf, size); - desc->flags = htole32(WPI_PAD32(size) << 28 | 1 << 24); - desc->segs[0].addr = htole32(ring->cmd_dma.paddr + - ring->cur * sizeof (struct wpi_tx_cmd)); - desc->segs[0].len = htole32(4 + size); + desc->nsegs = 1 + (WPI_PAD32(size) << 4); + desc->segs[0].addr = htole32(paddr); + desc->segs[0].len = htole32(totlen); - /* kick cmd ring */ - ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; - WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); + if (size > sizeof cmd->data) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_PREWRITE); + } else { + bus_dmamap_sync(ring->data_dmat, ring->cmd_dma.map, + BUS_DMASYNC_PREWRITE); + } + bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, + BUS_DMASYNC_PREWRITE); + + /* Kick command ring. */ + ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; + wpi_update_tx_ring(sc, ring); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); if (async) { - sc->flags &= ~ WPI_FLAG_BUSY; + sc->flags &= ~WPI_FLAG_BUSY; return 0; } return msleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); } -static int -wpi_wme_update(struct ieee80211com *ic) -{ -#define WPI_EXP2(v) htole16((1 << (v)) - 1) -#define WPI_USEC(v) htole16(IEEE80211_TXOP_TO_US(v)) - struct wpi_softc *sc = ic->ic_ifp->if_softc; - const struct wmeParams *wmep; - struct wpi_wme_setup wme; - int ac; - - /* don't override default WME values if WME is not actually enabled */ - if (!(ic->ic_flags & IEEE80211_F_WME)) - return 0; - - wme.flags = 0; - for (ac = 0; ac < WME_NUM_AC; ac++) { - wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; - wme.ac[ac].aifsn = wmep->wmep_aifsn; - wme.ac[ac].cwmin = WPI_EXP2(wmep->wmep_logcwmin); - wme.ac[ac].cwmax = WPI_EXP2(wmep->wmep_logcwmax); - wme.ac[ac].txop = WPI_USEC(wmep->wmep_txopLimit); - - DPRINTF(("setting WME for queue %d aifsn=%d cwmin=%d cwmax=%d " - "txop=%d\n", ac, wme.ac[ac].aifsn, wme.ac[ac].cwmin, - wme.ac[ac].cwmax, wme.ac[ac].txop)); - } - return wpi_cmd(sc, WPI_CMD_SET_WME, &wme, sizeof wme, 1); -#undef WPI_USEC -#undef WPI_EXP2 -} - /* - * Configure h/w multi-rate retries. + * Configure HW multi-rate retries. */ static int wpi_mrr_setup(struct wpi_softc *sc) @@ -2267,489 +2872,529 @@ wpi_mrr_setup(struct wpi_softc *sc) struct wpi_mrr_setup mrr; int i, error; - memset(&mrr, 0, sizeof (struct wpi_mrr_setup)); - - /* CCK rates (not used with 802.11a) */ - for (i = WPI_CCK1; i <= WPI_CCK11; i++) { + /* CCK rates (not used with 802.11a). */ + for (i = WPI_RIDX_CCK1; i <= WPI_RIDX_CCK11; i++) { mrr.rates[i].flags = 0; - mrr.rates[i].signal = wpi_ridx_to_plcp[i]; - /* fallback to the immediate lower CCK rate (if any) */ - mrr.rates[i].next = (i == WPI_CCK1) ? WPI_CCK1 : i - 1; - /* try one time at this rate before falling back to "next" */ + mrr.rates[i].plcp = wpi_ridx_to_plcp[i]; + /* Fallback to the immediate lower CCK rate (if any.) */ + mrr.rates[i].next = + (i == WPI_RIDX_CCK1) ? WPI_RIDX_CCK1 : i - 1; + /* Try one time at this rate before falling back to "next". */ mrr.rates[i].ntries = 1; } - - /* OFDM rates (not used with 802.11b) */ - for (i = WPI_OFDM6; i <= WPI_OFDM54; i++) { + /* OFDM rates (not used with 802.11b). */ + for (i = WPI_RIDX_OFDM6; i <= WPI_RIDX_OFDM54; i++) { mrr.rates[i].flags = 0; - mrr.rates[i].signal = wpi_ridx_to_plcp[i]; - /* fallback to the immediate lower OFDM rate (if any) */ - /* we allow fallback from OFDM/6 to CCK/2 in 11b/g mode */ - mrr.rates[i].next = (i == WPI_OFDM6) ? + mrr.rates[i].plcp = wpi_ridx_to_plcp[i]; + /* Fallback to the immediate lower rate (if any.) */ + /* We allow fallback from OFDM/6 to CCK/2 in 11b/g mode. */ + mrr.rates[i].next = (i == WPI_RIDX_OFDM6) ? ((ic->ic_curmode == IEEE80211_MODE_11A) ? - WPI_OFDM6 : WPI_CCK2) : + WPI_RIDX_OFDM6 : WPI_RIDX_CCK2) : i - 1; - /* try one time at this rate before falling back to "next" */ + /* Try one time at this rate before falling back to "next". */ mrr.rates[i].ntries = 1; } - - /* setup MRR for control frames */ - mrr.which = WPI_MRR_CTL; + /* Setup MRR for control frames. */ + mrr.which = htole32(WPI_MRR_CTL); error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); if (error != 0) { device_printf(sc->sc_dev, "could not setup MRR for control frames\n"); return error; } - - /* setup MRR for data frames */ - mrr.which = WPI_MRR_DATA; + /* Setup MRR for data frames. */ + mrr.which = htole32(WPI_MRR_DATA); error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); if (error != 0) { device_printf(sc->sc_dev, "could not setup MRR for data frames\n"); return error; } - return 0; } +static int +wpi_add_node(struct wpi_softc *sc, struct ieee80211_node *ni) +{ + struct ieee80211com *ic = ni->ni_ic; + struct wpi_node *wn = (void *)ni; + struct wpi_node_info node; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + if (wn->id == WPI_ID_UNDEFINED) + return EINVAL; + + memset(&node, 0, sizeof node); + IEEE80211_ADDR_COPY(node.macaddr, ni->ni_bssid); + node.id = wn->id; + node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? + wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; + node.action = htole32(WPI_ACTION_SET_RATE); + node.antenna = WPI_ANTENNA_BOTH; + + return wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); +} + +/* + * Broadcast node is used to send group-addressed and management frames. + */ +static int +wpi_add_broadcast_node(struct wpi_softc *sc, int async) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct wpi_node_info node; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + memset(&node, 0, sizeof node); + IEEE80211_ADDR_COPY(node.macaddr, ifp->if_broadcastaddr); + node.id = WPI_ID_BROADCAST; + node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? + wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; + node.action = htole32(WPI_ACTION_SET_RATE); + node.antenna = WPI_ANTENNA_BOTH; + + return wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, async); +} + +static int +wpi_add_ibss_node(struct wpi_softc *sc, struct ieee80211_node *ni) +{ + struct wpi_node *wn = (void *)ni; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + if (wn->id != WPI_ID_UNDEFINED) + return EINVAL; + + wn->id = alloc_unrl(sc->sc_unr); + + if (wn->id == (uint8_t)-1) + return ENOBUFS; + + return wpi_add_node(sc, ni); +} + +static void +wpi_del_node(struct wpi_softc *sc, struct ieee80211_node *ni) +{ + struct wpi_node *wn = (void *)ni; + struct wpi_cmd_del_node node; + int error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + if (wn->id == WPI_ID_UNDEFINED) { + device_printf(sc->sc_dev, "%s: undefined node id passed\n", + __func__); + return; + } + + memset(&node, 0, sizeof node); + IEEE80211_ADDR_COPY(node.macaddr, ni->ni_bssid); + node.count = 1; + + error = wpi_cmd(sc, WPI_CMD_DEL_NODE, &node, sizeof node, 1); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not delete node %u, error %d\n", __func__, + wn->id, error); + } +} + +static int +wpi_updateedca(struct ieee80211com *ic) +{ +#define WPI_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ + struct wpi_softc *sc = ic->ic_ifp->if_softc; + struct wpi_edca_params cmd; + int aci, error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + memset(&cmd, 0, sizeof cmd); + cmd.flags = htole32(WPI_EDCA_UPDATE); + for (aci = 0; aci < WME_NUM_AC; aci++) { + const struct wmeParams *ac = + &ic->ic_wme.wme_chanParams.cap_wmeParams[aci]; + cmd.ac[aci].aifsn = ac->wmep_aifsn; + cmd.ac[aci].cwmin = htole16(WPI_EXP2(ac->wmep_logcwmin)); + cmd.ac[aci].cwmax = htole16(WPI_EXP2(ac->wmep_logcwmax)); + cmd.ac[aci].txoplimit = + htole16(IEEE80211_TXOP_TO_US(ac->wmep_txopLimit)); + + DPRINTF(sc, WPI_DEBUG_EDCA, + "setting WME for queue %d aifsn=%d cwmin=%d cwmax=%d " + "txoplimit=%d\n", aci, cmd.ac[aci].aifsn, + cmd.ac[aci].cwmin, cmd.ac[aci].cwmax, + cmd.ac[aci].txoplimit); + } + IEEE80211_UNLOCK(ic); + WPI_LOCK(sc); + error = wpi_cmd(sc, WPI_CMD_EDCA_PARAMS, &cmd, sizeof cmd, 1); + WPI_UNLOCK(sc); + IEEE80211_LOCK(ic); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return error; +#undef WPI_EXP2 +} + +static void +wpi_set_promisc(struct wpi_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + uint32_t promisc_filter; + + promisc_filter = WPI_FILTER_PROMISC | WPI_FILTER_CTL; + + if (ifp->if_flags & IFF_PROMISC) + sc->rxon.filter |= htole32(promisc_filter); + else + sc->rxon.filter &= ~htole32(promisc_filter); +} + +static void +wpi_update_promisc(struct ifnet *ifp) +{ + struct wpi_softc *sc = ifp->if_softc; + + wpi_set_promisc(sc); + + WPI_LOCK(sc); + if (wpi_send_rxon(sc, 1, 1) != 0) { + device_printf(sc->sc_dev, "%s: could not send RXON\n", + __func__); + } + WPI_UNLOCK(sc); +} + +static void +wpi_update_mcast(struct ifnet *ifp) +{ + /* Ignore */ +} + static void wpi_set_led(struct wpi_softc *sc, uint8_t which, uint8_t off, uint8_t on) { struct wpi_cmd_led led; + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + led.which = which; led.unit = htole32(100000); /* on/off in unit of 100ms */ led.off = off; led.on = on; - (void)wpi_cmd(sc, WPI_CMD_SET_LED, &led, sizeof led, 1); } -static void -wpi_enable_tsf(struct wpi_softc *sc, struct ieee80211_node *ni) +static int +wpi_set_timing(struct wpi_softc *sc, struct ieee80211_node *ni) { - struct wpi_cmd_tsf tsf; + struct wpi_cmd_timing cmd; uint64_t val, mod; - memset(&tsf, 0, sizeof tsf); - memcpy(&tsf.tstamp, ni->ni_tstamp.data, 8); - tsf.bintval = htole16(ni->ni_intval); - tsf.lintval = htole16(10); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); - /* compute remaining time until next beacon */ - val = (uint64_t)ni->ni_intval * 1024; /* msec -> usec */ - mod = le64toh(tsf.tstamp) % val; - tsf.binitval = htole32((uint32_t)(val - mod)); + memset(&cmd, 0, sizeof cmd); + memcpy(&cmd.tstamp, ni->ni_tstamp.data, sizeof (uint64_t)); + cmd.bintval = htole16(ni->ni_intval); + cmd.lintval = htole16(10); - if (wpi_cmd(sc, WPI_CMD_TSF, &tsf, sizeof tsf, 1) != 0) - device_printf(sc->sc_dev, "could not enable TSF\n"); + /* Compute remaining time until next beacon. */ + val = (uint64_t)ni->ni_intval * IEEE80211_DUR_TU; + mod = le64toh(cmd.tstamp) % val; + cmd.binitval = htole32((uint32_t)(val - mod)); + + DPRINTF(sc, WPI_DEBUG_RESET, "timing bintval=%u tstamp=%ju, init=%u\n", + ni->ni_intval, le64toh(cmd.tstamp), (uint32_t)(val - mod)); + + return wpi_cmd(sc, WPI_CMD_TIMING, &cmd, sizeof cmd, 1); } -#if 0 /* - * Build a beacon frame that the firmware will broadcast periodically in - * IBSS or HostAP modes. + * This function is called periodically (every 60 seconds) to adjust output + * power to temperature changes. + */ +static void +wpi_power_calibration(struct wpi_softc *sc) +{ + int temp; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + /* Update sensor data. */ + temp = (int)WPI_READ(sc, WPI_UCODE_GP2); + DPRINTF(sc, WPI_DEBUG_TEMP, "Temp in calibration is: %d\n", temp); + + /* Sanity-check read value. */ + if (temp < -260 || temp > 25) { + /* This can't be correct, ignore. */ + DPRINTF(sc, WPI_DEBUG_TEMP, + "out-of-range temperature reported: %d\n", temp); + return; + } + + DPRINTF(sc, WPI_DEBUG_TEMP, "temperature %d->%d\n", sc->temp, temp); + + /* Adjust Tx power if need be. */ + if (abs(temp - sc->temp) <= 6) + return; + + sc->temp = temp; + + if (wpi_set_txpower(sc, 1) != 0) { + /* just warn, too bad for the automatic calibration... */ + device_printf(sc->sc_dev,"could not adjust Tx power\n"); + } +} + +/* + * Set TX power for current channel. */ static int -wpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) +wpi_set_txpower(struct wpi_softc *sc, int async) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct wpi_tx_ring *ring = &sc->cmdq; - struct wpi_tx_desc *desc; - struct wpi_tx_data *data; - struct wpi_tx_cmd *cmd; - struct wpi_cmd_beacon *bcn; - struct ieee80211_beacon_offsets bo; - struct mbuf *m0; - bus_addr_t physaddr; - int error; + struct ieee80211_channel *ch; + struct wpi_power_group *group; + struct wpi_cmd_txpower cmd; + uint8_t chan; + int idx, i; - desc = &ring->desc[ring->cur]; - data = &ring->data[ring->cur]; + /* Retrieve current channel from last RXON. */ + chan = sc->rxon.chan; + ch = &ic->ic_channels[chan]; - m0 = ieee80211_beacon_alloc(ic, ni, &bo); - if (m0 == NULL) { - device_printf(sc->sc_dev, "could not allocate beacon frame\n"); - return ENOMEM; + /* Find the TX power group to which this channel belongs. */ + if (IEEE80211_IS_CHAN_5GHZ(ch)) { + for (group = &sc->groups[1]; group < &sc->groups[4]; group++) + if (chan <= group->chan) + break; + } else + group = &sc->groups[0]; + + memset(&cmd, 0, sizeof cmd); + cmd.band = IEEE80211_IS_CHAN_5GHZ(ch) ? 0 : 1; + cmd.chan = htole16(chan); + + /* Set TX power for all OFDM and CCK rates. */ + for (i = 0; i <= WPI_RIDX_MAX ; i++) { + /* Retrieve TX power for this channel/rate. */ + idx = wpi_get_power_index(sc, group, ch, i); + + cmd.rates[i].plcp = wpi_ridx_to_plcp[i]; + + if (IEEE80211_IS_CHAN_5GHZ(ch)) { + cmd.rates[i].rf_gain = wpi_rf_gain_5ghz[idx]; + cmd.rates[i].dsp_gain = wpi_dsp_gain_5ghz[idx]; + } else { + cmd.rates[i].rf_gain = wpi_rf_gain_2ghz[idx]; + cmd.rates[i].dsp_gain = wpi_dsp_gain_2ghz[idx]; + } + DPRINTF(sc, WPI_DEBUG_TEMP, + "chan %d/ridx %d: power index %d\n", chan, i, idx); } - cmd = &ring->cmd[ring->cur]; - cmd->code = WPI_CMD_SET_BEACON; - cmd->flags = 0; - cmd->qid = ring->qid; - cmd->idx = ring->cur; + return wpi_cmd(sc, WPI_CMD_TXPOWER, &cmd, sizeof cmd, async); +} - bcn = (struct wpi_cmd_beacon *)cmd->data; - memset(bcn, 0, sizeof (struct wpi_cmd_beacon)); - bcn->id = WPI_ID_BROADCAST; - bcn->ofdm_mask = 0xff; - bcn->cck_mask = 0x0f; - bcn->lifetime = htole32(WPI_LIFETIME_INFINITE); - bcn->len = htole16(m0->m_pkthdr.len); - bcn->rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? - wpi_plcp_signal(12) : wpi_plcp_signal(2); - bcn->flags = htole32(WPI_TX_AUTO_SEQ | WPI_TX_INSERT_TSTAMP); +/* + * Determine Tx power index for a given channel/rate combination. + * This takes into account the regulatory information from EEPROM and the + * current temperature. + */ +static int +wpi_get_power_index(struct wpi_softc *sc, struct wpi_power_group *group, + struct ieee80211_channel *c, int ridx) +{ +/* Fixed-point arithmetic division using a n-bit fractional part. */ +#define fdivround(a, b, n) \ + ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n)) - /* save and trim IEEE802.11 header */ - m_copydata(m0, 0, sizeof (struct ieee80211_frame), (caddr_t)&bcn->wh); - m_adj(m0, sizeof (struct ieee80211_frame)); +/* Linear interpolation. */ +#define interpolate(x, x1, y1, x2, y2, n) \ + ((y1) + fdivround(((x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n)) - /* assume beacon frame is contiguous */ - error = bus_dmamap_load(ring->data_dmat, data->map, mtod(m0, void *), - m0->m_pkthdr.len, wpi_dma_map_addr, &physaddr, 0); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct wpi_power_sample *sample; + int pwr, idx; + u_int chan; + + /* Get channel number. */ + chan = ieee80211_chan2ieee(ic, c); + + /* Default TX power is group maximum TX power minus 3dB. */ + pwr = group->maxpwr / 2; + + /* Decrease TX power for highest OFDM rates to reduce distortion. */ + switch (ridx) { + case WPI_RIDX_OFDM36: + pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 0 : 5; + break; + case WPI_RIDX_OFDM48: + pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 7 : 10; + break; + case WPI_RIDX_OFDM54: + pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 9 : 12; + break; + } + + /* Never exceed the channel maximum allowed TX power. */ + pwr = min(pwr, sc->maxpwr[chan]); + + /* Retrieve TX power index into gain tables from samples. */ + for (sample = group->samples; sample < &group->samples[3]; sample++) + if (pwr > sample[1].power) + break; + /* Fixed-point linear interpolation using a 19-bit fractional part. */ + idx = interpolate(pwr, sample[0].power, sample[0].index, + sample[1].power, sample[1].index, 19); + + /*- + * Adjust power index based on current temperature: + * - if cooler than factory-calibrated: decrease output power + * - if warmer than factory-calibrated: increase output power + */ + idx -= (sc->temp - group->temp) * 11 / 100; + + /* Decrease TX power for CCK rates (-5dB). */ + if (ridx >= WPI_RIDX_CCK1) + idx += 10; + + /* Make sure idx stays in a valid range. */ + if (idx < 0) + return 0; + if (idx > WPI_MAX_PWR_INDEX) + return WPI_MAX_PWR_INDEX; + return idx; + +#undef interpolate +#undef fdivround +} + +/* + * Set STA mode power saving level (between 0 and 5). + * Level 0 is CAM (Continuously Aware Mode), 5 is for maximum power saving. + */ +static int +wpi_set_pslevel(struct wpi_softc *sc, uint8_t dtim, int level, int async) +{ + struct wpi_pmgt_cmd cmd; + const struct wpi_pmgt *pmgt; + uint32_t max, skip_dtim; + uint32_t reg; + int i; + + DPRINTF(sc, WPI_DEBUG_PWRSAVE, + "%s: dtim=%d, level=%d, async=%d\n", + __func__, dtim, level, async); + + /* Select which PS parameters to use. */ + if (dtim <= 10) + pmgt = &wpi_pmgt[0][level]; + else + pmgt = &wpi_pmgt[1][level]; + + memset(&cmd, 0, sizeof cmd); + if (level != 0) /* not CAM */ + cmd.flags |= htole16(WPI_PS_ALLOW_SLEEP); + /* Retrieve PCIe Active State Power Management (ASPM). */ + reg = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); + if (!(reg & 0x1)) /* L0s Entry disabled. */ + cmd.flags |= htole16(WPI_PS_PCI_PMGT); + + cmd.rxtimeout = htole32(pmgt->rxtimeout * IEEE80211_DUR_TU); + cmd.txtimeout = htole32(pmgt->txtimeout * IEEE80211_DUR_TU); + + if (dtim == 0) { + dtim = 1; + skip_dtim = 0; + } else + skip_dtim = pmgt->skip_dtim; + + if (skip_dtim != 0) { + cmd.flags |= htole16(WPI_PS_SLEEP_OVER_DTIM); + max = pmgt->intval[4]; + if (max == (uint32_t)-1) + max = dtim * (skip_dtim + 1); + else if (max > dtim) + max = (max / dtim) * dtim; + } else + max = dtim; + + for (i = 0; i < 5; i++) + cmd.intval[i] = htole32(MIN(max, pmgt->intval[i])); + + return wpi_cmd(sc, WPI_CMD_SET_POWER_MODE, &cmd, sizeof cmd, async); +} + +static int +wpi_send_btcoex(struct wpi_softc *sc) +{ + struct wpi_bluetooth cmd; + + memset(&cmd, 0, sizeof cmd); + cmd.flags = WPI_BT_COEX_MODE_4WIRE; + cmd.lead_time = WPI_BT_LEAD_TIME_DEF; + cmd.max_kill = WPI_BT_MAX_KILL_DEF; + DPRINTF(sc, WPI_DEBUG_RESET, "%s: configuring bluetooth coexistence\n", + __func__); + return wpi_cmd(sc, WPI_CMD_BT_COEX, &cmd, sizeof(cmd), 0); +} + +static int +wpi_send_rxon(struct wpi_softc *sc, int assoc, int async) +{ + int error; + + if (assoc && (sc->rxon.filter & htole32(WPI_FILTER_BSS))) { + struct wpi_assoc rxon_assoc; + + rxon_assoc.flags = sc->rxon.flags; + rxon_assoc.filter = sc->rxon.filter; + rxon_assoc.ofdm_mask = sc->rxon.ofdm_mask; + rxon_assoc.cck_mask = sc->rxon.cck_mask; + rxon_assoc.reserved = 0; + + error = wpi_cmd(sc, WPI_CMD_RXON_ASSOC, &rxon_assoc, + sizeof (struct wpi_assoc), async); + } else { + error = wpi_cmd(sc, WPI_CMD_RXON, &sc->rxon, + sizeof (struct wpi_rxon), async); + } if (error != 0) { - device_printf(sc->sc_dev, "could not map beacon\n"); - m_freem(m0); + device_printf(sc->sc_dev, "RXON command failed, error %d\n", + error); return error; } - data->m = m0; + /* Configuration has changed, set Tx power accordingly. */ + if ((error = wpi_set_txpower(sc, async)) != 0) { + device_printf(sc->sc_dev, + "%s: could not set TX power, error %d\n", __func__, error); + return error; + } - /* first scatter/gather segment is used by the beacon command */ - desc->flags = htole32(WPI_PAD32(m0->m_pkthdr.len) << 28 | 2 << 24); - desc->segs[0].addr = htole32(ring->cmd_dma.paddr + - ring->cur * sizeof (struct wpi_tx_cmd)); - desc->segs[0].len = htole32(4 + sizeof (struct wpi_cmd_beacon)); - desc->segs[1].addr = htole32(physaddr); - desc->segs[1].len = htole32(m0->m_pkthdr.len); - - /* kick cmd ring */ - ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; - WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); + if (!(sc->rxon.filter & htole32(WPI_FILTER_BSS))) { + /* Add broadcast node. */ + error = wpi_add_broadcast_node(sc, async); + if (error != 0) { + device_printf(sc->sc_dev, + "could not add broadcast node, error %d\n", error); + return error; + } + } return 0; } -#endif - -static int -wpi_auth(struct wpi_softc *sc, struct ieee80211vap *vap) -{ - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_node *ni = vap->iv_bss; - struct wpi_node_info node; - int error; - - - /* update adapter's configuration */ - sc->config.associd = 0; - sc->config.filter &= ~htole32(WPI_FILTER_BSS); - IEEE80211_ADDR_COPY(sc->config.bssid, ni->ni_bssid); - sc->config.chan = ieee80211_chan2ieee(ic, ni->ni_chan); - if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { - sc->config.flags |= htole32(WPI_CONFIG_AUTO | - WPI_CONFIG_24GHZ); - } else { - sc->config.flags &= ~htole32(WPI_CONFIG_AUTO | - WPI_CONFIG_24GHZ); - } - if (IEEE80211_IS_CHAN_A(ni->ni_chan)) { - sc->config.cck_mask = 0; - sc->config.ofdm_mask = 0x15; - } else if (IEEE80211_IS_CHAN_B(ni->ni_chan)) { - sc->config.cck_mask = 0x03; - sc->config.ofdm_mask = 0; - } else { - /* XXX assume 802.11b/g */ - sc->config.cck_mask = 0x0f; - sc->config.ofdm_mask = 0x15; - } - - DPRINTF(("config chan %d flags %x cck %x ofdm %x\n", sc->config.chan, - sc->config.flags, sc->config.cck_mask, sc->config.ofdm_mask)); - error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config, - sizeof (struct wpi_config), 1); - if (error != 0) { - device_printf(sc->sc_dev, "could not configure\n"); - return error; - } - - /* configuration has changed, set Tx power accordingly */ - if ((error = wpi_set_txpower(sc, ni->ni_chan, 1)) != 0) { - device_printf(sc->sc_dev, "could not set Tx power\n"); - return error; - } - - /* add default node */ - memset(&node, 0, sizeof node); - IEEE80211_ADDR_COPY(node.bssid, ni->ni_bssid); - node.id = WPI_ID_BSS; - node.rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? - wpi_plcp_signal(12) : wpi_plcp_signal(2); - node.action = htole32(WPI_ACTION_SET_RATE); - node.antenna = WPI_ANTENNA_BOTH; - error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); - if (error != 0) - device_printf(sc->sc_dev, "could not add BSS node\n"); - - return (error); -} - -static int -wpi_run(struct wpi_softc *sc, struct ieee80211vap *vap) -{ - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_node *ni = vap->iv_bss; - int error; - - if (vap->iv_opmode == IEEE80211_M_MONITOR) { - /* link LED blinks while monitoring */ - wpi_set_led(sc, WPI_LED_LINK, 5, 5); - return 0; - } - - wpi_enable_tsf(sc, ni); - - /* update adapter's configuration */ - sc->config.associd = htole16(ni->ni_associd & ~0xc000); - /* short preamble/slot time are negotiated when associating */ - sc->config.flags &= ~htole32(WPI_CONFIG_SHPREAMBLE | - WPI_CONFIG_SHSLOT); - if (ic->ic_flags & IEEE80211_F_SHSLOT) - sc->config.flags |= htole32(WPI_CONFIG_SHSLOT); - if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) - sc->config.flags |= htole32(WPI_CONFIG_SHPREAMBLE); - sc->config.filter |= htole32(WPI_FILTER_BSS); - - /* XXX put somewhere HC_QOS_SUPPORT_ASSOC + HC_IBSS_START */ - - DPRINTF(("config chan %d flags %x\n", sc->config.chan, - sc->config.flags)); - error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config, sizeof (struct - wpi_config), 1); - if (error != 0) { - device_printf(sc->sc_dev, "could not update configuration\n"); - return error; - } - - error = wpi_set_txpower(sc, ni->ni_chan, 1); - if (error != 0) { - device_printf(sc->sc_dev, "could set txpower\n"); - return error; - } - - /* link LED always on while associated */ - wpi_set_led(sc, WPI_LED_LINK, 0, 1); - - /* start automatic rate control timer */ - callout_reset(&sc->calib_to, 60*hz, wpi_calib_timeout, sc); - - return (error); -} - -/* - * Send a scan request to the firmware. Since this command is huge, we map it - * into a mbufcluster instead of using the pre-allocated set of commands. Note, - * much of this code is similar to that in wpi_cmd but because we must manually - * construct the probe & channels, we duplicate what's needed here. XXX In the - * future, this function should be modified to use wpi_cmd to help cleanup the - * code base. - */ -static int -wpi_scan(struct wpi_softc *sc) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211_scan_state *ss = ic->ic_scan; - struct wpi_tx_ring *ring = &sc->cmdq; - struct wpi_tx_desc *desc; - struct wpi_tx_data *data; - struct wpi_tx_cmd *cmd; - struct wpi_scan_hdr *hdr; - struct wpi_scan_chan *chan; - struct ieee80211_frame *wh; - struct ieee80211_rateset *rs; - struct ieee80211_channel *c; - enum ieee80211_phymode mode; - uint8_t *frm; - int pktlen, error, i, nssid; - bus_addr_t physaddr; - - desc = &ring->desc[ring->cur]; - data = &ring->data[ring->cur]; - - data->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); - if (data->m == NULL) { - device_printf(sc->sc_dev, - "could not allocate mbuf for scan command\n"); - return ENOMEM; - } - - cmd = mtod(data->m, struct wpi_tx_cmd *); - cmd->code = WPI_CMD_SCAN; - cmd->flags = 0; - cmd->qid = ring->qid; - cmd->idx = ring->cur; - - hdr = (struct wpi_scan_hdr *)cmd->data; - memset(hdr, 0, sizeof(struct wpi_scan_hdr)); - - /* - * Move to the next channel if no packets are received within 5 msecs - * after sending the probe request (this helps to reduce the duration - * of active scans). - */ - hdr->quiet = htole16(5); - hdr->threshold = htole16(1); - - if (IEEE80211_IS_CHAN_A(ic->ic_curchan)) { - /* send probe requests at 6Mbps */ - hdr->tx.rate = wpi_ridx_to_plcp[WPI_OFDM6]; - - /* Enable crc checking */ - hdr->promotion = htole16(1); - } else { - hdr->flags = htole32(WPI_CONFIG_24GHZ | WPI_CONFIG_AUTO); - /* send probe requests at 1Mbps */ - hdr->tx.rate = wpi_ridx_to_plcp[WPI_CCK1]; - } - hdr->tx.id = WPI_ID_BROADCAST; - hdr->tx.lifetime = htole32(WPI_LIFETIME_INFINITE); - hdr->tx.flags = htole32(WPI_TX_AUTO_SEQ); - - memset(hdr->scan_essids, 0, sizeof(hdr->scan_essids)); - nssid = MIN(ss->ss_nssid, WPI_SCAN_MAX_ESSIDS); - for (i = 0; i < nssid; i++) { - hdr->scan_essids[i].id = IEEE80211_ELEMID_SSID; - hdr->scan_essids[i].esslen = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); - memcpy(hdr->scan_essids[i].essid, ss->ss_ssid[i].ssid, - hdr->scan_essids[i].esslen); -#ifdef WPI_DEBUG - if (wpi_debug & WPI_DEBUG_SCANNING) { - printf("Scanning Essid: "); - ieee80211_print_essid(hdr->scan_essids[i].essid, - hdr->scan_essids[i].esslen); - printf("\n"); - } -#endif - } - - /* - * Build a probe request frame. Most of the following code is a - * copy & paste of what is done in net80211. - */ - wh = (struct ieee80211_frame *)&hdr->scan_essids[WPI_SCAN_MAX_ESSIDS]; - wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | - IEEE80211_FC0_SUBTYPE_PROBE_REQ; - wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; - IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); - IEEE80211_ADDR_COPY(wh->i_addr2, IF_LLADDR(ifp)); - IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); - *(u_int16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ - *(u_int16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ - - frm = (uint8_t *)(wh + 1); - - mode = ieee80211_chan2mode(ic->ic_curchan); - rs = &ic->ic_sup_rates[mode]; - - frm = ieee80211_add_ssid(frm, NULL, 0); - frm = ieee80211_add_rates(frm, rs); - frm = ieee80211_add_xrates(frm, rs); - - /* setup length of probe request */ - hdr->tx.len = htole16(frm - (uint8_t *)wh); - - /* - * Construct information about the channel that we - * want to scan. The firmware expects this to be directly - * after the scan probe request - */ - c = ic->ic_curchan; - chan = (struct wpi_scan_chan *)frm; - chan->chan = ieee80211_chan2ieee(ic, c); - chan->flags = 0; - if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { - chan->flags |= WPI_CHAN_ACTIVE; - if (nssid != 0) - chan->flags |= WPI_CHAN_DIRECT; - } - chan->gain_dsp = 0x6e; /* Default level */ - if (IEEE80211_IS_CHAN_5GHZ(c)) { - chan->active = htole16(10); - chan->passive = htole16(ss->ss_maxdwell); - chan->gain_radio = 0x3b; - } else { - chan->active = htole16(20); - chan->passive = htole16(ss->ss_maxdwell); - chan->gain_radio = 0x28; - } - - DPRINTFN(WPI_DEBUG_SCANNING, - ("Scanning %u Passive: %d\n", - chan->chan, - c->ic_flags & IEEE80211_CHAN_PASSIVE)); - - hdr->nchan++; - chan++; - - frm += sizeof (struct wpi_scan_chan); -#if 0 - // XXX All Channels.... - for (c = &ic->ic_channels[1]; - c <= &ic->ic_channels[IEEE80211_CHAN_MAX]; c++) { - if ((c->ic_flags & ic->ic_curchan->ic_flags) != ic->ic_curchan->ic_flags) - continue; - - chan->chan = ieee80211_chan2ieee(ic, c); - chan->flags = 0; - if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { - chan->flags |= WPI_CHAN_ACTIVE; - if (ic->ic_des_ssid[0].len != 0) - chan->flags |= WPI_CHAN_DIRECT; - } - chan->gain_dsp = 0x6e; /* Default level */ - if (IEEE80211_IS_CHAN_5GHZ(c)) { - chan->active = htole16(10); - chan->passive = htole16(110); - chan->gain_radio = 0x3b; - } else { - chan->active = htole16(20); - chan->passive = htole16(120); - chan->gain_radio = 0x28; - } - - DPRINTFN(WPI_DEBUG_SCANNING, - ("Scanning %u Passive: %d\n", - chan->chan, - c->ic_flags & IEEE80211_CHAN_PASSIVE)); - - hdr->nchan++; - chan++; - - frm += sizeof (struct wpi_scan_chan); - } -#endif - - hdr->len = htole16(frm - (uint8_t *)hdr); - pktlen = frm - (uint8_t *)cmd; - - error = bus_dmamap_load(ring->data_dmat, data->map, cmd, pktlen, - wpi_dma_map_addr, &physaddr, BUS_DMA_NOWAIT); - if (error != 0) { - device_printf(sc->sc_dev, "could not map scan command\n"); - m_freem(data->m); - data->m = NULL; - return error; - } - - desc->flags = htole32(WPI_PAD32(pktlen) << 28 | 1 << 24); - desc->segs[0].addr = htole32(physaddr); - desc->segs[0].len = htole32(pktlen); - - bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, - BUS_DMASYNC_PREWRITE); - bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); - - /* kick cmd ring */ - ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; - WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); - - sc->sc_scan_timer = 5; - return 0; /* will be notified async. of failure/success */ -} /** * Configure the card to listen to a particular channel, this transisions the @@ -2760,383 +3405,1313 @@ wpi_config(struct wpi_softc *sc) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct wpi_power power; - struct wpi_bluetooth bluetooth; - struct wpi_node_info node; + uint32_t flags; int error; - /* set power mode */ - memset(&power, 0, sizeof power); - power.flags = htole32(WPI_POWER_CAM|0x8); - error = wpi_cmd(sc, WPI_CMD_SET_POWER_MODE, &power, sizeof power, 0); - if (error != 0) { - device_printf(sc->sc_dev, "could not set power mode\n"); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + /* Set power saving level to CAM during initialization. */ + if ((error = wpi_set_pslevel(sc, 0, 0, 0)) != 0) { + device_printf(sc->sc_dev, + "%s: could not set power saving level\n", __func__); return error; } - /* configure bluetooth coexistence */ - memset(&bluetooth, 0, sizeof bluetooth); - bluetooth.flags = 3; - bluetooth.lead = 0xaa; - bluetooth.kill = 1; - error = wpi_cmd(sc, WPI_CMD_BLUETOOTH, &bluetooth, sizeof bluetooth, - 0); - if (error != 0) { + /* Configure bluetooth coexistence. */ + if ((error = wpi_send_btcoex(sc)) != 0) { device_printf(sc->sc_dev, "could not configure bluetooth coexistence\n"); return error; } - /* configure adapter */ - memset(&sc->config, 0, sizeof (struct wpi_config)); - IEEE80211_ADDR_COPY(sc->config.myaddr, IF_LLADDR(ifp)); - /*set default channel*/ - sc->config.chan = htole16(ieee80211_chan2ieee(ic, ic->ic_curchan)); - sc->config.flags = htole32(WPI_CONFIG_TSF); - if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { - sc->config.flags |= htole32(WPI_CONFIG_AUTO | - WPI_CONFIG_24GHZ); - } - sc->config.filter = 0; + /* Configure adapter. */ + memset(&sc->rxon, 0, sizeof (struct wpi_rxon)); + IEEE80211_ADDR_COPY(sc->rxon.myaddr, IF_LLADDR(ifp)); + + /* Set default channel. */ + sc->rxon.chan = ieee80211_chan2ieee(ic, ic->ic_curchan); + sc->rxon.flags = htole32(WPI_RXON_TSF | WPI_RXON_CTS_TO_SELF); + if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) + sc->rxon.flags |= htole32(WPI_RXON_AUTO | WPI_RXON_24GHZ); + switch (ic->ic_opmode) { case IEEE80211_M_STA: - case IEEE80211_M_WDS: /* No know setup, use STA for now */ - sc->config.mode = WPI_MODE_STA; - sc->config.filter |= htole32(WPI_FILTER_MULTICAST); + sc->rxon.mode = WPI_MODE_STA; + sc->rxon.filter = htole32(WPI_FILTER_MULTICAST); break; case IEEE80211_M_IBSS: - case IEEE80211_M_AHDEMO: - sc->config.mode = WPI_MODE_IBSS; - sc->config.filter |= htole32(WPI_FILTER_BEACON | - WPI_FILTER_MULTICAST); + sc->rxon.mode = WPI_MODE_IBSS; + sc->rxon.filter = htole32(WPI_FILTER_BEACON | + WPI_FILTER_MULTICAST); break; + /* XXX workaround for passive channels selection */ + case IEEE80211_M_AHDEMO: + sc->rxon.filter = htole32(WPI_FILTER_MULTICAST); + /* FALLTHROUGH */ case IEEE80211_M_HOSTAP: - sc->config.mode = WPI_MODE_HOSTAP; + sc->rxon.mode = WPI_MODE_HOSTAP; break; case IEEE80211_M_MONITOR: - sc->config.mode = WPI_MODE_MONITOR; - sc->config.filter |= htole32(WPI_FILTER_MULTICAST | - WPI_FILTER_CTL | WPI_FILTER_PROMISC); + sc->rxon.mode = WPI_MODE_MONITOR; + sc->rxon.filter = htole32(WPI_FILTER_MULTICAST); break; default: device_printf(sc->sc_dev, "unknown opmode %d\n", ic->ic_opmode); return EINVAL; } - sc->config.cck_mask = 0x0f; /* not yet negotiated */ - sc->config.ofdm_mask = 0xff; /* not yet negotiated */ - error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config, - sizeof (struct wpi_config), 0); - if (error != 0) { - device_printf(sc->sc_dev, "configure command failed\n"); + wpi_set_promisc(sc); + sc->rxon.cck_mask = 0x0f; /* not yet negotiated */ + sc->rxon.ofdm_mask = 0xff; /* not yet negotiated */ + + if ((error = wpi_send_rxon(sc, 0, 0)) != 0) { + device_printf(sc->sc_dev, "%s: could not send RXON\n", + __func__); return error; } - /* configuration has changed, set Tx power accordingly */ - if ((error = wpi_set_txpower(sc, ic->ic_curchan, 0)) != 0) { - device_printf(sc->sc_dev, "could not set Tx power\n"); - return error; + /* Setup rate scalling. */ + if ((error = wpi_mrr_setup(sc)) != 0) { + device_printf(sc->sc_dev, "could not setup MRR, error %d\n", + error); + return error; } - /* add broadcast node */ + /* Disable beacon notifications (unused). */ + flags = WPI_STATISTICS_BEACON_DISABLE; + error = wpi_cmd(sc, WPI_CMD_GET_STATISTICS, &flags, sizeof flags, 1); + if (error != 0) { + device_printf(sc->sc_dev, + "could not disable beacon statistics, error %d\n", error); + return error; + } + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return 0; +} + +static uint16_t +wpi_get_active_dwell_time(struct wpi_softc *sc, + struct ieee80211_channel *c, uint8_t n_probes) +{ + /* No channel? Default to 2GHz settings. */ + if (c == NULL || IEEE80211_IS_CHAN_2GHZ(c)) { + return (WPI_ACTIVE_DWELL_TIME_2GHZ + + WPI_ACTIVE_DWELL_FACTOR_2GHZ * (n_probes + 1)); + } + + /* 5GHz dwell time. */ + return (WPI_ACTIVE_DWELL_TIME_5GHZ + + WPI_ACTIVE_DWELL_FACTOR_5GHZ * (n_probes + 1)); +} + +/* + * Limit the total dwell time to 85% of the beacon interval. + * + * Returns the dwell time in milliseconds. + */ +static uint16_t +wpi_limit_dwell(struct wpi_softc *sc, uint16_t dwell_time) +{ + struct ieee80211com *ic = sc->sc_ifp->if_l2com; + struct ieee80211vap *vap = NULL; + int bintval = 0; + + /* bintval is in TU (1.024mS) */ + if (! TAILQ_EMPTY(&ic->ic_vaps)) { + vap = TAILQ_FIRST(&ic->ic_vaps); + bintval = vap->iv_bss->ni_intval; + } + + /* + * If it's non-zero, we should calculate the minimum of + * it and the DWELL_BASE. + * + * XXX Yes, the math should take into account that bintval + * is 1.024mS, not 1mS.. + */ + if (bintval > 0) { + DPRINTF(sc, WPI_DEBUG_SCAN, "%s: bintval=%d\n", __func__, + bintval); + return (MIN(WPI_PASSIVE_DWELL_BASE, ((bintval * 85) / 100))); + } + + /* No association context? Default. */ + return (WPI_PASSIVE_DWELL_BASE); +} + +static uint16_t +wpi_get_passive_dwell_time(struct wpi_softc *sc, struct ieee80211_channel *c) +{ + uint16_t passive; + + if (c == NULL || IEEE80211_IS_CHAN_2GHZ(c)) + passive = WPI_PASSIVE_DWELL_BASE + WPI_PASSIVE_DWELL_TIME_2GHZ; + else + passive = WPI_PASSIVE_DWELL_BASE + WPI_PASSIVE_DWELL_TIME_5GHZ; + + /* Clamp to the beacon interval if we're associated. */ + return (wpi_limit_dwell(sc, passive)); +} + +/* + * Send a scan request to the firmware. + */ +static int +wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211_scan_state *ss = ic->ic_scan; + struct wpi_scan_hdr *hdr; + struct wpi_cmd_data *tx; + struct wpi_scan_essid *essids; + struct wpi_scan_chan *chan; + struct ieee80211_frame *wh; + struct ieee80211_rateset *rs; + uint16_t dwell_active, dwell_passive; + uint8_t *buf, *frm; + int buflen, error, i, nssid; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + /* + * We are absolutely not allowed to send a scan command when another + * scan command is pending. + */ + if (sc->sc_scan_timer) { + device_printf(sc->sc_dev, "%s: called whilst scanning!\n", + __func__); + return (EAGAIN); + } + + buf = malloc(WPI_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO); + if (buf == NULL) { + device_printf(sc->sc_dev, + "%s: could not allocate buffer for scan command\n", + __func__); + return ENOMEM; + } + hdr = (struct wpi_scan_hdr *)buf; + + /* + * Move to the next channel if no packets are received within 10 msecs + * after sending the probe request. + */ + hdr->quiet_time = htole16(10); /* timeout in milliseconds */ + hdr->quiet_threshold = htole16(1); /* min # of packets */ + /* + * Max needs to be greater than active and passive and quiet! + * It's also in microseconds! + */ + hdr->max_svc = htole32(250 * IEEE80211_DUR_TU); + hdr->pause_svc = htole32((4 << 24) | + (100 * IEEE80211_DUR_TU)); /* Hardcode for now */ + hdr->filter = htole32(WPI_FILTER_MULTICAST | WPI_FILTER_BEACON); + + tx = (struct wpi_cmd_data *)(hdr + 1); + tx->flags = htole32(WPI_TX_AUTO_SEQ); + tx->id = WPI_ID_BROADCAST; + tx->lifetime = htole32(WPI_LIFETIME_INFINITE); + + if (IEEE80211_IS_CHAN_5GHZ(c)) { + /* Send probe requests at 6Mbps. */ + tx->plcp = wpi_ridx_to_plcp[WPI_RIDX_OFDM6]; + rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; + } else { + hdr->flags = htole32(WPI_RXON_24GHZ | WPI_RXON_AUTO); + /* Send probe requests at 1Mbps. */ + tx->plcp = wpi_ridx_to_plcp[WPI_RIDX_CCK1]; + rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; + } + + essids = (struct wpi_scan_essid *)(tx + 1); + nssid = MIN(ss->ss_nssid, WPI_SCAN_MAX_ESSIDS); + for (i = 0; i < nssid; i++) { + essids[i].id = IEEE80211_ELEMID_SSID; + essids[i].len = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); + memcpy(essids[i].data, ss->ss_ssid[i].ssid, essids[i].len); +#ifdef WPI_DEBUG + if (sc->sc_debug & WPI_DEBUG_SCAN) { + printf("Scanning Essid: "); + ieee80211_print_essid(essids[i].data, essids[i].len); + printf("\n"); + } +#endif + } + + /* + * Build a probe request frame. Most of the following code is a + * copy & paste of what is done in net80211. + */ + wh = (struct ieee80211_frame *)(essids + WPI_SCAN_MAX_ESSIDS); + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | + IEEE80211_FC0_SUBTYPE_PROBE_REQ; + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); + IEEE80211_ADDR_COPY(wh->i_addr2, IF_LLADDR(ifp)); + IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); + *(uint16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ + *(uint16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ + + frm = (uint8_t *)(wh + 1); + frm = ieee80211_add_ssid(frm, NULL, 0); + frm = ieee80211_add_rates(frm, rs); + if (rs->rs_nrates > IEEE80211_RATE_SIZE) + frm = ieee80211_add_xrates(frm, rs); + + /* Set length of probe request. */ + tx->len = htole16(frm - (uint8_t *)wh); + + /* + * Construct information about the channel that we + * want to scan. The firmware expects this to be directly + * after the scan probe request + */ + chan = (struct wpi_scan_chan *)frm; + chan->chan = htole16(ieee80211_chan2ieee(ic, c)); + chan->flags = 0; + if (nssid) { + hdr->crc_threshold = WPI_SCAN_CRC_TH_DEFAULT; + chan->flags |= WPI_CHAN_NPBREQS(nssid); + } else + hdr->crc_threshold = WPI_SCAN_CRC_TH_NEVER; + + if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) + chan->flags |= WPI_CHAN_ACTIVE; + + /* + * Calculate the active/passive dwell times. + */ + + dwell_active = wpi_get_active_dwell_time(sc, c, nssid); + dwell_passive = wpi_get_passive_dwell_time(sc, c); + + /* Make sure they're valid. */ + if (dwell_passive <= dwell_active) + dwell_passive = dwell_active + 1; + + chan->active = htole16(dwell_active); + chan->passive = htole16(dwell_passive); + + chan->dsp_gain = 0x6e; /* Default level */ + + if (IEEE80211_IS_CHAN_5GHZ(c)) + chan->rf_gain = 0x3b; + else + chan->rf_gain = 0x28; + + DPRINTF(sc, WPI_DEBUG_SCAN, "Scanning %u Passive: %d\n", + chan->chan, (c->ic_flags & IEEE80211_CHAN_PASSIVE) ? 1 : 0); + + hdr->nchan++; + chan++; + + buflen = (uint8_t *)chan - buf; + hdr->len = htole16(buflen); + + DPRINTF(sc, WPI_DEBUG_CMD, "sending scan command nchan=%d\n", + hdr->nchan); + error = wpi_cmd(sc, WPI_CMD_SCAN, buf, buflen, 1); + free(buf, M_DEVBUF); + + sc->sc_scan_timer = 5; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return error; +} + +static int +wpi_auth(struct wpi_softc *sc, struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_node *ni = vap->iv_bss; + int error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + /* Update adapter configuration. */ + sc->rxon.associd = 0; + sc->rxon.filter &= ~htole32(WPI_FILTER_BSS); + IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid); + sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan); + sc->rxon.flags = htole32(WPI_RXON_TSF | WPI_RXON_CTS_TO_SELF); + if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) + sc->rxon.flags |= htole32(WPI_RXON_AUTO | WPI_RXON_24GHZ); + if (ic->ic_flags & IEEE80211_F_SHSLOT) + sc->rxon.flags |= htole32(WPI_RXON_SHSLOT); + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + sc->rxon.flags |= htole32(WPI_RXON_SHPREAMBLE); + if (IEEE80211_IS_CHAN_A(ni->ni_chan)) { + sc->rxon.cck_mask = 0; + sc->rxon.ofdm_mask = 0x15; + } else if (IEEE80211_IS_CHAN_B(ni->ni_chan)) { + sc->rxon.cck_mask = 0x03; + sc->rxon.ofdm_mask = 0; + } else { + /* Assume 802.11b/g. */ + sc->rxon.cck_mask = 0x0f; + sc->rxon.ofdm_mask = 0x15; + } + + DPRINTF(sc, WPI_DEBUG_STATE, "rxon chan %d flags %x cck %x ofdm %x\n", + sc->rxon.chan, sc->rxon.flags, sc->rxon.cck_mask, + sc->rxon.ofdm_mask); + + if ((error = wpi_send_rxon(sc, 0, 1)) != 0) { + device_printf(sc->sc_dev, "%s: could not send RXON\n", + __func__); + } + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return error; +} + +static int +wpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = ni->ni_vap; + struct wpi_vap *wvp = WPI_VAP(vap); + struct wpi_buf *bcn = &wvp->wv_bcbuf; + struct ieee80211_beacon_offsets bo; + struct wpi_cmd_beacon *cmd; + struct mbuf *m; + int totlen; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + if (ni->ni_chan == IEEE80211_CHAN_ANYC) + return EINVAL; + + m = ieee80211_beacon_alloc(ni, &bo); + if (m == NULL) { + device_printf(sc->sc_dev, + "%s: could not allocate beacon frame\n", __func__); + return ENOMEM; + } + totlen = m->m_pkthdr.len; + + if (bcn->data == NULL) { + cmd = malloc(sizeof(struct wpi_cmd_beacon), M_DEVBUF, + M_NOWAIT | M_ZERO); + + if (cmd == NULL) { + device_printf(sc->sc_dev, + "could not allocate buffer for beacon command\n"); + m_freem(m); + return ENOMEM; + } + + cmd->id = WPI_ID_BROADCAST; + cmd->ofdm_mask = 0xff; + cmd->cck_mask = 0x0f; + cmd->lifetime = htole32(WPI_LIFETIME_INFINITE); + cmd->flags = htole32(WPI_TX_AUTO_SEQ | WPI_TX_INSERT_TSTAMP); + + bcn->data = cmd; + bcn->ni = NULL; + bcn->code = WPI_CMD_SET_BEACON; + bcn->ac = 4; + bcn->size = sizeof(struct wpi_cmd_beacon); + } else + cmd = bcn->data; + + cmd->len = htole16(totlen); + cmd->plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? + wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; + + /* NB: m will be freed in wpi_cmd_done() */ + bcn->m = m; + + return wpi_cmd2(sc, bcn); +} + +static void +wpi_update_beacon(struct ieee80211vap *vap, int item) +{ + struct ieee80211_node *ni = vap->iv_bss; + struct ifnet *ifp = vap->iv_ifp; + struct wpi_softc *sc = ifp->if_softc; + int error; + + if ((error = wpi_setup_beacon(sc, ni)) != 0) { + device_printf(sc->sc_dev, + "%s: could not update beacon frame, error %d", __func__, + error); + } +} + +static int +wpi_run(struct wpi_softc *sc, struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_node *ni = vap->iv_bss; + int error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + + if (vap->iv_opmode == IEEE80211_M_MONITOR) { + /* Link LED blinks while monitoring. */ + wpi_set_led(sc, WPI_LED_LINK, 5, 5); + return 0; + } + + /* XXX kernel panic workaround */ + if (ni->ni_chan == IEEE80211_CHAN_ANYC) { + device_printf(sc->sc_dev, "%s: incomplete configuration\n", + __func__); + return EINVAL; + } + + if ((error = wpi_set_timing(sc, ni)) != 0) { + device_printf(sc->sc_dev, + "%s: could not set timing, error %d\n", __func__, error); + return error; + } + + /* Update adapter configuration. */ + IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid); + sc->rxon.associd = htole16(IEEE80211_NODE_AID(ni)); + sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan); + sc->rxon.flags = htole32(WPI_RXON_TSF | WPI_RXON_CTS_TO_SELF); + if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) + sc->rxon.flags |= htole32(WPI_RXON_AUTO | WPI_RXON_24GHZ); + /* Short preamble and slot time are negotiated when associating. */ + sc->rxon.flags &= ~htole32(WPI_RXON_SHPREAMBLE | WPI_RXON_SHSLOT); + if (ic->ic_flags & IEEE80211_F_SHSLOT) + sc->rxon.flags |= htole32(WPI_RXON_SHSLOT); + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + sc->rxon.flags |= htole32(WPI_RXON_SHPREAMBLE); + if (IEEE80211_IS_CHAN_A(ni->ni_chan)) { + sc->rxon.cck_mask = 0; + sc->rxon.ofdm_mask = 0x15; + } else if (IEEE80211_IS_CHAN_B(ni->ni_chan)) { + sc->rxon.cck_mask = 0x03; + sc->rxon.ofdm_mask = 0; + } else { + /* Assume 802.11b/g. */ + sc->rxon.cck_mask = 0x0f; + sc->rxon.ofdm_mask = 0x15; + } + sc->rxon.filter |= htole32(WPI_FILTER_BSS); + + /* XXX put somewhere HC_QOS_SUPPORT_ASSOC + HC_IBSS_START */ + + DPRINTF(sc, WPI_DEBUG_STATE, "rxon chan %d flags %x\n", + sc->rxon.chan, sc->rxon.flags); + + if ((error = wpi_send_rxon(sc, 0, 1)) != 0) { + device_printf(sc->sc_dev, "%s: could not send RXON\n", + __func__); + return error; + } + + if (vap->iv_opmode == IEEE80211_M_IBSS) { + if ((error = wpi_setup_beacon(sc, ni)) != 0) { + device_printf(sc->sc_dev, + "%s: could not setup beacon, error %d\n", __func__, + error); + return error; + } + } + + if (vap->iv_opmode == IEEE80211_M_STA) { + /* Add BSS node. */ + ((struct wpi_node *)ni)->id = WPI_ID_BSS; + if ((error = wpi_add_node(sc, ni)) != 0) { + device_printf(sc->sc_dev, + "%s: could not add BSS node, error %d\n", __func__, + error); + return error; + } + } + + /* Link LED always on while associated. */ + wpi_set_led(sc, WPI_LED_LINK, 0, 1); + + /* Start periodic calibration timer. */ + callout_reset(&sc->calib_to, 60*hz, wpi_calib_timeout, sc); + + /* Enable power-saving mode if requested by user. */ + if (vap->iv_flags & IEEE80211_F_PMGTON) + (void)wpi_set_pslevel(sc, 0, 3, 1); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return 0; +} + +static int +wpi_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, + ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) +{ + struct ifnet *ifp = vap->iv_ifp; + struct wpi_softc *sc = ifp->if_softc; + + if (!(&vap->iv_nw_keys[0] <= k && + k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) { + if (k->wk_flags & IEEE80211_KEY_GROUP) { + /* should not happen */ + DPRINTF(sc, WPI_DEBUG_KEY, "%s: bogus group key\n", + __func__); + return 0; + } + *keyix = 0; /* NB: use key index 0 for ucast key */ + } else { + *keyix = *rxkeyix = k - vap->iv_nw_keys; + + if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_AES_CCM) + k->wk_flags |= IEEE80211_KEY_SWCRYPT; + } + return 1; +} + +static int +wpi_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + const struct ieee80211_cipher *cip = k->wk_cipher; + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_node *ni = vap->iv_bss; + struct wpi_softc *sc = ic->ic_ifp->if_softc; + struct wpi_node *wn = (void *)ni; + struct wpi_node_info node; + uint16_t kflags; + int error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + switch (cip->ic_cipher) { + case IEEE80211_CIPHER_AES_CCM: + if (k->wk_flags & IEEE80211_KEY_GROUP) + return 1; + + kflags = WPI_KFLAG_CCMP; + break; + default: + /* null_key_set() */ + return 1; + } + + if (wn->id == WPI_ID_UNDEFINED) + return 0; + + kflags |= WPI_KFLAG_KID(k->wk_keyix); + if (k->wk_flags & IEEE80211_KEY_GROUP) + kflags |= WPI_KFLAG_MULTICAST; + memset(&node, 0, sizeof node); - IEEE80211_ADDR_COPY(node.bssid, ifp->if_broadcastaddr); - node.id = WPI_ID_BROADCAST; - node.rate = wpi_plcp_signal(2); - error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 0); + node.id = wn->id; + node.control = WPI_NODE_UPDATE; + node.flags = WPI_FLAG_KEY_SET; + node.kflags = htole16(kflags); + memcpy(node.key, k->wk_key, k->wk_keylen); + + DPRINTF(sc, WPI_DEBUG_KEY, "set key id=%d for node %d\n", k->wk_keyix, + node.id); + + error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); if (error != 0) { - device_printf(sc->sc_dev, "could not add broadcast node\n"); + device_printf(sc->sc_dev, "can't update node info, error %d\n", + error); + return 0; + } + + return 1; +} + +static int +wpi_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + const struct ieee80211_cipher *cip = k->wk_cipher; + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_node *ni = vap->iv_bss; + struct wpi_softc *sc = ic->ic_ifp->if_softc; + struct wpi_node *wn = (void *)ni; + struct wpi_node_info node; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + switch (cip->ic_cipher) { + case IEEE80211_CIPHER_AES_CCM: + break; + default: + /* null_key_delete() */ + return 1; + } + + if (vap->iv_state != IEEE80211_S_RUN || + (k->wk_flags & IEEE80211_KEY_GROUP)) + return 1; /* Nothing to do. */ + + memset(&node, 0, sizeof node); + node.id = wn->id; + node.control = WPI_NODE_UPDATE; + node.flags = WPI_FLAG_KEY_SET; + + DPRINTF(sc, WPI_DEBUG_KEY, "delete keys for node %d\n", node.id); + (void)wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); + + return 1; +} + +/* + * This function is called after the runtime firmware notifies us of its + * readiness (called in a process context). + */ +static int +wpi_post_alive(struct wpi_softc *sc) +{ + int ntries, error; + + /* Check (again) that the radio is not disabled. */ + if ((error = wpi_nic_lock(sc)) != 0) + return error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + /* NB: Runtime firmware must be up and running. */ + if (!(wpi_prph_read(sc, WPI_APMG_RFKILL) & 1)) { + device_printf(sc->sc_dev, + "RF switch: radio disabled (%s)\n", __func__); + wpi_nic_unlock(sc); + return EPERM; /* :-) */ + } + wpi_nic_unlock(sc); + + /* Wait for thermal sensor to calibrate. */ + for (ntries = 0; ntries < 1000; ntries++) { + if ((sc->temp = (int)WPI_READ(sc, WPI_UCODE_GP2)) != 0) + break; + DELAY(10); + } + + if (ntries == 1000) { + device_printf(sc->sc_dev, + "timeout waiting for thermal sensor calibration\n"); + return ETIMEDOUT; + } + + DPRINTF(sc, WPI_DEBUG_TEMP, "temperature %d\n", sc->temp); + return 0; +} + +/* + * The firmware boot code is small and is intended to be copied directly into + * the NIC internal memory (no DMA transfer). + */ +static int +wpi_load_bootcode(struct wpi_softc *sc, const uint8_t *ucode, int size) +{ + int error, ntries; + + DPRINTF(sc, WPI_DEBUG_HW, "Loading microcode size 0x%x\n", size); + + size /= sizeof (uint32_t); + + if ((error = wpi_nic_lock(sc)) != 0) + return error; + + /* Copy microcode image into NIC memory. */ + wpi_prph_write_region_4(sc, WPI_BSM_SRAM_BASE, + (const uint32_t *)ucode, size); + + wpi_prph_write(sc, WPI_BSM_WR_MEM_SRC, 0); + wpi_prph_write(sc, WPI_BSM_WR_MEM_DST, WPI_FW_TEXT_BASE); + wpi_prph_write(sc, WPI_BSM_WR_DWCOUNT, size); + + /* Start boot load now. */ + wpi_prph_write(sc, WPI_BSM_WR_CTRL, WPI_BSM_WR_CTRL_START); + + /* Wait for transfer to complete. */ + for (ntries = 0; ntries < 1000; ntries++) { + uint32_t status = WPI_READ(sc, WPI_FH_TX_STATUS); + DPRINTF(sc, WPI_DEBUG_HW, + "firmware status=0x%x, val=0x%x, result=0x%x\n", status, + WPI_FH_TX_STATUS_IDLE(6), + status & WPI_FH_TX_STATUS_IDLE(6)); + if (status & WPI_FH_TX_STATUS_IDLE(6)) { + DPRINTF(sc, WPI_DEBUG_HW, + "Status Match! - ntries = %d\n", ntries); + break; + } + DELAY(10); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, "%s: could not load boot firmware\n", + __func__); + wpi_nic_unlock(sc); + return ETIMEDOUT; + } + + /* Enable boot after power up. */ + wpi_prph_write(sc, WPI_BSM_WR_CTRL, WPI_BSM_WR_CTRL_START_EN); + + wpi_nic_unlock(sc); + return 0; +} + +static int +wpi_load_firmware(struct wpi_softc *sc) +{ + struct wpi_fw_info *fw = &sc->fw; + struct wpi_dma_info *dma = &sc->fw_dma; + int error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + /* Copy initialization sections into pre-allocated DMA-safe memory. */ + memcpy(dma->vaddr, fw->init.data, fw->init.datasz); + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); + memcpy(dma->vaddr + WPI_FW_DATA_MAXSZ, fw->init.text, fw->init.textsz); + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); + + /* Tell adapter where to find initialization sections. */ + if ((error = wpi_nic_lock(sc)) != 0) + return error; + wpi_prph_write(sc, WPI_BSM_DRAM_DATA_ADDR, dma->paddr); + wpi_prph_write(sc, WPI_BSM_DRAM_DATA_SIZE, fw->init.datasz); + wpi_prph_write(sc, WPI_BSM_DRAM_TEXT_ADDR, + dma->paddr + WPI_FW_DATA_MAXSZ); + wpi_prph_write(sc, WPI_BSM_DRAM_TEXT_SIZE, fw->init.textsz); + wpi_nic_unlock(sc); + + /* Load firmware boot code. */ + error = wpi_load_bootcode(sc, fw->boot.text, fw->boot.textsz); + if (error != 0) { + device_printf(sc->sc_dev, "%s: could not load boot firmware\n", + __func__); return error; } - /* Setup rate scalling */ - error = wpi_mrr_setup(sc); - if (error != 0) { - device_printf(sc->sc_dev, "could not setup MRR\n"); + /* Now press "execute". */ + WPI_WRITE(sc, WPI_RESET, 0); + + /* Wait at most one second for first alive notification. */ + if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { + device_printf(sc->sc_dev, + "%s: timeout waiting for adapter to initialize, error %d\n", + __func__, error); return error; } + /* Copy runtime sections into pre-allocated DMA-safe memory. */ + memcpy(dma->vaddr, fw->main.data, fw->main.datasz); + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); + memcpy(dma->vaddr + WPI_FW_DATA_MAXSZ, fw->main.text, fw->main.textsz); + bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); + + /* Tell adapter where to find runtime sections. */ + if ((error = wpi_nic_lock(sc)) != 0) + return error; + wpi_prph_write(sc, WPI_BSM_DRAM_DATA_ADDR, dma->paddr); + wpi_prph_write(sc, WPI_BSM_DRAM_DATA_SIZE, fw->main.datasz); + wpi_prph_write(sc, WPI_BSM_DRAM_TEXT_ADDR, + dma->paddr + WPI_FW_DATA_MAXSZ); + wpi_prph_write(sc, WPI_BSM_DRAM_TEXT_SIZE, + WPI_FW_UPDATED | fw->main.textsz); + wpi_nic_unlock(sc); + + return 0; +} + +static int +wpi_read_firmware(struct wpi_softc *sc) +{ + const struct firmware *fp; + struct wpi_fw_info *fw = &sc->fw; + const struct wpi_firmware_hdr *hdr; + int error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + DPRINTF(sc, WPI_DEBUG_FIRMWARE, + "Attempting Loading Firmware from %s module\n", WPI_FW_NAME); + + WPI_UNLOCK(sc); + fp = firmware_get(WPI_FW_NAME); + WPI_LOCK(sc); + + if (fp == NULL) { + device_printf(sc->sc_dev, + "could not load firmware image '%s'\n", WPI_FW_NAME); + return EINVAL; + } + + sc->fw_fp = fp; + + if (fp->datasize < sizeof (struct wpi_firmware_hdr)) { + device_printf(sc->sc_dev, + "firmware file too short: %zu bytes\n", fp->datasize); + error = EINVAL; + goto fail; + } + + fw->size = fp->datasize; + fw->data = (const uint8_t *)fp->data; + + /* Extract firmware header information. */ + hdr = (const struct wpi_firmware_hdr *)fw->data; + + /* | RUNTIME FIRMWARE | INIT FIRMWARE | BOOT FW | + |HDR|<--TEXT-->|<--DATA-->|<--TEXT-->|<--DATA-->|<--TEXT-->| */ + + fw->main.textsz = le32toh(hdr->rtextsz); + fw->main.datasz = le32toh(hdr->rdatasz); + fw->init.textsz = le32toh(hdr->itextsz); + fw->init.datasz = le32toh(hdr->idatasz); + fw->boot.textsz = le32toh(hdr->btextsz); + fw->boot.datasz = 0; + + /* Sanity-check firmware header. */ + if (fw->main.textsz > WPI_FW_TEXT_MAXSZ || + fw->main.datasz > WPI_FW_DATA_MAXSZ || + fw->init.textsz > WPI_FW_TEXT_MAXSZ || + fw->init.datasz > WPI_FW_DATA_MAXSZ || + fw->boot.textsz > WPI_FW_BOOT_TEXT_MAXSZ || + (fw->boot.textsz & 3) != 0) { + device_printf(sc->sc_dev, "invalid firmware header\n"); + error = EINVAL; + goto fail; + } + + /* Check that all firmware sections fit. */ + if (fw->size < sizeof (*hdr) + fw->main.textsz + fw->main.datasz + + fw->init.textsz + fw->init.datasz + fw->boot.textsz) { + device_printf(sc->sc_dev, + "firmware file too short: %zu bytes\n", fw->size); + error = EINVAL; + goto fail; + } + + /* Get pointers to firmware sections. */ + fw->main.text = (const uint8_t *)(hdr + 1); + fw->main.data = fw->main.text + fw->main.textsz; + fw->init.text = fw->main.data + fw->main.datasz; + fw->init.data = fw->init.text + fw->init.textsz; + fw->boot.text = fw->init.data + fw->init.datasz; + + DPRINTF(sc, WPI_DEBUG_FIRMWARE, + "Firmware Version: Major %d, Minor %d, Driver %d, \n" + "runtime (text: %u, data: %u) init (text: %u, data %u) boot (text %u)\n", + hdr->major, hdr->minor, le32toh(hdr->driver), + fw->main.textsz, fw->main.datasz, + fw->init.textsz, fw->init.datasz, fw->boot.textsz); + + DPRINTF(sc, WPI_DEBUG_FIRMWARE, "fw->main.text %p\n", fw->main.text); + DPRINTF(sc, WPI_DEBUG_FIRMWARE, "fw->main.data %p\n", fw->main.data); + DPRINTF(sc, WPI_DEBUG_FIRMWARE, "fw->init.text %p\n", fw->init.text); + DPRINTF(sc, WPI_DEBUG_FIRMWARE, "fw->init.data %p\n", fw->init.data); + DPRINTF(sc, WPI_DEBUG_FIRMWARE, "fw->boot.text %p\n", fw->boot.text); + + return 0; + +fail: wpi_unload_firmware(sc); + return error; +} + +/** + * Free the referenced firmware image + */ +static void +wpi_unload_firmware(struct wpi_softc *sc) +{ + if (sc->fw_fp != NULL) { + firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); + sc->fw_fp = NULL; + } +} + +static int +wpi_clock_wait(struct wpi_softc *sc) +{ + int ntries; + + /* Set "initialization complete" bit. */ + WPI_SETBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_INIT_DONE); + + /* Wait for clock stabilization. */ + for (ntries = 0; ntries < 2500; ntries++) { + if (WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_MAC_CLOCK_READY) + return 0; + DELAY(100); + } + device_printf(sc->sc_dev, + "%s: timeout waiting for clock stabilization\n", __func__); + + return ETIMEDOUT; +} + +static int +wpi_apm_init(struct wpi_softc *sc) +{ + uint32_t reg; + int error; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + /* Disable L0s exit timer (NMI bug workaround). */ + WPI_SETBITS(sc, WPI_GIO_CHICKEN, WPI_GIO_CHICKEN_DIS_L0S_TIMER); + /* Don't wait for ICH L0s (ICH bug workaround). */ + WPI_SETBITS(sc, WPI_GIO_CHICKEN, WPI_GIO_CHICKEN_L1A_NO_L0S_RX); + + /* Set FH wait threshold to max (HW bug under stress workaround). */ + WPI_SETBITS(sc, WPI_DBG_HPET_MEM, 0xffff0000); + + /* Retrieve PCIe Active State Power Management (ASPM). */ + reg = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); + /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */ + if (reg & 0x02) /* L1 Entry enabled. */ + WPI_SETBITS(sc, WPI_GIO, WPI_GIO_L0S_ENA); + else + WPI_CLRBITS(sc, WPI_GIO, WPI_GIO_L0S_ENA); + + WPI_SETBITS(sc, WPI_ANA_PLL, WPI_ANA_PLL_INIT); + + /* Wait for clock stabilization before accessing prph. */ + if ((error = wpi_clock_wait(sc)) != 0) + return error; + + if ((error = wpi_nic_lock(sc)) != 0) + return error; + /* Enable DMA and BSM (Bootstrap State Machine). */ + wpi_prph_write(sc, WPI_APMG_CLK_EN, + WPI_APMG_CLK_CTRL_DMA_CLK_RQT | WPI_APMG_CLK_CTRL_BSM_CLK_RQT); + DELAY(20); + /* Disable L1-Active. */ + wpi_prph_setbits(sc, WPI_APMG_PCI_STT, WPI_APMG_PCI_STT_L1A_DIS); + wpi_nic_unlock(sc); + return 0; } static void -wpi_stop_master(struct wpi_softc *sc) +wpi_apm_stop_master(struct wpi_softc *sc) { - uint32_t tmp; int ntries; - DPRINTFN(WPI_DEBUG_HW,("Disabling Firmware execution\n")); - - tmp = WPI_READ(sc, WPI_RESET); - WPI_WRITE(sc, WPI_RESET, tmp | WPI_STOP_MASTER | WPI_NEVO_RESET); - - tmp = WPI_READ(sc, WPI_GPIO_CTL); - if ((tmp & WPI_GPIO_PWR_STATUS) == WPI_GPIO_PWR_SLEEP) - return; /* already asleep */ + /* Stop busmaster DMA activity. */ + WPI_SETBITS(sc, WPI_RESET, WPI_RESET_STOP_MASTER); + + if ((WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_PS_MASK) == + WPI_GP_CNTRL_MAC_PS) + return; /* Already asleep. */ for (ntries = 0; ntries < 100; ntries++) { - if (WPI_READ(sc, WPI_RESET) & WPI_MASTER_DISABLED) - break; + if (WPI_READ(sc, WPI_RESET) & WPI_RESET_MASTER_DISABLED) + return; DELAY(10); } - if (ntries == 100) { - device_printf(sc->sc_dev, "timeout waiting for master\n"); - } + device_printf(sc->sc_dev, "%s: timeout waiting for master\n", __func__); +} + +static void +wpi_apm_stop(struct wpi_softc *sc) +{ + wpi_apm_stop_master(sc); + + /* Reset the entire device. */ + WPI_SETBITS(sc, WPI_RESET, WPI_RESET_SW); + DELAY(10); + /* Clear "initialization complete" bit. */ + WPI_CLRBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_INIT_DONE); +} + +static void +wpi_nic_config(struct wpi_softc *sc) +{ + uint32_t rev; + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + /* voodoo from the Linux "driver".. */ + rev = pci_read_config(sc->sc_dev, PCIR_REVID, 1); + if ((rev & 0xc0) == 0x40) + WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_ALM_MB); + else if (!(rev & 0x80)) + WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_ALM_MM); + + if (sc->cap == 0x80) + WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_SKU_MRC); + + if ((le16toh(sc->rev) & 0xf0) == 0xd0) + WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_REV_D); + else + WPI_CLRBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_REV_D); + + if (sc->type > 1) + WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_TYPE_B); } static int -wpi_power_up(struct wpi_softc *sc) +wpi_hw_init(struct wpi_softc *sc) { - uint32_t tmp; - int ntries; + int chnl, ntries, error; - wpi_mem_lock(sc); - tmp = wpi_mem_read(sc, WPI_MEM_POWER); - wpi_mem_write(sc, WPI_MEM_POWER, tmp & ~0x03000000); - wpi_mem_unlock(sc); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); + /* Clear pending interrupts. */ + WPI_WRITE(sc, WPI_INT, 0xffffffff); + + if ((error = wpi_apm_init(sc)) != 0) { + device_printf(sc->sc_dev, + "%s: could not power ON adapter, error %d\n", __func__, + error); + return error; + } + + /* Select VMAIN power source. */ + if ((error = wpi_nic_lock(sc)) != 0) + return error; + wpi_prph_clrbits(sc, WPI_APMG_PS, WPI_APMG_PS_PWR_SRC_MASK); + wpi_nic_unlock(sc); + /* Spin until VMAIN gets selected. */ for (ntries = 0; ntries < 5000; ntries++) { - if (WPI_READ(sc, WPI_GPIO_STATUS) & WPI_POWERED) + if (WPI_READ(sc, WPI_GPIO_IN) & WPI_GPIO_IN_VMAIN) break; DELAY(10); } if (ntries == 5000) { - device_printf(sc->sc_dev, - "timeout waiting for NIC to power up\n"); - return ETIMEDOUT; - } - return 0; -} - -static int -wpi_reset(struct wpi_softc *sc) -{ - uint32_t tmp; - int ntries; - - DPRINTFN(WPI_DEBUG_HW, - ("Resetting the card - clearing any uploaded firmware\n")); - - /* clear any pending interrupts */ - WPI_WRITE(sc, WPI_INTR, 0xffffffff); - - tmp = WPI_READ(sc, WPI_PLL_CTL); - WPI_WRITE(sc, WPI_PLL_CTL, tmp | WPI_PLL_INIT); - - tmp = WPI_READ(sc, WPI_CHICKEN); - WPI_WRITE(sc, WPI_CHICKEN, tmp | WPI_CHICKEN_RXNOLOS); - - tmp = WPI_READ(sc, WPI_GPIO_CTL); - WPI_WRITE(sc, WPI_GPIO_CTL, tmp | WPI_GPIO_INIT); - - /* wait for clock stabilization */ - for (ntries = 0; ntries < 25000; ntries++) { - if (WPI_READ(sc, WPI_GPIO_CTL) & WPI_GPIO_CLOCK) - break; - DELAY(10); - } - if (ntries == 25000) { - device_printf(sc->sc_dev, - "timeout waiting for clock stabilization\n"); + device_printf(sc->sc_dev, "timeout selecting power source\n"); return ETIMEDOUT; } - /* initialize EEPROM */ - tmp = WPI_READ(sc, WPI_EEPROM_STATUS); + /* Perform adapter initialization. */ + wpi_nic_config(sc); - if ((tmp & WPI_EEPROM_VERSION) == 0) { - device_printf(sc->sc_dev, "EEPROM not found\n"); - return EIO; + /* Initialize RX ring. */ + if ((error = wpi_nic_lock(sc)) != 0) + return error; + /* Set physical address of RX ring. */ + WPI_WRITE(sc, WPI_FH_RX_BASE, sc->rxq.desc_dma.paddr); + /* Set physical address of RX read pointer. */ + WPI_WRITE(sc, WPI_FH_RX_RPTR_ADDR, sc->shared_dma.paddr + + offsetof(struct wpi_shared, next)); + WPI_WRITE(sc, WPI_FH_RX_WPTR, 0); + /* Enable RX. */ + WPI_WRITE(sc, WPI_FH_RX_CONFIG, + WPI_FH_RX_CONFIG_DMA_ENA | + WPI_FH_RX_CONFIG_RDRBD_ENA | + WPI_FH_RX_CONFIG_WRSTATUS_ENA | + WPI_FH_RX_CONFIG_MAXFRAG | + WPI_FH_RX_CONFIG_NRBD(WPI_RX_RING_COUNT_LOG) | + WPI_FH_RX_CONFIG_IRQ_DST_HOST | + WPI_FH_RX_CONFIG_IRQ_TIMEOUT(1)); + (void)WPI_READ(sc, WPI_FH_RSSR_TBL); /* barrier */ + wpi_nic_unlock(sc); + WPI_WRITE(sc, WPI_FH_RX_WPTR, (WPI_RX_RING_COUNT - 1) & ~7); + + /* Initialize TX rings. */ + if ((error = wpi_nic_lock(sc)) != 0) + return error; + wpi_prph_write(sc, WPI_ALM_SCHED_MODE, 2); /* bypass mode */ + wpi_prph_write(sc, WPI_ALM_SCHED_ARASTAT, 1); /* enable RA0 */ + /* Enable all 6 TX rings. */ + wpi_prph_write(sc, WPI_ALM_SCHED_TXFACT, 0x3f); + wpi_prph_write(sc, WPI_ALM_SCHED_SBYPASS_MODE1, 0x10000); + wpi_prph_write(sc, WPI_ALM_SCHED_SBYPASS_MODE2, 0x30002); + wpi_prph_write(sc, WPI_ALM_SCHED_TXF4MF, 4); + wpi_prph_write(sc, WPI_ALM_SCHED_TXF5MF, 5); + /* Set physical address of TX rings. */ + WPI_WRITE(sc, WPI_FH_TX_BASE, sc->shared_dma.paddr); + WPI_WRITE(sc, WPI_FH_MSG_CONFIG, 0xffff05a5); + + /* Enable all DMA channels. */ + for (chnl = 0; chnl < WPI_NDMACHNLS; chnl++) { + WPI_WRITE(sc, WPI_FH_CBBC_CTRL(chnl), 0); + WPI_WRITE(sc, WPI_FH_CBBC_BASE(chnl), 0); + WPI_WRITE(sc, WPI_FH_TX_CONFIG(chnl), 0x80200008); } - WPI_WRITE(sc, WPI_EEPROM_STATUS, tmp & ~WPI_EEPROM_LOCKED); + wpi_nic_unlock(sc); + (void)WPI_READ(sc, WPI_FH_TX_BASE); /* barrier */ - return 0; + /* Clear "radio off" and "commands blocked" bits. */ + WPI_WRITE(sc, WPI_UCODE_GP1_CLR, WPI_UCODE_GP1_RFKILL); + WPI_WRITE(sc, WPI_UCODE_GP1_CLR, WPI_UCODE_GP1_CMD_BLOCKED); + + /* Clear pending interrupts. */ + WPI_WRITE(sc, WPI_INT, 0xffffffff); + /* Enable interrupts. */ + WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); + + /* _Really_ make sure "radio off" bit is cleared! */ + WPI_WRITE(sc, WPI_UCODE_GP1_CLR, WPI_UCODE_GP1_RFKILL); + WPI_WRITE(sc, WPI_UCODE_GP1_CLR, WPI_UCODE_GP1_RFKILL); + + if ((error = wpi_load_firmware(sc)) != 0) { + device_printf(sc->sc_dev, + "%s: could not load firmware, error %d\n", __func__, + error); + return error; + } + /* Wait at most one second for firmware alive notification. */ + if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { + device_printf(sc->sc_dev, + "%s: timeout waiting for adapter to initialize, error %d\n", + __func__, error); + return error; + } + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + /* Do post-firmware initialization. */ + return wpi_post_alive(sc); } static void -wpi_hw_config(struct wpi_softc *sc) +wpi_hw_stop(struct wpi_softc *sc) { - uint32_t rev, hw; + int chnl, qid, ntries; - /* voodoo from the Linux "driver".. */ - hw = WPI_READ(sc, WPI_HWCONFIG); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); - rev = pci_read_config(sc->sc_dev, PCIR_REVID, 1); - if ((rev & 0xc0) == 0x40) - hw |= WPI_HW_ALM_MB; - else if (!(rev & 0x80)) - hw |= WPI_HW_ALM_MM; + if (WPI_READ(sc, WPI_UCODE_GP1) & WPI_UCODE_GP1_MAC_SLEEP) + wpi_nic_lock(sc); - if (sc->cap == 0x80) - hw |= WPI_HW_SKU_MRC; + WPI_WRITE(sc, WPI_RESET, WPI_RESET_NEVO); - hw &= ~WPI_HW_REV_D; - if ((le16toh(sc->rev) & 0xf0) == 0xd0) - hw |= WPI_HW_REV_D; + /* Disable interrupts. */ + WPI_WRITE(sc, WPI_INT_MASK, 0); + WPI_WRITE(sc, WPI_INT, 0xffffffff); + WPI_WRITE(sc, WPI_FH_INT, 0xffffffff); - if (sc->type > 1) - hw |= WPI_HW_TYPE_B; + /* Make sure we no longer hold the NIC lock. */ + wpi_nic_unlock(sc); - WPI_WRITE(sc, WPI_HWCONFIG, hw); + if (wpi_nic_lock(sc) == 0) { + /* Stop TX scheduler. */ + wpi_prph_write(sc, WPI_ALM_SCHED_MODE, 0); + wpi_prph_write(sc, WPI_ALM_SCHED_TXFACT, 0); + + /* Stop all DMA channels. */ + for (chnl = 0; chnl < WPI_NDMACHNLS; chnl++) { + WPI_WRITE(sc, WPI_FH_TX_CONFIG(chnl), 0); + for (ntries = 0; ntries < 200; ntries++) { + if (WPI_READ(sc, WPI_FH_TX_STATUS) & + WPI_FH_TX_STATUS_IDLE(chnl)) + break; + DELAY(10); + } + } + wpi_nic_unlock(sc); + } + + /* Stop RX ring. */ + wpi_reset_rx_ring(sc); + + /* Reset all TX rings. */ + for (qid = 0; qid < WPI_NTXQUEUES; qid++) + wpi_reset_tx_ring(sc, &sc->txq[qid]); + + if (wpi_nic_lock(sc) == 0) { + wpi_prph_write(sc, WPI_APMG_CLK_DIS, + WPI_APMG_CLK_CTRL_DMA_CLK_RQT); + wpi_nic_unlock(sc); + } + DELAY(5); + /* Power OFF adapter. */ + wpi_apm_stop(sc); } static void -wpi_rfkill_resume(struct wpi_softc *sc) +wpi_radio_on(void *arg0, int pending) { + struct wpi_softc *sc = arg0; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - int ntries; - /* enable firmware again */ - WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); - WPI_WRITE(sc, WPI_UCODE_CLR, WPI_DISABLE_CMD); - - /* wait for thermal sensors to calibrate */ - for (ntries = 0; ntries < 1000; ntries++) { - if ((sc->temp = (int)WPI_READ(sc, WPI_TEMPERATURE)) != 0) - break; - DELAY(10); - } - - if (ntries == 1000) { - device_printf(sc->sc_dev, - "timeout waiting for thermal calibration\n"); - return; - } - DPRINTFN(WPI_DEBUG_TEMP,("temperature %d\n", sc->temp)); - - if (wpi_config(sc) != 0) { - device_printf(sc->sc_dev, "device config failed\n"); - return; - } - - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - ifp->if_drv_flags |= IFF_DRV_RUNNING; - sc->flags &= ~WPI_FLAG_HW_RADIO_OFF; + device_printf(sc->sc_dev, "RF switch: radio enabled\n"); if (vap != NULL) { - if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { - if (vap->iv_opmode != IEEE80211_M_MONITOR) { - ieee80211_beacon_miss(ic); - wpi_set_led(sc, WPI_LED_LINK, 0, 1); - } else - wpi_set_led(sc, WPI_LED_LINK, 5, 5); - } else { - ieee80211_scan_next(vap); - wpi_set_led(sc, WPI_LED_LINK, 20, 2); - } + wpi_init(sc); + ieee80211_init(vap); } - callout_reset(&sc->watchdog_to, hz, wpi_watchdog, sc); + if (WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL) { + WPI_LOCK(sc); + callout_stop(&sc->watchdog_rfkill); + WPI_UNLOCK(sc); + } } static void -wpi_init_locked(struct wpi_softc *sc, int force) +wpi_radio_off(void *arg0, int pending) +{ + struct wpi_softc *sc = arg0; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + + device_printf(sc->sc_dev, "RF switch: radio disabled\n"); + + wpi_stop(sc); + if (vap != NULL) + ieee80211_stop(vap); + + callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, sc); +} + +static void +wpi_init_locked(struct wpi_softc *sc) { struct ifnet *ifp = sc->sc_ifp; - uint32_t tmp; - int ntries, qid; + int error; - wpi_stop_locked(sc); - (void)wpi_reset(sc); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); - wpi_mem_lock(sc); - wpi_mem_write(sc, WPI_MEM_CLOCK1, 0xa00); - DELAY(20); - tmp = wpi_mem_read(sc, WPI_MEM_PCIDEV); - wpi_mem_write(sc, WPI_MEM_PCIDEV, tmp | 0x800); - wpi_mem_unlock(sc); + WPI_LOCK_ASSERT(sc); - (void)wpi_power_up(sc); - wpi_hw_config(sc); - - /* init Rx ring */ - wpi_mem_lock(sc); - WPI_WRITE(sc, WPI_RX_BASE, sc->rxq.desc_dma.paddr); - WPI_WRITE(sc, WPI_RX_RIDX_PTR, sc->shared_dma.paddr + - offsetof(struct wpi_shared, next)); - WPI_WRITE(sc, WPI_RX_WIDX, (WPI_RX_RING_COUNT - 1) & ~7); - WPI_WRITE(sc, WPI_RX_CONFIG, 0xa9601010); - wpi_mem_unlock(sc); - - /* init Tx rings */ - wpi_mem_lock(sc); - wpi_mem_write(sc, WPI_MEM_MODE, 2); /* bypass mode */ - wpi_mem_write(sc, WPI_MEM_RA, 1); /* enable RA0 */ - wpi_mem_write(sc, WPI_MEM_TXCFG, 0x3f); /* enable all 6 Tx rings */ - wpi_mem_write(sc, WPI_MEM_BYPASS1, 0x10000); - wpi_mem_write(sc, WPI_MEM_BYPASS2, 0x30002); - wpi_mem_write(sc, WPI_MEM_MAGIC4, 4); - wpi_mem_write(sc, WPI_MEM_MAGIC5, 5); - - WPI_WRITE(sc, WPI_TX_BASE_PTR, sc->shared_dma.paddr); - WPI_WRITE(sc, WPI_MSG_CONFIG, 0xffff05a5); - - for (qid = 0; qid < 6; qid++) { - WPI_WRITE(sc, WPI_TX_CTL(qid), 0); - WPI_WRITE(sc, WPI_TX_BASE(qid), 0); - WPI_WRITE(sc, WPI_TX_CONFIG(qid), 0x80200008); - } - wpi_mem_unlock(sc); - - /* clear "radio off" and "disable command" bits (reversed logic) */ - WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); - WPI_WRITE(sc, WPI_UCODE_CLR, WPI_DISABLE_CMD); - sc->flags &= ~WPI_FLAG_HW_RADIO_OFF; - - /* clear any pending interrupts */ - WPI_WRITE(sc, WPI_INTR, 0xffffffff); - - /* enable interrupts */ - WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK); - - WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); - WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); - - if ((wpi_load_firmware(sc)) != 0) { - device_printf(sc->sc_dev, - "A problem occurred loading the firmware to the driver\n"); - return; - } - - /* At this point the firmware is up and running. If the hardware - * RF switch is turned off thermal calibration will fail, though - * the card is still happy to continue to accept commands, catch - * this case and schedule a task to watch for it to be turned on. - */ - wpi_mem_lock(sc); - tmp = wpi_mem_read(sc, WPI_MEM_HW_RADIO_OFF); - wpi_mem_unlock(sc); - - if (!(tmp & 0x1)) { - sc->flags |= WPI_FLAG_HW_RADIO_OFF; - device_printf(sc->sc_dev,"Radio Transmitter is switched off\n"); - goto out; - } - - /* wait for thermal sensors to calibrate */ - for (ntries = 0; ntries < 1000; ntries++) { - if ((sc->temp = (int)WPI_READ(sc, WPI_TEMPERATURE)) != 0) - break; - DELAY(10); - } - - if (ntries == 1000) { + /* Check that the radio is not disabled by hardware switch. */ + if (!(WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL)) { device_printf(sc->sc_dev, - "timeout waiting for thermal sensors calibration\n"); + "RF switch: radio disabled (%s)\n", __func__); + callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, + sc); return; } - DPRINTFN(WPI_DEBUG_TEMP,("temperature %d\n", sc->temp)); - if (wpi_config(sc) != 0) { - device_printf(sc->sc_dev, "device config failed\n"); - return; + /* Read firmware images from the filesystem. */ + if ((error = wpi_read_firmware(sc)) != 0) { + device_printf(sc->sc_dev, + "%s: could not read firmware, error %d\n", __func__, + error); + goto fail; + } + + /* Initialize hardware and upload firmware. */ + error = wpi_hw_init(sc); + wpi_unload_firmware(sc); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not initialize hardware, error %d\n", __func__, + error); + goto fail; + } + + /* Configure adapter now that it is ready. */ + if ((error = wpi_config(sc)) != 0) { + device_printf(sc->sc_dev, + "%s: could not configure device, error %d\n", __func__, + error); + goto fail; } ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_RUNNING; -out: + callout_reset(&sc->watchdog_to, hz, wpi_watchdog, sc); + + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); + + return; + +fail: wpi_stop_locked(sc); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); } static void @@ -3147,56 +4722,28 @@ wpi_init(void *arg) struct ieee80211com *ic = ifp->if_l2com; WPI_LOCK(sc); - wpi_init_locked(sc, 0); + wpi_init_locked(sc); WPI_UNLOCK(sc); if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ieee80211_start_all(ic); /* start all vaps */ + ieee80211_start_all(ic); } static void wpi_stop_locked(struct wpi_softc *sc) { struct ifnet *ifp = sc->sc_ifp; - uint32_t tmp; - int ac; - sc->sc_tx_timer = 0; + WPI_LOCK_ASSERT(sc); + sc->sc_scan_timer = 0; - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - sc->flags &= ~WPI_FLAG_HW_RADIO_OFF; + sc->sc_tx_timer = 0; callout_stop(&sc->watchdog_to); callout_stop(&sc->calib_to); + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - /* disable interrupts */ - WPI_WRITE(sc, WPI_MASK, 0); - WPI_WRITE(sc, WPI_INTR, WPI_INTR_MASK); - WPI_WRITE(sc, WPI_INTR_STATUS, 0xff); - WPI_WRITE(sc, WPI_INTR_STATUS, 0x00070000); - - wpi_mem_lock(sc); - wpi_mem_write(sc, WPI_MEM_MODE, 0); - wpi_mem_unlock(sc); - - /* reset all Tx rings */ - for (ac = 0; ac < 4; ac++) - wpi_reset_tx_ring(sc, &sc->txq[ac]); - wpi_reset_tx_ring(sc, &sc->cmdq); - - /* reset Rx ring */ - wpi_reset_rx_ring(sc, &sc->rxq); - - wpi_mem_lock(sc); - wpi_mem_write(sc, WPI_MEM_CLOCK2, 0x200); - wpi_mem_unlock(sc); - - DELAY(5); - - wpi_stop_master(sc); - - tmp = WPI_READ(sc, WPI_RESET); - WPI_WRITE(sc, WPI_RESET, tmp | WPI_SW_RESET); - sc->flags &= ~WPI_FLAG_BUSY; + /* Power OFF hardware. */ + wpi_hw_stop(sc); } static void @@ -3207,300 +4754,8 @@ wpi_stop(struct wpi_softc *sc) WPI_UNLOCK(sc); } -static void -wpi_calib_timeout(void *arg) -{ - struct wpi_softc *sc = arg; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - int temp; - - if (vap->iv_state != IEEE80211_S_RUN) - return; - - /* update sensor data */ - temp = (int)WPI_READ(sc, WPI_TEMPERATURE); - DPRINTFN(WPI_DEBUG_TEMP,("Temp in calibration is: %d\n", temp)); - - wpi_power_calibration(sc, temp); - - callout_reset(&sc->calib_to, 60*hz, wpi_calib_timeout, sc); -} - /* - * This function is called periodically (every 60 seconds) to adjust output - * power to temperature changes. - */ -static void -wpi_power_calibration(struct wpi_softc *sc, int temp) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - /* sanity-check read value */ - if (temp < -260 || temp > 25) { - /* this can't be correct, ignore */ - DPRINTFN(WPI_DEBUG_TEMP, - ("out-of-range temperature reported: %d\n", temp)); - return; - } - - DPRINTFN(WPI_DEBUG_TEMP,("temperature %d->%d\n", sc->temp, temp)); - - /* adjust Tx power if need be */ - if (abs(temp - sc->temp) <= 6) - return; - - sc->temp = temp; - - if (wpi_set_txpower(sc, vap->iv_bss->ni_chan, 1) != 0) { - /* just warn, too bad for the automatic calibration... */ - device_printf(sc->sc_dev,"could not adjust Tx power\n"); - } -} - -/** - * Read the eeprom to find out what channels are valid for the given - * band and update net80211 with what we find. - */ -static void -wpi_read_eeprom_channels(struct wpi_softc *sc, int n) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - const struct wpi_chan_band *band = &wpi_bands[n]; - struct wpi_eeprom_chan channels[WPI_MAX_CHAN_PER_BAND]; - struct ieee80211_channel *c; - int chan, i, passive; - - wpi_read_prom_data(sc, band->addr, channels, - band->nchan * sizeof (struct wpi_eeprom_chan)); - - for (i = 0; i < band->nchan; i++) { - if (!(channels[i].flags & WPI_EEPROM_CHAN_VALID)) { - DPRINTFN(WPI_DEBUG_HW, - ("Channel Not Valid: %d, band %d\n", - band->chan[i],n)); - continue; - } - - passive = 0; - chan = band->chan[i]; - c = &ic->ic_channels[ic->ic_nchans++]; - - /* is active scan allowed on this channel? */ - if (!(channels[i].flags & WPI_EEPROM_CHAN_ACTIVE)) { - passive = IEEE80211_CHAN_PASSIVE; - } - - if (n == 0) { /* 2GHz band */ - c->ic_ieee = chan; - c->ic_freq = ieee80211_ieee2mhz(chan, - IEEE80211_CHAN_2GHZ); - c->ic_flags = IEEE80211_CHAN_B | passive; - - c = &ic->ic_channels[ic->ic_nchans++]; - c->ic_ieee = chan; - c->ic_freq = ieee80211_ieee2mhz(chan, - IEEE80211_CHAN_2GHZ); - c->ic_flags = IEEE80211_CHAN_G | passive; - - } else { /* 5GHz band */ - /* - * Some 3945ABG adapters support channels 7, 8, 11 - * and 12 in the 2GHz *and* 5GHz bands. - * Because of limitations in our net80211(9) stack, - * we can't support these channels in 5GHz band. - * XXX not true; just need to map to proper frequency - */ - if (chan <= 14) - continue; - - c->ic_ieee = chan; - c->ic_freq = ieee80211_ieee2mhz(chan, - IEEE80211_CHAN_5GHZ); - c->ic_flags = IEEE80211_CHAN_A | passive; - } - - /* save maximum allowed power for this channel */ - sc->maxpwr[chan] = channels[i].maxpwr; - -#if 0 - // XXX We can probably use this an get rid of maxpwr - ben 20070617 - ic->ic_channels[chan].ic_maxpower = channels[i].maxpwr; - //ic->ic_channels[chan].ic_minpower... - //ic->ic_channels[chan].ic_maxregtxpower... -#endif - - DPRINTF(("adding chan %d (%dMHz) flags=0x%x maxpwr=%d" - " passive=%d, offset %d\n", chan, c->ic_freq, - channels[i].flags, sc->maxpwr[chan], - (c->ic_flags & IEEE80211_CHAN_PASSIVE) != 0, - ic->ic_nchans)); - } -} - -static void -wpi_read_eeprom_group(struct wpi_softc *sc, int n) -{ - struct wpi_power_group *group = &sc->groups[n]; - struct wpi_eeprom_group rgroup; - int i; - - wpi_read_prom_data(sc, WPI_EEPROM_POWER_GRP + n * 32, &rgroup, - sizeof rgroup); - - /* save power group information */ - group->chan = rgroup.chan; - group->maxpwr = rgroup.maxpwr; - /* temperature at which the samples were taken */ - group->temp = (int16_t)le16toh(rgroup.temp); - - DPRINTF(("power group %d: chan=%d maxpwr=%d temp=%d\n", n, - group->chan, group->maxpwr, group->temp)); - - for (i = 0; i < WPI_SAMPLES_COUNT; i++) { - group->samples[i].index = rgroup.samples[i].index; - group->samples[i].power = rgroup.samples[i].power; - - DPRINTF(("\tsample %d: index=%d power=%d\n", i, - group->samples[i].index, group->samples[i].power)); - } -} - -/* - * Update Tx power to match what is defined for channel `c'. - */ -static int -wpi_set_txpower(struct wpi_softc *sc, struct ieee80211_channel *c, int async) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct wpi_power_group *group; - struct wpi_cmd_txpower txpower; - u_int chan; - int i; - - /* get channel number */ - chan = ieee80211_chan2ieee(ic, c); - - /* find the power group to which this channel belongs */ - if (IEEE80211_IS_CHAN_5GHZ(c)) { - for (group = &sc->groups[1]; group < &sc->groups[4]; group++) - if (chan <= group->chan) - break; - } else - group = &sc->groups[0]; - - memset(&txpower, 0, sizeof txpower); - txpower.band = IEEE80211_IS_CHAN_5GHZ(c) ? 0 : 1; - txpower.channel = htole16(chan); - - /* set Tx power for all OFDM and CCK rates */ - for (i = 0; i <= 11 ; i++) { - /* retrieve Tx power for this channel/rate combination */ - int idx = wpi_get_power_index(sc, group, c, - wpi_ridx_to_rate[i]); - - txpower.rates[i].rate = wpi_ridx_to_plcp[i]; - - if (IEEE80211_IS_CHAN_5GHZ(c)) { - txpower.rates[i].gain_radio = wpi_rf_gain_5ghz[idx]; - txpower.rates[i].gain_dsp = wpi_dsp_gain_5ghz[idx]; - } else { - txpower.rates[i].gain_radio = wpi_rf_gain_2ghz[idx]; - txpower.rates[i].gain_dsp = wpi_dsp_gain_2ghz[idx]; - } - DPRINTFN(WPI_DEBUG_TEMP,("chan %d/rate %d: power index %d\n", - chan, wpi_ridx_to_rate[i], idx)); - } - - return wpi_cmd(sc, WPI_CMD_TXPOWER, &txpower, sizeof txpower, async); -} - -/* - * Determine Tx power index for a given channel/rate combination. - * This takes into account the regulatory information from EEPROM and the - * current temperature. - */ -static int -wpi_get_power_index(struct wpi_softc *sc, struct wpi_power_group *group, - struct ieee80211_channel *c, int rate) -{ -/* fixed-point arithmetic division using a n-bit fractional part */ -#define fdivround(a, b, n) \ - ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n)) - -/* linear interpolation */ -#define interpolate(x, x1, y1, x2, y2, n) \ - ((y1) + fdivround(((x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n)) - - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct wpi_power_sample *sample; - int pwr, idx; - u_int chan; - - /* get channel number */ - chan = ieee80211_chan2ieee(ic, c); - - /* default power is group's maximum power - 3dB */ - pwr = group->maxpwr / 2; - - /* decrease power for highest OFDM rates to reduce distortion */ - switch (rate) { - case 72: /* 36Mb/s */ - pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 0 : 5; - break; - case 96: /* 48Mb/s */ - pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 7 : 10; - break; - case 108: /* 54Mb/s */ - pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 9 : 12; - break; - } - - /* never exceed channel's maximum allowed Tx power */ - pwr = min(pwr, sc->maxpwr[chan]); - - /* retrieve power index into gain tables from samples */ - for (sample = group->samples; sample < &group->samples[3]; sample++) - if (pwr > sample[1].power) - break; - /* fixed-point linear interpolation using a 19-bit fractional part */ - idx = interpolate(pwr, sample[0].power, sample[0].index, - sample[1].power, sample[1].index, 19); - - /* - * Adjust power index based on current temperature - * - if colder than factory-calibrated: decreate output power - * - if warmer than factory-calibrated: increase output power - */ - idx -= (sc->temp - group->temp) * 11 / 100; - - /* decrease power for CCK rates (-5dB) */ - if (!WPI_RATE_IS_OFDM(rate)) - idx += 10; - - /* keep power index in a valid range */ - if (idx < 0) - return 0; - if (idx > WPI_MAX_PWR_INDEX) - return WPI_MAX_PWR_INDEX; - return idx; - -#undef interpolate -#undef fdivround -} - -/** - * Called by net80211 framework to indicate that a scan - * is starting. This function doesn't actually do the scan, - * wpi_scan_curchan starts things off. This function is more - * of an early warning from the framework we should get ready - * for the scan. + * Callback from net80211 to start a scan. */ static void wpi_scan_start(struct ieee80211com *ic) @@ -3513,15 +4768,21 @@ wpi_scan_start(struct ieee80211com *ic) WPI_UNLOCK(sc); } -/** - * Called by the net80211 framework, indicates that the - * scan has ended. If there is a scan in progress on the card - * then it should be aborted. +/* + * Callback from net80211 to terminate a scan. */ static void wpi_scan_end(struct ieee80211com *ic) { - /* XXX ignore */ + struct ifnet *ifp = ic->ic_ifp; + struct wpi_softc *sc = ifp->if_softc; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + + if (vap->iv_state == IEEE80211_S_RUN) { + WPI_LOCK(sc); + wpi_set_led(sc, WPI_LED_LINK, 0, 1); + WPI_UNLOCK(sc); + } } /** @@ -3531,22 +4792,38 @@ wpi_scan_end(struct ieee80211com *ic) static void wpi_set_channel(struct ieee80211com *ic) { + const struct ieee80211_channel *c = ic->ic_curchan; struct ifnet *ifp = ic->ic_ifp; struct wpi_softc *sc = ifp->if_softc; int error; + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); + + WPI_LOCK(sc); + sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); + sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); + sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); + sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags); + /* * Only need to set the channel in Monitor mode. AP scanning and auth * are already taken care of by their respective firmware commands. */ if (ic->ic_opmode == IEEE80211_M_MONITOR) { - WPI_LOCK(sc); - error = wpi_config(sc); - WPI_UNLOCK(sc); - if (error != 0) + sc->rxon.chan = ieee80211_chan2ieee(ic, c); + if (IEEE80211_IS_CHAN_2GHZ(c)) { + sc->rxon.flags |= htole32(WPI_RXON_AUTO | + WPI_RXON_24GHZ); + } else { + sc->rxon.flags &= ~htole32(WPI_RXON_AUTO | + WPI_RXON_24GHZ); + } + if ((error = wpi_send_rxon(sc, 0, 0)) != 0) device_printf(sc->sc_dev, - "error %d settting channel\n", error); + "%s: error %d settting channel\n", __func__, + error); } + WPI_UNLOCK(sc); } /** @@ -3558,13 +4835,21 @@ static void wpi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) { struct ieee80211vap *vap = ss->ss_vap; - struct ifnet *ifp = vap->iv_ic->ic_ifp; + struct ieee80211com *ic = vap->iv_ic; + struct ifnet *ifp = ic->ic_ifp; struct wpi_softc *sc = ifp->if_softc; + int error; - WPI_LOCK(sc); - if (wpi_scan(sc)) - ieee80211_cancel_scan(vap); - WPI_UNLOCK(sc); + if (sc->rxon.chan != ieee80211_chan2ieee(ic, ic->ic_curchan)) { + WPI_LOCK(sc); + error = wpi_scan(sc, ic->ic_curchan); + WPI_UNLOCK(sc); + if (error != 0) + ieee80211_cancel_scan(vap); + } else { + /* Send probe request when associated. */ + sc->sc_scan_curchan(ss, maxdwell); + } } /** @@ -3580,118 +4865,19 @@ wpi_scan_mindwell(struct ieee80211_scan_state *ss) } static void -wpi_hwreset(void *arg, int pending) -{ - struct wpi_softc *sc = arg; - - WPI_LOCK(sc); - wpi_init_locked(sc, 0); - WPI_UNLOCK(sc); -} - -static void -wpi_rfreset(void *arg, int pending) -{ - struct wpi_softc *sc = arg; - - WPI_LOCK(sc); - wpi_rfkill_resume(sc); - WPI_UNLOCK(sc); -} - -/* - * Allocate DMA-safe memory for firmware transfer. - */ -static int -wpi_alloc_fwmem(struct wpi_softc *sc) -{ - /* allocate enough contiguous space to store text and data */ - return wpi_dma_contig_alloc(sc, &sc->fw_dma, NULL, - WPI_FW_MAIN_TEXT_MAXSZ + WPI_FW_MAIN_DATA_MAXSZ, 1, - BUS_DMA_NOWAIT); -} - -static void -wpi_free_fwmem(struct wpi_softc *sc) -{ - wpi_dma_contig_free(&sc->fw_dma); -} - -/** - * Called every second, wpi_watchdog used by the watch dog timer - * to check that the card is still alive - */ -static void -wpi_watchdog(void *arg) +wpi_hw_reset(void *arg, int pending) { struct wpi_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - uint32_t tmp; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - DPRINTFN(WPI_DEBUG_WATCHDOG,("Watchdog: tick\n")); + DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); - if (sc->flags & WPI_FLAG_HW_RADIO_OFF) { - /* No need to lock firmware memory */ - tmp = wpi_mem_read(sc, WPI_MEM_HW_RADIO_OFF); - - if ((tmp & 0x1) == 0) { - /* Radio kill switch is still off */ - callout_reset(&sc->watchdog_to, hz, wpi_watchdog, sc); - return; - } - - device_printf(sc->sc_dev, "Hardware Switch Enabled\n"); - ieee80211_runtask(ic, &sc->sc_radiotask); - return; - } - - if (sc->sc_tx_timer > 0) { - if (--sc->sc_tx_timer == 0) { - device_printf(sc->sc_dev,"device timeout\n"); - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - ieee80211_runtask(ic, &sc->sc_restarttask); - } - } - if (sc->sc_scan_timer > 0) { - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - if (--sc->sc_scan_timer == 0 && vap != NULL) { - device_printf(sc->sc_dev,"scan timeout\n"); - ieee80211_cancel_scan(vap); - ieee80211_runtask(ic, &sc->sc_restarttask); - } - } - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - callout_reset(&sc->watchdog_to, hz, wpi_watchdog, sc); + wpi_stop(sc); + if (vap != NULL) + ieee80211_stop(vap); + wpi_init(sc); + if (vap != NULL) + ieee80211_init(vap); } - -#ifdef WPI_DEBUG -static const char *wpi_cmd_str(int cmd) -{ - switch (cmd) { - case WPI_DISABLE_CMD: return "WPI_DISABLE_CMD"; - case WPI_CMD_CONFIGURE: return "WPI_CMD_CONFIGURE"; - case WPI_CMD_ASSOCIATE: return "WPI_CMD_ASSOCIATE"; - case WPI_CMD_SET_WME: return "WPI_CMD_SET_WME"; - case WPI_CMD_TSF: return "WPI_CMD_TSF"; - case WPI_CMD_ADD_NODE: return "WPI_CMD_ADD_NODE"; - case WPI_CMD_TX_DATA: return "WPI_CMD_TX_DATA"; - case WPI_CMD_MRR_SETUP: return "WPI_CMD_MRR_SETUP"; - case WPI_CMD_SET_LED: return "WPI_CMD_SET_LED"; - case WPI_CMD_SET_POWER_MODE: return "WPI_CMD_SET_POWER_MODE"; - case WPI_CMD_SCAN: return "WPI_CMD_SCAN"; - case WPI_CMD_SET_BEACON:return "WPI_CMD_SET_BEACON"; - case WPI_CMD_TXPOWER: return "WPI_CMD_TXPOWER"; - case WPI_CMD_BLUETOOTH: return "WPI_CMD_BLUETOOTH"; - - default: - KASSERT(1, ("Unknown Command: %d\n", cmd)); - return "UNKNOWN CMD"; /* Make the compiler happy */ - } -} -#endif - -MODULE_DEPEND(wpi, pci, 1, 1, 1); -MODULE_DEPEND(wpi, wlan, 1, 1, 1); -MODULE_DEPEND(wpi, firmware, 1, 1, 1); diff --git a/sys/dev/wpi/if_wpi_debug.h b/sys/dev/wpi/if_wpi_debug.h new file mode 100644 index 000000000000..91a7383e348d --- /dev/null +++ b/sys/dev/wpi/if_wpi_debug.h @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2006,2007 + * Damien Bergamini + * Benjamin Close + * + * Permission to use, copy, modify, and 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. + * + * $FreeBSD$ + */ + +#ifndef __IF_WPI_DEBUG_H__ +#define __IF_WPI_DEBUG_H__ + +#ifdef WPI_DEBUG +enum { + WPI_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ + WPI_DEBUG_RECV = 0x00000002, /* basic recv operation */ + WPI_DEBUG_STATE = 0x00000004, /* 802.11 state transitions */ + WPI_DEBUG_HW = 0x00000008, /* Stage 1 (eeprom) debugging */ + WPI_DEBUG_RESET = 0x00000010, /* reset processing */ + WPI_DEBUG_FIRMWARE = 0x00000020, /* firmware(9) loading debug */ + WPI_DEBUG_BEACON = 0x00000040, /* beacon handling */ + WPI_DEBUG_WATCHDOG = 0x00000080, /* watchdog timeout */ + WPI_DEBUG_INTR = 0x00000100, /* ISR */ + WPI_DEBUG_SCAN = 0x00000200, /* Scan related operations */ + WPI_DEBUG_NOTIFY = 0x00000400, /* State 2 Notif intr debug */ + WPI_DEBUG_TEMP = 0x00000800, /* TXPower/Temp Calibration */ + WPI_DEBUG_CMD = 0x00001000, /* cmd submission */ + WPI_DEBUG_TRACE = 0x00002000, /* Print begin and start driver function */ + WPI_DEBUG_PWRSAVE = 0x00004000, /* Power save operations */ + WPI_DEBUG_EEPROM = 0x00008000, /* EEPROM info */ + WPI_DEBUG_KEY = 0x00010000, /* node key management */ + WPI_DEBUG_EDCA = 0x00020000, /* WME info */ + WPI_DEBUG_ANY = 0xffffffff +}; + +#define DPRINTF(sc, m, ...) do { \ + if (sc->sc_debug & (m)) \ + printf(__VA_ARGS__); \ +} while (0) + +#define TRACE_STR_BEGIN "->%s: begin\n" +#define TRACE_STR_DOING "->Doing %s\n" +#define TRACE_STR_END "->%s: end\n" +#define TRACE_STR_END_ERR "->%s: end in error\n" + +static const char *wpi_cmd_str(int cmd) +{ + switch (cmd) { + /* Notifications */ + case WPI_UC_READY: return "UC_READY"; + case WPI_RX_DONE: return "RX_DONE"; + case WPI_START_SCAN: return "START_SCAN"; + case WPI_SCAN_RESULTS: return "SCAN_RESULTS"; + case WPI_STOP_SCAN: return "STOP_SCAN"; + case WPI_BEACON_SENT: return "BEACON_SENT"; + case WPI_RX_STATISTICS: return "RX_STATS"; + case WPI_BEACON_STATISTICS: return "BEACON_STATS"; + case WPI_STATE_CHANGED: return "STATE_CHANGED"; + case WPI_BEACON_MISSED: return "BEACON_MISSED"; + + /* Command notifications */ + case WPI_CMD_RXON: return "WPI_CMD_RXON"; + case WPI_CMD_RXON_ASSOC: return "WPI_CMD_RXON_ASSOC"; + case WPI_CMD_EDCA_PARAMS: return "WPI_CMD_EDCA_PARAMS"; + case WPI_CMD_TIMING: return "WPI_CMD_TIMING"; + case WPI_CMD_ADD_NODE: return "WPI_CMD_ADD_NODE"; + case WPI_CMD_DEL_NODE: return "WPI_CMD_DEL_NODE"; + case WPI_CMD_TX_DATA: return "WPI_CMD_TX_DATA"; + case WPI_CMD_MRR_SETUP: return "WPI_CMD_MRR_SETUP"; + case WPI_CMD_SET_LED: return "WPI_CMD_SET_LED"; + case WPI_CMD_SET_POWER_MODE: return "WPI_CMD_SET_POWER_MODE"; + case WPI_CMD_SCAN: return "WPI_CMD_SCAN"; + case WPI_CMD_SET_BEACON: return "WPI_CMD_SET_BEACON"; + case WPI_CMD_TXPOWER: return "WPI_CMD_TXPOWER"; + case WPI_CMD_BT_COEX: return "WPI_CMD_BT_COEX"; + + default: + KASSERT(1, ("Unknown Command: %d\n", cmd)); + return "UNKNOWN CMD"; + } +} + +#else +#define DPRINTF(sc, m, ...) do { (void) sc; } while (0) +#endif + +#endif /* __IF_WPI_DEBUG_H__ */ diff --git a/sys/dev/wpi/if_wpireg.h b/sys/dev/wpi/if_wpireg.h index 60d183a6736b..cfd8a09ad282 100644 --- a/sys/dev/wpi/if_wpireg.h +++ b/sys/dev/wpi/if_wpireg.h @@ -18,155 +18,207 @@ */ #define WPI_TX_RING_COUNT 256 -#define WPI_CMD_RING_COUNT 256 -#define WPI_RX_RING_COUNT 64 +#define WPI_TX_RING_LOMARK 192 +#define WPI_TX_RING_HIMARK 224 +#define WPI_RX_RING_COUNT_LOG 6 +#define WPI_RX_RING_COUNT (1 << WPI_RX_RING_COUNT_LOG) + +#define WPI_NTXQUEUES 8 +#define WPI_NDMACHNLS 6 + +/* Maximum scatter/gather. */ +#define WPI_MAX_SCATTER 4 /* * Rings must be aligned on a 16K boundary. */ #define WPI_RING_DMA_ALIGN 0x4000 -/* maximum scatter/gather */ -#define WPI_MAX_SCATTER 4 - -/* maximum Rx buffer size */ +/* Maximum Rx buffer size. */ #define WPI_RBUF_SIZE ( 3 * 1024 ) /* XXX 3000 but must be aligned */ /* * Control and status registers. */ -#define WPI_HWCONFIG 0x000 -#define WPI_INTR 0x008 -#define WPI_MASK 0x00c -#define WPI_INTR_STATUS 0x010 -#define WPI_GPIO_STATUS 0x018 +#define WPI_HW_IF_CONFIG 0x000 +#define WPI_INT 0x008 +#define WPI_INT_MASK 0x00c +#define WPI_FH_INT 0x010 +#define WPI_GPIO_IN 0x018 #define WPI_RESET 0x020 -#define WPI_GPIO_CTL 0x024 -#define WPI_EEPROM_CTL 0x02c -#define WPI_EEPROM_STATUS 0x030 -#define WPI_UCODE_SET 0x058 -#define WPI_UCODE_CLR 0x05c -#define WPI_TEMPERATURE 0x060 -#define WPI_CHICKEN 0x100 -#define WPI_PLL_CTL 0x20c -#define WPI_WRITE_MEM_ADDR 0x444 -#define WPI_READ_MEM_ADDR 0x448 -#define WPI_WRITE_MEM_DATA 0x44c -#define WPI_READ_MEM_DATA 0x450 -#define WPI_TX_WIDX 0x460 -#define WPI_TX_CTL(qid) (0x940 + (qid) * 8) -#define WPI_TX_BASE(qid) (0x944 + (qid) * 8) -#define WPI_TX_DESC(qid) (0x980 + (qid) * 80) -#define WPI_RX_CONFIG 0xc00 -#define WPI_RX_BASE 0xc04 -#define WPI_RX_WIDX 0xc20 -#define WPI_RX_RIDX_PTR 0xc24 -#define WPI_RX_CTL 0xcc0 -#define WPI_RX_STATUS 0xcc4 -#define WPI_TX_CONFIG(qid) (0xd00 + (qid) * 32) -#define WPI_TX_CREDIT(qid) (0xd04 + (qid) * 32) -#define WPI_TX_STATE(qid) (0xd08 + (qid) * 32) -#define WPI_TX_BASE_PTR 0xe80 -#define WPI_MSG_CONFIG 0xe88 -#define WPI_TX_STATUS 0xe90 +#define WPI_GP_CNTRL 0x024 +#define WPI_EEPROM 0x02c +#define WPI_EEPROM_GP 0x030 +#define WPI_GIO 0x03c +#define WPI_UCODE_GP1 0x054 +#define WPI_UCODE_GP1_SET 0x058 +#define WPI_UCODE_GP1_CLR 0x05c +#define WPI_UCODE_GP2 0x060 +#define WPI_GIO_CHICKEN 0x100 +#define WPI_ANA_PLL 0x20c +#define WPI_DBG_HPET_MEM 0x240 +#define WPI_MEM_RADDR 0x40c +#define WPI_MEM_WADDR 0x410 +#define WPI_MEM_WDATA 0x418 +#define WPI_MEM_RDATA 0x41c +#define WPI_PRPH_WADDR 0x444 +#define WPI_PRPH_RADDR 0x448 +#define WPI_PRPH_WDATA 0x44c +#define WPI_PRPH_RDATA 0x450 +#define WPI_HBUS_TARG_WRPTR 0x460 + +/* + * Flow-Handler registers. + */ +#define WPI_FH_CBBC_CTRL(qid) (0x940 + (qid) * 8) +#define WPI_FH_CBBC_BASE(qid) (0x944 + (qid) * 8) +#define WPI_FH_RX_CONFIG 0xc00 +#define WPI_FH_RX_BASE 0xc04 +#define WPI_FH_RX_WPTR 0xc20 +#define WPI_FH_RX_RPTR_ADDR 0xc24 +#define WPI_FH_RSSR_TBL 0xcc0 +#define WPI_FH_RX_STATUS 0xcc4 +#define WPI_FH_TX_CONFIG(qid) (0xd00 + (qid) * 32) +#define WPI_FH_TX_BASE 0xe80 +#define WPI_FH_MSG_CONFIG 0xe88 +#define WPI_FH_TX_STATUS 0xe90 /* * NIC internal memory offsets. */ -#define WPI_MEM_MODE 0x2e00 -#define WPI_MEM_RA 0x2e04 -#define WPI_MEM_TXCFG 0x2e10 -#define WPI_MEM_MAGIC4 0x2e14 -#define WPI_MEM_MAGIC5 0x2e20 -#define WPI_MEM_BYPASS1 0x2e2c -#define WPI_MEM_BYPASS2 0x2e30 -#define WPI_MEM_CLOCK1 0x3004 -#define WPI_MEM_CLOCK2 0x3008 -#define WPI_MEM_POWER 0x300c -#define WPI_MEM_PCIDEV 0x3010 -#define WPI_MEM_HW_RADIO_OFF 0x3014 -#define WPI_MEM_UCODE_CTL 0x3400 -#define WPI_MEM_UCODE_SRC 0x3404 -#define WPI_MEM_UCODE_DST 0x3408 -#define WPI_MEM_UCODE_SIZE 0x340c -#define WPI_MEM_UCODE_BASE 0x3800 - -#define WPI_MEM_TEXT_BASE 0x3490 -#define WPI_MEM_TEXT_SIZE 0x3494 -#define WPI_MEM_DATA_BASE 0x3498 -#define WPI_MEM_DATA_SIZE 0x349c +#define WPI_ALM_SCHED_MODE 0x2e00 +#define WPI_ALM_SCHED_ARASTAT 0x2e04 +#define WPI_ALM_SCHED_TXFACT 0x2e10 +#define WPI_ALM_SCHED_TXF4MF 0x2e14 +#define WPI_ALM_SCHED_TXF5MF 0x2e20 +#define WPI_ALM_SCHED_SBYPASS_MODE1 0x2e2c +#define WPI_ALM_SCHED_SBYPASS_MODE2 0x2e30 +#define WPI_APMG_CLK_EN 0x3004 +#define WPI_APMG_CLK_DIS 0x3008 +#define WPI_APMG_PS 0x300c +#define WPI_APMG_PCI_STT 0x3010 +#define WPI_APMG_RFKILL 0x3014 +#define WPI_BSM_WR_CTRL 0x3400 +#define WPI_BSM_WR_MEM_SRC 0x3404 +#define WPI_BSM_WR_MEM_DST 0x3408 +#define WPI_BSM_WR_DWCOUNT 0x340c +#define WPI_BSM_DRAM_TEXT_ADDR 0x3490 +#define WPI_BSM_DRAM_TEXT_SIZE 0x3494 +#define WPI_BSM_DRAM_DATA_ADDR 0x3498 +#define WPI_BSM_DRAM_DATA_SIZE 0x349c +#define WPI_BSM_SRAM_BASE 0x3800 -/* possible flags for register WPI_HWCONFIG */ -#define WPI_HW_ALM_MB (1 << 8) -#define WPI_HW_ALM_MM (1 << 9) -#define WPI_HW_SKU_MRC (1 << 10) -#define WPI_HW_REV_D (1 << 11) -#define WPI_HW_TYPE_B (1 << 12) +/* Possible flags for register WPI_HW_IF_CONFIG. */ +#define WPI_HW_IF_CONFIG_ALM_MB (1 << 8) +#define WPI_HW_IF_CONFIG_ALM_MM (1 << 9) +#define WPI_HW_IF_CONFIG_SKU_MRC (1 << 10) +#define WPI_HW_IF_CONFIG_REV_D (1 << 11) +#define WPI_HW_IF_CONFIG_TYPE_B (1 << 12) -/* possible flags for registers WPI_READ_MEM_ADDR/WPI_WRITE_MEM_ADDR */ -#define WPI_MEM_4 ((sizeof (uint32_t) - 1) << 24) +/* Possible flags for registers WPI_PRPH_RADDR/WPI_PRPH_WADDR. */ +#define WPI_PRPH_DWORD ((sizeof (uint32_t) - 1) << 24) -/* possible values for WPI_MEM_UCODE_DST */ -#define WPI_FW_TEXT 0x00000000 +/* Possible values for WPI_BSM_WR_MEM_DST. */ +#define WPI_FW_TEXT_BASE 0x00000000 +#define WPI_FW_DATA_BASE 0x00800000 -/* possible flags for WPI_GPIO_STATUS */ -#define WPI_POWERED (1 << 9) +/* Possible flags for WPI_GPIO_IN. */ +#define WPI_GPIO_IN_VMAIN (1 << 9) -/* possible flags for register WPI_RESET */ -#define WPI_NEVO_RESET (1 << 0) -#define WPI_SW_RESET (1 << 7) -#define WPI_MASTER_DISABLED (1 << 8) -#define WPI_STOP_MASTER (1 << 9) +/* Possible flags for register WPI_RESET. */ +#define WPI_RESET_NEVO (1 << 0) +#define WPI_RESET_SW (1 << 7) +#define WPI_RESET_MASTER_DISABLED (1 << 8) +#define WPI_RESET_STOP_MASTER (1 << 9) -/* possible flags for register WPI_GPIO_CTL */ -#define WPI_GPIO_CLOCK (1 << 0) -#define WPI_GPIO_INIT (1 << 2) -#define WPI_GPIO_MAC (1 << 3) -#define WPI_GPIO_SLEEP (1 << 4) -#define WPI_GPIO_PWR_STATUS 0x07000000 -#define WPI_GPIO_PWR_SLEEP (4 << 24) +/* Possible flags for register WPI_GP_CNTRL. */ +#define WPI_GP_CNTRL_MAC_ACCESS_ENA (1 << 0) +#define WPI_GP_CNTRL_MAC_CLOCK_READY (1 << 0) +#define WPI_GP_CNTRL_INIT_DONE (1 << 2) +#define WPI_GP_CNTRL_MAC_ACCESS_REQ (1 << 3) +#define WPI_GP_CNTRL_SLEEP (1 << 4) +#define WPI_GP_CNTRL_PS_MASK (7 << 24) +#define WPI_GP_CNTRL_MAC_PS (4 << 24) +#define WPI_GP_CNTRL_RFKILL (1 << 27) -/* possible flags for register WPI_CHICKEN */ -#define WPI_CHICKEN_RXNOLOS (1 << 23) +/* Possible flags for register WPI_GIO_CHICKEN. */ +#define WPI_GIO_CHICKEN_L1A_NO_L0S_RX (1 << 23) +#define WPI_GIO_CHICKEN_DIS_L0S_TIMER (1 << 29) -/* possible flags for register WPI_PLL_CTL */ -#define WPI_PLL_INIT (1 << 24) +/* Possible flags for register WPI_GIO. */ +#define WPI_GIO_L0S_ENA (1 << 1) -/* possible flags for register WPI_UCODE_CLR */ -#define WPI_RADIO_OFF (1 << 1) -#define WPI_DISABLE_CMD (1 << 2) +/* Possible flags for register WPI_FH_RX_CONFIG. */ +#define WPI_FH_RX_CONFIG_DMA_ENA (1U << 31) +#define WPI_FH_RX_CONFIG_RDRBD_ENA (1 << 29) +#define WPI_FH_RX_CONFIG_WRSTATUS_ENA (1 << 27) +#define WPI_FH_RX_CONFIG_MAXFRAG (1 << 24) +#define WPI_FH_RX_CONFIG_NRBD(x) ((x) << 20) +#define WPI_FH_RX_CONFIG_IRQ_DST_HOST (1 << 12) +#define WPI_FH_RX_CONFIG_IRQ_TIMEOUT(x) ((x) << 4) -/* possible flags for WPI_RX_STATUS */ -#define WPI_RX_IDLE (1 << 24) +/* Possible flags for register WPI_ANA_PLL. */ +#define WPI_ANA_PLL_INIT (1 << 24) -/* possible flags for register WPI_UC_CTL */ -#define WPI_UC_ENABLE (1 << 30) -#define WPI_UC_RUN (1U << 31) +/* Possible flags for register WPI_UCODE_GP1*. */ +#define WPI_UCODE_GP1_MAC_SLEEP (1 << 0) +#define WPI_UCODE_GP1_RFKILL (1 << 1) +#define WPI_UCODE_GP1_CMD_BLOCKED (1 << 2) -/* possible flags for register WPI_INTR_CSR */ -#define WPI_ALIVE_INTR (1 << 0) -#define WPI_WAKEUP_INTR (1 << 1) -#define WPI_SW_ERROR (1 << 25) -#define WPI_TX_INTR (1 << 27) -#define WPI_HW_ERROR (1 << 29) -#define WPI_RX_INTR (1U << 31) +/* Possible flags for register WPI_FH_RX_STATUS. */ +#define WPI_FH_RX_STATUS_IDLE (1 << 24) -#define WPI_INTR_MASK \ - (WPI_SW_ERROR | WPI_HW_ERROR | WPI_TX_INTR | WPI_RX_INTR | \ - WPI_ALIVE_INTR | WPI_WAKEUP_INTR) +/* Possible flags for register WPI_BSM_WR_CTRL. */ +#define WPI_BSM_WR_CTRL_START_EN (1 << 30) +#define WPI_BSM_WR_CTRL_START (1U << 31) -/* possible flags for register WPI_TX_STATUS */ -#define WPI_TX_IDLE(qid) (1 << ((qid) + 24) | 1 << ((qid) + 16)) +/* Possible flags for register WPI_INT. */ +#define WPI_INT_ALIVE (1 << 0) +#define WPI_INT_WAKEUP (1 << 1) +#define WPI_INT_SW_RX (1 << 3) +#define WPI_INT_SW_ERR (1 << 25) +#define WPI_INT_FH_TX (1 << 27) +#define WPI_INT_HW_ERR (1 << 29) +#define WPI_INT_FH_RX (1U << 31) -/* possible flags for register WPI_EEPROM_CTL */ -#define WPI_EEPROM_READY (1 << 0) +/* Shortcut. */ +#define WPI_INT_MASK_DEF \ + (WPI_INT_SW_ERR | WPI_INT_HW_ERR | WPI_INT_FH_TX | \ + WPI_INT_FH_RX | WPI_INT_ALIVE | WPI_INT_WAKEUP | \ + WPI_INT_SW_RX) -/* possible flags for register WPI_EEPROM_STATUS */ +/* Possible flags for register WPI_FH_INT. */ +#define WPI_FH_INT_RX_CHNL(x) (1 << ((x) + 16)) +#define WPI_FH_INT_HI_PRIOR (1 << 30) +/* Shortcuts for the above. */ +#define WPI_FH_INT_RX \ + (WPI_FH_INT_RX_CHNL(0) | \ + WPI_FH_INT_RX_CHNL(1) | \ + WPI_FH_INT_RX_CHNL(2) | \ + WPI_FH_INT_HI_PRIOR) + +/* Possible flags for register WPI_FH_TX_STATUS. */ +#define WPI_FH_TX_STATUS_IDLE(qid) \ + (1 << ((qid) + 24) | 1 << ((qid) + 16)) + +/* Possible flags for register WPI_EEPROM. */ +#define WPI_EEPROM_READ_VALID (1 << 0) + +/* Possible flags for register WPI_EEPROM_GP. */ #define WPI_EEPROM_VERSION 0x00000007 -#define WPI_EEPROM_LOCKED 0x00000180 +#define WPI_EEPROM_GP_IF_OWNER 0x00000180 +/* Possible flags for register WPI_APMG_PS. */ +#define WPI_APMG_PS_PWR_SRC_MASK (3 << 24) + +/* Possible flags for registers WPI_APMG_CLK_*. */ +#define WPI_APMG_CLK_CTRL_DMA_CLK_RQT (1 << 9) +#define WPI_APMG_CLK_CTRL_BSM_CLK_RQT (1 << 11) + +/* Possible flags for register WPI_APMG_PCI_STT. */ +#define WPI_APMG_PCI_STT_L1A_DIS (1 << 11) struct wpi_shared { uint32_t txbase[8]; @@ -176,20 +228,21 @@ struct wpi_shared { #define WPI_MAX_SEG_LEN 65520 struct wpi_tx_desc { - uint32_t flags; + uint8_t reserved1[3]; + uint8_t nsegs; #define WPI_PAD32(x) (roundup2(x, 4) - (x)) struct { uint32_t addr; uint32_t len; - } __attribute__((__packed__)) segs[WPI_MAX_SCATTER]; - uint8_t reserved[28]; + } __packed segs[WPI_MAX_SCATTER]; + uint8_t reserved2[28]; } __packed; struct wpi_tx_stat { - uint8_t nrts; - uint8_t ntries; - uint8_t nkill; + uint8_t rtsfailcnt; + uint8_t ackfailcnt; + uint8_t btkillcnt; uint8_t rate; uint32_t duration; uint32_t status; @@ -204,8 +257,11 @@ struct wpi_rx_desc { #define WPI_START_SCAN 130 #define WPI_SCAN_RESULTS 131 #define WPI_STOP_SCAN 132 +#define WPI_BEACON_SENT 144 +#define WPI_RX_STATISTICS 156 +#define WPI_BEACON_STATISTICS 157 #define WPI_STATE_CHANGED 161 -#define WPI_MISSED_BEACON 162 +#define WPI_BEACON_MISSED 162 uint8_t flags; uint8_t idx; @@ -228,8 +284,10 @@ struct wpi_rx_stat { struct wpi_rx_head { uint16_t chan; uint16_t flags; +#define WPI_STAT_FLAG_SHPREAMBLE (1 << 2) + uint8_t reserved; - uint8_t rate; + uint8_t plcp; uint16_t len; } __packed; @@ -239,17 +297,23 @@ struct wpi_rx_tail { #define WPI_RX_NO_OVFL_ERR (1 << 1) /* shortcut for the above */ #define WPI_RX_NOERROR (WPI_RX_NO_CRC_ERR | WPI_RX_NO_OVFL_ERR) +#define WPI_RX_CIPHER_MASK (7 << 8) +#define WPI_RX_CIPHER_CCMP (2 << 8) +#define WPI_RX_DECRYPT_MASK (3 << 11) +#define WPI_RX_DECRYPT_OK (3 << 11) + uint64_t tstamp; uint32_t tbeacon; } __packed; struct wpi_tx_cmd { uint8_t code; -#define WPI_CMD_CONFIGURE 16 -#define WPI_CMD_ASSOCIATE 17 -#define WPI_CMD_SET_WME 19 -#define WPI_CMD_TSF 20 +#define WPI_CMD_RXON 16 +#define WPI_CMD_RXON_ASSOC 17 +#define WPI_CMD_EDCA_PARAMS 19 +#define WPI_CMD_TIMING 20 #define WPI_CMD_ADD_NODE 24 +#define WPI_CMD_DEL_NODE 25 #define WPI_CMD_TX_DATA 28 #define WPI_CMD_MRR_SETUP 71 #define WPI_CMD_SET_LED 72 @@ -257,21 +321,22 @@ struct wpi_tx_cmd { #define WPI_CMD_SCAN 128 #define WPI_CMD_SET_BEACON 145 #define WPI_CMD_TXPOWER 151 -#define WPI_CMD_BLUETOOTH 155 +#define WPI_CMD_BT_COEX 155 +#define WPI_CMD_GET_STATISTICS 156 uint8_t flags; uint8_t idx; uint8_t qid; - uint8_t data[360]; + uint8_t data[124]; } __packed; -/* structure for WPI_CMD_CONFIGURE */ -struct wpi_config { +/* Structure for command WPI_CMD_RXON. */ +struct wpi_rxon { uint8_t myaddr[IEEE80211_ADDR_LEN]; uint16_t reserved1; uint8_t bssid[IEEE80211_ADDR_LEN]; uint16_t reserved2; - uint8_t wlap_bssid_addr[6]; + uint8_t wlap[IEEE80211_ADDR_LEN]; uint16_t reserved3; uint8_t mode; #define WPI_MODE_HOSTAP 1 @@ -279,21 +344,22 @@ struct wpi_config { #define WPI_MODE_IBSS 4 #define WPI_MODE_MONITOR 6 - uint8_t air_propogation; + uint8_t air; uint16_t reserved4; uint8_t ofdm_mask; uint8_t cck_mask; uint16_t associd; uint32_t flags; -#define WPI_CONFIG_24GHZ (1 << 0) -#define WPI_CONFIG_CCK (1 << 1) -#define WPI_CONFIG_AUTO (1 << 2) -#define WPI_CONFIG_SHSLOT (1 << 4) -#define WPI_CONFIG_SHPREAMBLE (1 << 5) -#define WPI_CONFIG_NODIVERSITY (1 << 7) -#define WPI_CONFIG_ANTENNA_A (1 << 8) -#define WPI_CONFIG_ANTENNA_B (1 << 9) -#define WPI_CONFIG_TSF (1 << 15) +#define WPI_RXON_24GHZ (1 << 0) +#define WPI_RXON_CCK (1 << 1) +#define WPI_RXON_AUTO (1 << 2) +#define WPI_RXON_SHSLOT (1 << 4) +#define WPI_RXON_SHPREAMBLE (1 << 5) +#define WPI_RXON_NODIVERSITY (1 << 7) +#define WPI_RXON_ANTENNA_A (1 << 8) +#define WPI_RXON_ANTENNA_B (1 << 9) +#define WPI_RXON_TSF (1 << 15) +#define WPI_RXON_CTS_TO_SELF (1 << 30) uint32_t filter; #define WPI_FILTER_PROMISC (1 << 0) @@ -304,10 +370,10 @@ struct wpi_config { #define WPI_FILTER_BEACON (1 << 6) uint8_t chan; - uint16_t reserved6; + uint16_t reserved5; } __packed; -/* structure for command WPI_CMD_ASSOCIATE */ +/* Structure for command WPI_CMD_RXON_ASSOC. */ struct wpi_assoc { uint32_t flags; uint32_t filter; @@ -316,20 +382,22 @@ struct wpi_assoc { uint16_t reserved; } __packed; -/* structure for command WPI_CMD_SET_WME */ -struct wpi_wme_setup { +/* Structure for command WPI_CMD_EDCA_PARAMS. */ +struct wpi_edca_params { uint32_t flags; +#define WPI_EDCA_UPDATE (1 << 0) + struct { uint16_t cwmin; uint16_t cwmax; uint8_t aifsn; uint8_t reserved; - uint16_t txop; + uint16_t txoplimit; } __packed ac[WME_NUM_AC]; } __packed; -/* structure for command WPI_CMD_TSF */ -struct wpi_cmd_tsf { +/* Structure for command WPI_CMD_TIMING. */ +struct wpi_cmd_timing { uint64_t tstamp; uint16_t bintval; uint16_t atim; @@ -338,41 +406,60 @@ struct wpi_cmd_tsf { uint16_t reserved; } __packed; -/* structure for WPI_CMD_ADD_NODE */ +/* Structure for command WPI_CMD_ADD_NODE. */ struct wpi_node_info { uint8_t control; -#define WPI_NODE_UPDATE (1 << 0) +#define WPI_NODE_UPDATE (1 << 0) uint8_t reserved1[3]; - uint8_t bssid[IEEE80211_ADDR_LEN]; + uint8_t macaddr[IEEE80211_ADDR_LEN]; uint16_t reserved2; uint8_t id; #define WPI_ID_BSS 0 +#define WPI_ID_IBSS_MIN 2 +#define WPI_ID_IBSS_MAX 23 #define WPI_ID_BROADCAST 24 +#define WPI_ID_UNDEFINED (uint8_t)-1 uint8_t flags; +#define WPI_FLAG_KEY_SET (1 << 0) + uint16_t reserved3; - uint16_t key_flags; - uint8_t tkip; + uint16_t kflags; +#define WPI_KFLAG_CCMP (1 << 1) +#define WPI_KFLAG_KID(kid) ((kid) << 8) +#define WPI_KFLAG_MULTICAST (1 << 14) + + uint8_t tsc2; uint8_t reserved4; uint16_t ttak[5]; uint16_t reserved5; uint8_t key[IEEE80211_KEYBUF_SIZE]; uint32_t action; -#define WPI_ACTION_SET_RATE 4 +#define WPI_ACTION_SET_RATE (1 << 2) + uint32_t mask; uint16_t tid; - uint8_t rate; + uint8_t plcp; uint8_t antenna; -#define WPI_ANTENNA_A (1<<6) -#define WPI_ANTENNA_B (1<<7) -#define WPI_ANTENNA_BOTH (WPI_ANTENNA_A|WPI_ANTENNA_B) +#define WPI_ANTENNA_A (1 << 6) +#define WPI_ANTENNA_B (1 << 7) +#define WPI_ANTENNA_BOTH (WPI_ANTENNA_A | WPI_ANTENNA_B) + uint8_t add_imm; uint8_t del_imm; uint16_t add_imm_start; } __packed; -/* structure for command WPI_CMD_TX_DATA */ +/* Structure for command WPI_CMD_DEL_NODE. */ +struct wpi_cmd_del_node { + uint8_t count; + uint8_t reserved1[3]; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + uint16_t reserved2; +} __packed; + +/* Structure for command WPI_CMD_TX_DATA. */ struct wpi_cmd_data { uint16_t len; uint16_t lnext; @@ -381,34 +468,39 @@ struct wpi_cmd_data { #define WPI_TX_NEED_CTS (1 << 2) #define WPI_TX_NEED_ACK (1 << 3) #define WPI_TX_FULL_TXOP (1 << 7) -#define WPI_TX_BT_DISABLE (1 << 12) /* bluetooth coexistence */ +#define WPI_TX_BT_DISABLE (1 << 12) /* bluetooth coexistence */ #define WPI_TX_AUTO_SEQ (1 << 13) #define WPI_TX_INSERT_TSTAMP (1 << 16) - uint8_t rate; + uint8_t plcp; uint8_t id; uint8_t tid; uint8_t security; +#define WPI_CIPHER_WEP 1 +#define WPI_CIPHER_CCMP 2 +#define WPI_CIPHER_TKIP 3 +#define WPI_CIPHER_WEP104 9 + uint8_t key[IEEE80211_KEYBUF_SIZE]; uint8_t tkip[IEEE80211_WEP_MICLEN]; uint32_t fnext; uint32_t lifetime; #define WPI_LIFETIME_INFINITE 0xffffffff + uint8_t ofdm_mask; uint8_t cck_mask; uint8_t rts_ntries; uint8_t data_ntries; uint16_t timeout; uint16_t txop; - struct ieee80211_frame wh; } __packed; -/* structure for command WPI_CMD_SET_BEACON */ +/* Structure for command WPI_CMD_SET_BEACON. */ struct wpi_cmd_beacon { uint16_t len; uint16_t reserved1; uint32_t flags; /* same as wpi_cmd_data */ - uint8_t rate; + uint8_t plcp; uint8_t id; uint8_t reserved2[30]; uint32_t lifetime; @@ -418,11 +510,10 @@ struct wpi_cmd_beacon { uint16_t tim; uint8_t timsz; uint8_t reserved4; - struct ieee80211_frame wh; } __packed; -/* structure for notification WPI_MISSED_BEACON */ -struct wpi_missed_beacon { +/* Structure for notification WPI_BEACON_MISSED. */ +struct wpi_beacon_missed { uint32_t consecutive; uint32_t total; uint32_t expected; @@ -430,29 +521,22 @@ struct wpi_missed_beacon { } __packed; -/* structure for WPI_CMD_MRR_SETUP */ +/* Structure for command WPI_CMD_MRR_SETUP. */ +#define WPI_RIDX_MAX 11 struct wpi_mrr_setup { - uint8_t which; + uint32_t which; #define WPI_MRR_CTL 0 #define WPI_MRR_DATA 1 - uint8_t reserved[3]; - struct { - uint8_t signal; + uint8_t plcp; uint8_t flags; uint8_t ntries; uint8_t next; -#define WPI_OFDM6 0 -#define WPI_OFDM54 7 -#define WPI_CCK1 8 -#define WPI_CCK2 9 -#define WPI_CCK11 11 - - } __attribute__((__packed__)) rates[WPI_CCK11 + 1]; + } __packed rates[WPI_RIDX_MAX + 1]; } __packed; -/* structure for WPI_CMD_SET_LED */ +/* Structure for command WPI_CMD_SET_LED. */ struct wpi_cmd_led { uint32_t unit; /* multiplier (in usecs) */ uint8_t which; @@ -464,136 +548,127 @@ struct wpi_cmd_led { uint8_t reserved; } __packed; -/* structure for WPI_CMD_SET_POWER_MODE */ -struct wpi_power { - uint32_t flags; -#define WPI_POWER_CAM 0 /* constantly awake mode */ - uint32_t rx_timeout; - uint32_t tx_timeout; - uint32_t sleep[5]; +/* Structure for command WPI_CMD_SET_POWER_MODE. */ +struct wpi_pmgt_cmd { + uint16_t flags; +#define WPI_PS_ALLOW_SLEEP (1 << 0) +#define WPI_PS_NOTIFY (1 << 1) +#define WPI_PS_SLEEP_OVER_DTIM (1 << 2) +#define WPI_PS_PCI_PMGT (1 << 3) + + uint8_t reserved[2]; + uint32_t rxtimeout; + uint32_t txtimeout; + uint32_t intval[5]; +} __packed; + +/* Structures for command WPI_CMD_SCAN. */ +#define WPI_SCAN_MAX_ESSIDS 4 +struct wpi_scan_essid { + uint8_t id; + uint8_t len; + uint8_t data[IEEE80211_NWID_LEN]; } __packed; -/* structure for command WPI_CMD_SCAN */ struct wpi_scan_hdr { uint16_t len; uint8_t reserved1; uint8_t nchan; - uint16_t quiet; - uint16_t threshold; - uint16_t promotion; + uint16_t quiet_time; + uint16_t quiet_threshold; + uint16_t crc_threshold; uint16_t reserved2; - uint32_t maxtimeout; - uint32_t suspend; + uint32_t max_svc; /* background scans */ + uint32_t pause_svc; /* background scans */ uint32_t flags; uint32_t filter; -struct { - uint16_t len; - uint16_t lnext; - uint32_t flags; - uint8_t rate; - uint8_t id; - uint8_t tid; - uint8_t security; - uint8_t key[IEEE80211_KEYBUF_SIZE]; - uint8_t tkip[IEEE80211_WEP_MICLEN]; - uint32_t fnext; - uint32_t lifetime; - uint8_t ofdm_mask; - uint8_t cck_mask; - uint8_t rts_ntries; - uint8_t data_ntries; - uint16_t timeout; - uint16_t txop; -} tx __attribute__((__packed__)); - -#define WPI_SCAN_MAX_ESSIDS 4 - struct { - uint8_t id; - uint8_t esslen; - uint8_t essid[IEEE80211_NWID_LEN]; - }scan_essids[WPI_SCAN_MAX_ESSIDS]; - /* followed by probe request body */ - /* followed by nchan x wpi_scan_chan */ + /* Followed by a struct wpi_cmd_data. */ + /* Followed by an array of 4 structs wpi_scan_essid. */ + /* Followed by probe request body. */ + /* Followed by an array of ``nchan'' structs wpi_scan_chan. */ } __packed; struct wpi_scan_chan { uint8_t flags; +#define WPI_CHAN_ACTIVE (1 << 0) +#define WPI_CHAN_NPBREQS(x) (((1 << (x)) - 1) << 1) + uint8_t chan; -#define WPI_CHAN_ACTIVE (1 << 0) -#define WPI_CHAN_DIRECT (1 << 1) - uint8_t gain_radio; - uint8_t gain_dsp; + uint8_t rf_gain; + uint8_t dsp_gain; uint16_t active; /* msecs */ uint16_t passive; /* msecs */ } __packed; -/* structure for WPI_CMD_BLUETOOTH */ +#define WPI_SCAN_CRC_TH_DEFAULT htole16(1) +#define WPI_SCAN_CRC_TH_NEVER htole16(0xffff) + +/* Maximum size of a scan command. */ +#define WPI_SCAN_MAXSZ (MCLBYTES - 4) + +#define WPI_ACTIVE_DWELL_TIME_2GHZ (30) /* all times in msec */ +#define WPI_ACTIVE_DWELL_TIME_5GHZ (20) +#define WPI_ACTIVE_DWELL_FACTOR_2GHZ ( 3) +#define WPI_ACTIVE_DWELL_FACTOR_5GHZ ( 2) + +#define WPI_PASSIVE_DWELL_TIME_2GHZ ( 20) +#define WPI_PASSIVE_DWELL_TIME_5GHZ ( 10) +#define WPI_PASSIVE_DWELL_BASE (100) + +/* Structure for command WPI_CMD_TXPOWER. */ +struct wpi_cmd_txpower { + uint8_t band; +#define WPI_BAND_5GHZ 0 +#define WPI_BAND_2GHZ 1 + + uint8_t reserved; + uint16_t chan; + + struct { + uint8_t plcp; + uint8_t rf_gain; + uint8_t dsp_gain; + uint8_t reserved; + } __packed rates[WPI_RIDX_MAX + 1]; + +} __packed; + +/* Structure for command WPI_CMD_BT_COEX. */ struct wpi_bluetooth { uint8_t flags; - uint8_t lead; - uint8_t kill; +#define WPI_BT_COEX_DISABLE 0 +#define WPI_BT_COEX_MODE_2WIRE 1 +#define WPI_BT_COEX_MODE_3WIRE 2 +#define WPI_BT_COEX_MODE_4WIRE 3 + + uint8_t lead_time; +#define WPI_BT_LEAD_TIME_DEF 30 + + uint8_t max_kill; +#define WPI_BT_MAX_KILL_DEF 5 + uint8_t reserved; - uint32_t ack; - uint32_t cts; + uint32_t kill_ack; + uint32_t kill_cts; } __packed; -/* structure for command WPI_CMD_TXPOWER */ -struct wpi_cmd_txpower { - - uint8_t band; -#define WPI_RATE_5GHZ 0 -#define WPI_RATE_2GHZ 1 - uint8_t reserved; - uint16_t channel; - -#define WPI_RATE_MAPPING_COUNT 12 - struct { - uint8_t rate; - uint8_t gain_radio; - uint8_t gain_dsp; - uint8_t reserved; - } __packed rates [WPI_RATE_MAPPING_COUNT]; - -} __packed; - - - -#define WPI_FW_MAIN_TEXT_MAXSZ (80 * 1024 ) -#define WPI_FW_MAIN_DATA_MAXSZ (32 * 1024 ) -#define WPI_FW_INIT_TEXT_MAXSZ (80 * 1024 ) -#define WPI_FW_INIT_DATA_MAXSZ (32 * 1024 ) -#define WPI_FW_BOOT_TEXT_MAXSZ 1024 - -#define WPI_FW_UPDATED (1 << 31 ) - -/* firmware image header */ -struct wpi_firmware_hdr { - -#define WPI_FW_MINVERSION 2144 - - uint32_t version; - uint32_t rtextsz; - uint32_t rdatasz; - uint32_t itextsz; - uint32_t idatasz; - uint32_t btextsz; -} __packed; - -/* structure for WPI_UC_READY notification */ +/* Structure for WPI_UC_READY notification. */ struct wpi_ucode_info { - uint32_t version; + uint8_t minor; + uint8_t major; + uint16_t reserved1; uint8_t revision[8]; uint8_t type; uint8_t subtype; - uint16_t reserved; + uint16_t reserved2; uint32_t logptr; - uint32_t errorptr; - uint32_t timestamp; + uint32_t errptr; + uint32_t tstamp; uint32_t valid; } __packed; -/* structure for WPI_START_SCAN notification */ +/* Structure for WPI_START_SCAN notification. */ struct wpi_start_scan { uint64_t tstamp; uint32_t tbeacon; @@ -603,7 +678,7 @@ struct wpi_start_scan { uint32_t status; } __packed; -/* structure for WPI_STOP_SCAN notification */ +/* Structure for WPI_STOP_SCAN notification. */ struct wpi_stop_scan { uint8_t nchan; uint8_t status; @@ -612,9 +687,114 @@ struct wpi_stop_scan { uint64_t tsf; } __packed; +/* Structures for WPI_{RX,BEACON}_STATISTICS notification. */ +struct wpi_rx_phy_stats { + uint32_t ina; + uint32_t fina; + uint32_t bad_plcp; + uint32_t bad_crc32; + uint32_t overrun; + uint32_t eoverrun; + uint32_t good_crc32; + uint32_t fa; + uint32_t bad_fina_sync; + uint32_t sfd_timeout; + uint32_t fina_timeout; + uint32_t no_rts_ack; + uint32_t rxe_limit; + uint32_t ack; + uint32_t cts; +} __packed; + +struct wpi_rx_general_stats { + uint32_t bad_cts; + uint32_t bad_ack; + uint32_t not_bss; + uint32_t filtered; + uint32_t bad_chan; +} __packed; + +struct wpi_rx_stats { + struct wpi_rx_phy_stats ofdm; + struct wpi_rx_phy_stats cck; + struct wpi_rx_general_stats general; +} __packed; + +struct wpi_tx_stats { + uint32_t preamble; + uint32_t rx_detected; + uint32_t bt_defer; + uint32_t bt_kill; + uint32_t short_len; + uint32_t cts_timeout; + uint32_t ack_timeout; + uint32_t exp_ack; + uint32_t ack; +} __packed; + +struct wpi_general_stats { + uint32_t temp; + uint32_t burst_check; + uint32_t burst; + uint32_t reserved[4]; + uint32_t sleep; + uint32_t slot_out; + uint32_t slot_idle; + uint32_t ttl_tstamp; + uint32_t tx_ant_a; + uint32_t tx_ant_b; + uint32_t exec; + uint32_t probe; +} __packed; + +struct wpi_stats { + uint32_t flags; + struct wpi_rx_stats rx; + struct wpi_tx_stats tx; + struct wpi_general_stats general; +} __packed; + +/* Possible flags for command WPI_CMD_GET_STATISTICS. */ +#define WPI_STATISTICS_BEACON_DISABLE (1 << 1) + + +/* Firmware error dump entry. */ +struct wpi_fw_dump { + uint32_t desc; + uint32_t time; + uint32_t blink[2]; + uint32_t ilink[2]; + uint32_t data; +} __packed; + +/* Firmware image file header. */ +struct wpi_firmware_hdr { + +#define WPI_FW_MINVERSION 2144 +#define WPI_FW_NAME "wpifw" + + uint16_t driver; + uint8_t minor; + uint8_t major; + uint32_t rtextsz; + uint32_t rdatasz; + uint32_t itextsz; + uint32_t idatasz; + uint32_t btextsz; +} __packed; + +#define WPI_FW_TEXT_MAXSZ ( 80 * 1024 ) +#define WPI_FW_DATA_MAXSZ ( 32 * 1024 ) +#define WPI_FW_BOOT_TEXT_MAXSZ 1024 + +#define WPI_FW_UPDATED (1U << 31 ) + +/* + * Offsets into EEPROM. + */ #define WPI_EEPROM_MAC 0x015 #define WPI_EEPROM_REVISION 0x035 -#define WPI_EEPROM_CAPABILITIES 0x045 +#define WPI_EEPROM_SKU_CAP 0x045 #define WPI_EEPROM_TYPE 0x04a #define WPI_EEPROM_DOMAIN 0x060 #define WPI_EEPROM_BAND1 0x063 @@ -626,49 +806,66 @@ struct wpi_stop_scan { struct wpi_eeprom_chan { uint8_t flags; -#define WPI_EEPROM_CHAN_VALID (1<<0) -#define WPI_EEPROM_CHAN_IBSS (1<<1) -#define WPI_EEPROM_CHAN_ACTIVE (1<<3) -#define WPI_EEPROM_CHAN_RADAR (1<<4) +#define WPI_EEPROM_CHAN_VALID (1 << 0) +#define WPI_EEPROM_CHAN_IBSS (1 << 1) +#define WPI_EEPROM_CHAN_ACTIVE (1 << 3) +#define WPI_EEPROM_CHAN_RADAR (1 << 4) int8_t maxpwr; } __packed; struct wpi_eeprom_sample { - uint8_t index; - int8_t power; - uint16_t volt; -}; - -#define WPI_POWER_GROUPS_COUNT 5 - -struct wpi_eeprom_group { - struct wpi_eeprom_sample samples[5]; - int32_t coef[5]; - int32_t corr[5]; - int8_t maxpwr; - uint8_t chan; - int16_t temp; + uint8_t index; + int8_t power; + uint16_t volt; } __packed; -#define WPI_CHAN_BANDS_COUNT 5 -#define WPI_MAX_CHAN_PER_BAND 14 +#define WPI_POWER_GROUPS_COUNT 5 +struct wpi_eeprom_group { + struct wpi_eeprom_sample samples[5]; + int32_t coef[5]; + int32_t corr[5]; + int8_t maxpwr; + uint8_t chan; + int16_t temp; +} __packed; +#define WPI_CHAN_BANDS_COUNT 5 +#define WPI_MAX_CHAN_PER_BAND 14 static const struct wpi_chan_band { - uint32_t addr; /* offset in EEPROM */ - uint8_t nchan; - uint8_t chan[WPI_MAX_CHAN_PER_BAND]; -} wpi_bands[5] = { - { WPI_EEPROM_BAND1, 14, - { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }}, - { WPI_EEPROM_BAND2, 13, - { 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 }}, - { WPI_EEPROM_BAND3, 12, - { 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 }}, - { WPI_EEPROM_BAND4, 11, - { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 }}, - { WPI_EEPROM_BAND5, 6, - { 145, 149, 153, 157, 161, 165 }} + uint32_t addr; /* offset in EEPROM */ + uint8_t nchan; + uint8_t chan[WPI_MAX_CHAN_PER_BAND]; +} wpi_bands[] = { + /* 20MHz channels, 2GHz band. */ + { WPI_EEPROM_BAND1, 14, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 } }, + /* 20MHz channels, 5GHz band. */ + { WPI_EEPROM_BAND2, 13, + { 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 } }, + { WPI_EEPROM_BAND3, 12, + { 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 } }, + { WPI_EEPROM_BAND4, 11, + { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 } }, + { WPI_EEPROM_BAND5, 6, + { 145, 149, 153, 157, 161, 165 } } +}; + +/* HW rate indices. */ +#define WPI_RIDX_OFDM6 0 +#define WPI_RIDX_OFDM36 5 +#define WPI_RIDX_OFDM48 6 +#define WPI_RIDX_OFDM54 7 +#define WPI_RIDX_CCK1 8 +#define WPI_RIDX_CCK2 9 +#define WPI_RIDX_CCK11 11 + +static const uint8_t wpi_ridx_to_plcp[] = { + /* OFDM: IEEE Std 802.11a-1999, pp. 14 Table 80 */ + /* R1-R4 (ral/ural is R4-R1) */ + 0xd, 0xf, 0x5, 0x7, 0x9, 0xb, 0x1, 0x3, + /* CCK: device-dependent */ + 10, 20, 55, 110 }; #define WPI_MAX_PWR_INDEX 77 @@ -678,25 +875,25 @@ static const struct wpi_chan_band { * the reference driver.) */ static const uint8_t wpi_rf_gain_2ghz[WPI_MAX_PWR_INDEX + 1] = { - 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xd3, 0xd3, 0xb3, 0xb3, 0xb3, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x73, 0xeb, 0xeb, 0xeb, - 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xab, 0xab, 0xab, 0x8b, - 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xc3, 0xc3, 0xc3, 0xc3, 0xa3, - 0xa3, 0xa3, 0xa3, 0x83, 0x83, 0x83, 0x83, 0x63, 0x63, 0x63, 0x63, - 0x43, 0x43, 0x43, 0x43, 0x23, 0x23, 0x23, 0x23, 0x03, 0x03, 0x03, - 0x03 + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xd3, 0xd3, 0xb3, 0xb3, 0xb3, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x73, 0xeb, 0xeb, 0xeb, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xab, 0xab, 0xab, 0x8b, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xc3, 0xc3, 0xc3, 0xc3, 0xa3, + 0xa3, 0xa3, 0xa3, 0x83, 0x83, 0x83, 0x83, 0x63, 0x63, 0x63, 0x63, + 0x43, 0x43, 0x43, 0x43, 0x23, 0x23, 0x23, 0x23, 0x03, 0x03, 0x03, + 0x03 }; static const uint8_t wpi_rf_gain_5ghz[WPI_MAX_PWR_INDEX + 1] = { - 0xfb, 0xfb, 0xfb, 0xdb, 0xdb, 0xbb, 0xbb, 0x9b, 0x9b, 0x7b, 0x7b, - 0x7b, 0x7b, 0x5b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x1b, 0x1b, - 0x1b, 0x73, 0x73, 0x73, 0x53, 0x53, 0x53, 0x53, 0x53, 0x33, 0x33, - 0x33, 0x33, 0x13, 0x13, 0x13, 0x13, 0x13, 0xab, 0xab, 0xab, 0x8b, - 0x8b, 0x8b, 0x8b, 0x6b, 0x6b, 0x6b, 0x6b, 0x4b, 0x4b, 0x4b, 0x4b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x0b, 0x0b, 0x0b, 0x0b, 0x83, 0x83, 0x63, - 0x63, 0x63, 0x63, 0x43, 0x43, 0x43, 0x43, 0x23, 0x23, 0x23, 0x23, - 0x03 + 0xfb, 0xfb, 0xfb, 0xdb, 0xdb, 0xbb, 0xbb, 0x9b, 0x9b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x5b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x1b, 0x1b, + 0x1b, 0x73, 0x73, 0x73, 0x53, 0x53, 0x53, 0x53, 0x53, 0x33, 0x33, + 0x33, 0x33, 0x13, 0x13, 0x13, 0x13, 0x13, 0xab, 0xab, 0xab, 0x8b, + 0x8b, 0x8b, 0x8b, 0x6b, 0x6b, 0x6b, 0x6b, 0x4b, 0x4b, 0x4b, 0x4b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x0b, 0x0b, 0x0b, 0x0b, 0x83, 0x83, 0x63, + 0x63, 0x63, 0x63, 0x43, 0x43, 0x43, 0x43, 0x23, 0x23, 0x23, 0x23, + 0x03 }; /* @@ -704,34 +901,94 @@ static const uint8_t wpi_rf_gain_5ghz[WPI_MAX_PWR_INDEX + 1] = { * from the reference driver.) */ static const uint8_t wpi_dsp_gain_2ghz[WPI_MAX_PWR_INDEX + 1] = { - 0x7f, 0x7f, 0x7f, 0x7f, 0x7d, 0x6e, 0x69, 0x62, 0x7d, 0x73, 0x6c, - 0x63, 0x77, 0x6f, 0x69, 0x61, 0x5c, 0x6a, 0x64, 0x78, 0x71, 0x6b, - 0x7d, 0x77, 0x70, 0x6a, 0x65, 0x61, 0x5b, 0x6b, 0x79, 0x73, 0x6d, - 0x7f, 0x79, 0x73, 0x6c, 0x66, 0x60, 0x5c, 0x6e, 0x68, 0x62, 0x74, - 0x7d, 0x77, 0x71, 0x6b, 0x65, 0x60, 0x71, 0x6a, 0x66, 0x5f, 0x71, - 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, - 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, - 0x5f + 0x7f, 0x7f, 0x7f, 0x7f, 0x7d, 0x6e, 0x69, 0x62, 0x7d, 0x73, 0x6c, + 0x63, 0x77, 0x6f, 0x69, 0x61, 0x5c, 0x6a, 0x64, 0x78, 0x71, 0x6b, + 0x7d, 0x77, 0x70, 0x6a, 0x65, 0x61, 0x5b, 0x6b, 0x79, 0x73, 0x6d, + 0x7f, 0x79, 0x73, 0x6c, 0x66, 0x60, 0x5c, 0x6e, 0x68, 0x62, 0x74, + 0x7d, 0x77, 0x71, 0x6b, 0x65, 0x60, 0x71, 0x6a, 0x66, 0x5f, 0x71, + 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, + 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, + 0x5f }; static const uint8_t wpi_dsp_gain_5ghz[WPI_MAX_PWR_INDEX + 1] = { - 0x7f, 0x78, 0x72, 0x77, 0x65, 0x71, 0x66, 0x72, 0x67, 0x75, 0x6b, - 0x63, 0x5c, 0x6c, 0x7d, 0x76, 0x6d, 0x66, 0x60, 0x5a, 0x68, 0x62, - 0x5c, 0x76, 0x6f, 0x68, 0x7e, 0x79, 0x71, 0x69, 0x63, 0x76, 0x6f, - 0x68, 0x62, 0x74, 0x6d, 0x66, 0x62, 0x5d, 0x71, 0x6b, 0x63, 0x78, - 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, - 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x6b, 0x63, 0x78, - 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, - 0x78 + 0x7f, 0x78, 0x72, 0x77, 0x65, 0x71, 0x66, 0x72, 0x67, 0x75, 0x6b, + 0x63, 0x5c, 0x6c, 0x7d, 0x76, 0x6d, 0x66, 0x60, 0x5a, 0x68, 0x62, + 0x5c, 0x76, 0x6f, 0x68, 0x7e, 0x79, 0x71, 0x69, 0x63, 0x76, 0x6f, + 0x68, 0x62, 0x74, 0x6d, 0x66, 0x62, 0x5d, 0x71, 0x6b, 0x63, 0x78, + 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, + 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x6b, 0x63, 0x78, + 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, + 0x78 }; +/* + * Power saving settings (values obtained from the reference driver.) + */ +#define WPI_NDTIMRANGES 2 +#define WPI_NPOWERLEVELS 6 +static const struct wpi_pmgt { + uint32_t rxtimeout; + uint32_t txtimeout; + uint32_t intval[5]; + int skip_dtim; +} wpi_pmgt[WPI_NDTIMRANGES][WPI_NPOWERLEVELS] = { + /* DTIM <= 10 */ + { + { 0, 0, { 0, 0, 0, 0, 0 }, 0 }, /* CAM */ + { 200, 500, { 1, 2, 3, 4, 4 }, 0 }, /* PS level 1 */ + { 200, 300, { 2, 4, 6, 7, 7 }, 0 }, /* PS level 2 */ + { 50, 100, { 2, 6, 9, 9, 10 }, 0 }, /* PS level 3 */ + { 50, 25, { 2, 7, 9, 9, 10 }, 1 }, /* PS level 4 */ + { 25, 25, { 4, 7, 10, 10, 10 }, 1 } /* PS level 5 */ + }, + /* DTIM >= 11 */ + { + { 0, 0, { 0, 0, 0, 0, 0 }, 0 }, /* CAM */ + { 200, 500, { 1, 2, 3, 4, -1 }, 0 }, /* PS level 1 */ + { 200, 300, { 2, 4, 6, 7, -1 }, 0 }, /* PS level 2 */ + { 50, 100, { 2, 6, 9, 9, -1 }, 0 }, /* PS level 3 */ + { 50, 25, { 2, 7, 9, 9, -1 }, 0 }, /* PS level 4 */ + { 25, 25, { 4, 7, 10, 10, -1 }, 0 } /* PS level 5 */ + } +}; + +/* Firmware errors. */ +static const char * const wpi_fw_errmsg[] = { + "OK", + "FAIL", + "BAD_PARAM", + "BAD_CHECKSUM", + "NMI_INTERRUPT", + "SYSASSERT", + "FATAL_ERROR" +}; + +/* XXX description for some error codes (error data). */ +/* 0x00000074 - wrong totlen field */ +/* 0x000003B3 - powersave error */ +/* 0x00000447 - wrong channel selected */ #define WPI_READ(sc, reg) \ - bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg)) + bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg)) #define WPI_WRITE(sc, reg, val) \ - bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val)) + bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val)) #define WPI_WRITE_REGION_4(sc, offset, datap, count) \ - bus_space_write_region_4((sc)->sc_st, (sc)->sc_sh, (offset), \ - (datap), (count)) + bus_space_write_region_4((sc)->sc_st, (sc)->sc_sh, (offset), \ + (datap), (count)) + +#define WPI_SETBITS(sc, reg, mask) \ + WPI_WRITE(sc, reg, WPI_READ(sc, reg) | (mask)) + +#define WPI_CLRBITS(sc, reg, mask) \ + WPI_WRITE(sc, reg, WPI_READ(sc, reg) & ~(mask)) + +#define WPI_BARRIER_WRITE(sc) \ + bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ + BUS_SPACE_BARRIER_WRITE) + +#define WPI_BARRIER_READ_WRITE(sc) \ + bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) diff --git a/sys/dev/wpi/if_wpivar.h b/sys/dev/wpi/if_wpivar.h index e579264a49d8..53627271afad 100644 --- a/sys/dev/wpi/if_wpivar.h +++ b/sys/dev/wpi/if_wpivar.h @@ -16,8 +16,6 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - struct wpi_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; uint64_t wr_tsft; @@ -28,7 +26,7 @@ struct wpi_rx_radiotap_header { int8_t wr_dbm_antsignal; int8_t wr_dbm_antnoise; uint8_t wr_antenna; -}; +} __packed; #define WPI_RX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_TSFT) | \ @@ -45,8 +43,7 @@ struct wpi_tx_radiotap_header { uint8_t wt_rate; uint16_t wt_chan_freq; uint16_t wt_chan_flags; - uint8_t wt_hwqueue; -}; +} __packed; #define WPI_TX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_FLAGS) | \ @@ -56,15 +53,14 @@ struct wpi_tx_radiotap_header { struct wpi_dma_info { bus_dma_tag_t tag; bus_dmamap_t map; - bus_addr_t paddr; /* aligned p address */ - bus_addr_t paddr_start; /* possibly unaligned p start*/ - caddr_t vaddr; /* aligned v address */ - caddr_t vaddr_start; /* possibly unaligned v start */ + bus_addr_t paddr; + caddr_t vaddr; bus_size_t size; }; struct wpi_tx_data { bus_dmamap_t map; + bus_addr_t cmd_paddr; struct mbuf *m; struct ieee80211_node *ni; }; @@ -74,19 +70,17 @@ struct wpi_tx_ring { struct wpi_dma_info cmd_dma; struct wpi_tx_desc *desc; struct wpi_tx_cmd *cmd; - struct wpi_tx_data *data; + struct wpi_tx_data data[WPI_TX_RING_COUNT]; bus_dma_tag_t data_dmat; int qid; - int count; int queued; int cur; + int update; }; -#define WPI_RBUF_COUNT ( WPI_RX_RING_COUNT + 16 ) - struct wpi_rx_data { - bus_dmamap_t map; - struct mbuf *m; + struct mbuf *m; + bus_dmamap_t map; }; struct wpi_rx_ring { @@ -95,15 +89,12 @@ struct wpi_rx_ring { struct wpi_rx_data data[WPI_RX_RING_COUNT]; bus_dma_tag_t data_dmat; int cur; + int update; }; -struct wpi_amrr { - struct ieee80211_node ni; /* must be the first */ - int txcnt; - int retrycnt; - int success; - int success_threshold; - int recovery; +struct wpi_node { + struct ieee80211_node ni; /* must be the first */ + uint8_t id; }; struct wpi_power_sample { @@ -119,80 +110,117 @@ struct wpi_power_group { int16_t temp; }; +struct wpi_buf { + void *data; + struct ieee80211_node *ni; + struct mbuf *m; + size_t size; + int code; + int ac; +}; + struct wpi_vap { struct ieee80211vap vap; + struct wpi_buf wv_bcbuf; int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); }; #define WPI_VAP(vap) ((struct wpi_vap *)(vap)) +struct wpi_fw_part { + const uint8_t *text; + uint32_t textsz; + const uint8_t *data; + uint32_t datasz; +}; + +struct wpi_fw_info { + const uint8_t *data; + size_t size; + struct wpi_fw_part init; + struct wpi_fw_part main; + struct wpi_fw_part boot; +}; + struct wpi_softc { device_t sc_dev; + struct ifnet *sc_ifp; + int sc_debug; + struct mtx sc_mtx; + struct unrhdr *sc_unr; /* Flags indicating the current state the driver * expects the hardware to be in */ uint32_t flags; -#define WPI_FLAG_HW_RADIO_OFF (1 << 0) -#define WPI_FLAG_BUSY (1 << 1) -#define WPI_FLAG_AUTH (1 << 2) +#define WPI_FLAG_BUSY (1 << 0) - /* shared area */ + /* Shared area. */ struct wpi_dma_info shared_dma; struct wpi_shared *shared; - struct wpi_tx_ring txq[WME_NUM_AC]; - struct wpi_tx_ring cmdq; + struct wpi_tx_ring txq[WPI_NTXQUEUES]; struct wpi_rx_ring rxq; - /* TX Thermal Callibration */ + /* TX Thermal Callibration. */ struct callout calib_to; int calib_cnt; - /* Watch dog timer */ + /* Watch dog timers. */ struct callout watchdog_to; - /* Hardware switch polling timer */ - struct callout hwswitch_to; + struct callout watchdog_rfkill; + + /* Firmware image. */ + struct wpi_fw_info fw; + uint32_t errptr; struct resource *irq; struct resource *mem; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; void *sc_ih; + bus_size_t sc_sz; + int sc_cap_off; /* PCIe Capabilities. */ - struct wpi_config config; + struct wpi_rxon rxon; int temp; - + uint32_t qfullmsk; int sc_tx_timer; int sc_scan_timer; - struct bpf_if *sc_drvbpf; + void (*sc_node_free)(struct ieee80211_node *); + void (*sc_scan_curchan)(struct ieee80211_scan_state *, + unsigned long); struct wpi_rx_radiotap_header sc_rxtap; struct wpi_tx_radiotap_header sc_txtap; - /* firmware image */ + /* Firmware image. */ const struct firmware *fw_fp; - /* firmware DMA transfer */ + /* Firmware DMA transfer. */ struct wpi_dma_info fw_dma; - /* Tasks used by the driver */ - struct task sc_restarttask; /* reset firmware task */ - struct task sc_radiotask; /* reset rf task */ + /* Tasks used by the driver. */ + struct task sc_reinittask; + struct task sc_radiooff_task; + struct task sc_radioon_task; - /* Eeprom info */ + /* Eeprom info. */ uint8_t cap; uint16_t rev; uint8_t type; + struct wpi_eeprom_chan + eeprom_channels[WPI_CHAN_BANDS_COUNT][WPI_MAX_CHAN_PER_BAND]; struct wpi_power_group groups[WPI_POWER_GROUPS_COUNT]; int8_t maxpwr[IEEE80211_CHAN_MAX]; - char domain[4]; /*reglatory domain XXX */ + char domain[4]; /* Regulatory domain. */ }; + #define WPI_LOCK_INIT(_sc) \ mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ MTX_NETWORK_LOCK, MTX_DEF) From 4676e354fdc2730c92dec0043c5ddbc53259d238 Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Sun, 8 Feb 2015 01:12:23 +0000 Subject: [PATCH 12/75] Act as a bus in attach method: probe and attach devices --- sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c index 126b35e2d239..6931c8992241 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c @@ -171,6 +171,9 @@ bcm_vchiq_attach(device_t dev) vchiq_init(); + bus_generic_probe(dev); + bus_generic_attach(dev); + return (0); } From 2f99b597e06cd39a628eb9d6496aed7fc4c779ee Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Sun, 8 Feb 2015 01:12:40 +0000 Subject: [PATCH 13/75] Add VideoCore audio driver for Rasperry Pi (BCM2835) --- sys/arm/broadcom/bcm2835/bcm2835_audio.c | 908 ++++++++++++++++++ sys/arm/broadcom/bcm2835/files.bcm2835 | 3 + .../broadcom/bcm2835/vc_vchi_audioserv_defs.h | 156 +++ sys/arm/conf/RPI-B | 1 + 4 files changed, 1068 insertions(+) create mode 100644 sys/arm/broadcom/bcm2835/bcm2835_audio.c create mode 100644 sys/arm/broadcom/bcm2835/vc_vchi_audioserv_defs.h diff --git a/sys/arm/broadcom/bcm2835/bcm2835_audio.c b/sys/arm/broadcom/bcm2835/bcm2835_audio.c new file mode 100644 index 000000000000..91696e9479e2 --- /dev/null +++ b/sys/arm/broadcom/bcm2835/bcm2835_audio.c @@ -0,0 +1,908 @@ +/*- + * Copyright (c) 2015 Oleksandr Tymoshenko + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_KERNEL_OPTION_HEADERS +#include "opt_snd.h" +#endif + +#include +#include + +#include "mixer_if.h" + +#include "interface/compat/vchi_bsd.h" +#include "interface/vchi/vchi.h" +#include "interface/vchiq_arm/vchiq.h" + +#include "vc_vchi_audioserv_defs.h" + +SND_DECLARE_FILE("$FreeBSD$"); + +#define DEST_AUTO 0 +#define DEST_HEADPHONES 1 +#define DEST_HDMI 2 + +#define VCHIQ_AUDIO_PACKET_SIZE 4000 +#define VCHIQ_AUDIO_BUFFER_SIZE 128000 + +#define VCHIQ_AUDIO_MAX_VOLUME +/* volume in terms of 0.01dB */ +#define VCHIQ_AUDIO_VOLUME_MIN -10239 +#define VCHIQ_AUDIO_VOLUME(db100) (uint32_t)(-((db100) << 8)/100) + +/* dB levels with 5% volume step */ +static int db_levels[] = { + VCHIQ_AUDIO_VOLUME_MIN, -4605, -3794, -3218, -2772, + -2407, -2099, -1832, -1597, -1386, + -1195, -1021, -861, -713, -575, + -446, -325, -210, -102, 0, +}; + +static uint32_t bcm2835_audio_playfmt[] = { + SND_FORMAT(AFMT_U8, 1, 0), + SND_FORMAT(AFMT_U8, 2, 0), + SND_FORMAT(AFMT_S8, 1, 0), + SND_FORMAT(AFMT_S8, 2, 0), + SND_FORMAT(AFMT_S16_LE, 1, 0), + SND_FORMAT(AFMT_S16_LE, 2, 0), + SND_FORMAT(AFMT_U16_LE, 1, 0), + SND_FORMAT(AFMT_U16_LE, 2, 0), + 0 +}; + +static struct pcmchan_caps bcm2835_audio_playcaps = {8000, 48000, bcm2835_audio_playfmt, 0}; + +struct bcm2835_audio_info; + +#define PLAYBACK_IDLE 0 +#define PLAYBACK_STARTING 1 +#define PLAYBACK_PLAYING 2 +#define PLAYBACK_STOPPING 3 + +struct bcm2835_audio_chinfo { + struct bcm2835_audio_info *parent; + struct pcm_channel *channel; + struct snd_dbuf *buffer; + uint32_t fmt, spd, blksz; + + uint32_t complete_pos; + uint32_t free_buffer; + uint32_t buffered_ptr; + int playback_state; +}; + +struct bcm2835_audio_info { + device_t dev; + unsigned int bufsz; + struct bcm2835_audio_chinfo pch; + uint32_t dest, volume; + struct mtx *lock; + struct intr_config_hook intr_hook; + + /* VCHI data */ + struct mtx vchi_lock; + + /* MSG reply */ + struct mtx msg_avail_lock; + struct cv msg_avail_cv; + uint32_t msg_result; + + VCHI_INSTANCE_T vchi_instance; + VCHI_CONNECTION_T *vchi_connection; + VCHI_SERVICE_HANDLE_T vchi_handle; + + struct mtx data_lock; + struct cv data_cv; + + /* Unloadign module */ + int unloading; +}; + +#define bcm2835_audio_lock(_ess) snd_mtxlock((_ess)->lock) +#define bcm2835_audio_unlock(_ess) snd_mtxunlock((_ess)->lock) +#define bcm2835_audio_lock_assert(_ess) snd_mtxassert((_ess)->lock) + +#define VCHIQ_VCHI_LOCK(sc) mtx_lock(&(sc)->vchi_lock) +#define VCHIQ_VCHI_UNLOCK(sc) mtx_unlock(&(sc)->vchi_lock) + +static const char * +dest_description(uint32_t dest) +{ + switch (dest) { + case DEST_AUTO: + return "AUTO"; + break; + + case DEST_HEADPHONES: + return "HEADPHONES"; + break; + + case DEST_HDMI: + return "HDMI"; + break; + default: + return "UNKNOWN"; + break; + } +} + +static void +bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle) +{ + struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param; + int32_t status; + uint32_t msg_len; + VC_AUDIO_MSG_T m; + + if (reason != VCHI_CALLBACK_MSG_AVAILABLE) + return; + + status = vchi_msg_dequeue(sc->vchi_handle, + &m, sizeof m, &msg_len, VCHI_FLAGS_NONE); + if (m.type == VC_AUDIO_MSG_TYPE_RESULT) { + sc->msg_result = m.u.result.success; + cv_signal(&sc->msg_avail_cv); + } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) { + struct bcm2835_audio_chinfo *ch = m.u.complete.cookie; + + int count = m.u.complete.count & 0xffff; + int perr = (m.u.complete.count & (1U << 30)) != 0; + + ch->complete_pos = (ch->complete_pos + count) % sndbuf_getsize(ch->buffer); + ch->free_buffer += count; + + if (perr || ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE) { + chn_intr(ch->channel); + cv_signal(&sc->data_cv); + } + } else + printf("%s: unknown m.type: %d\n", __func__, m.type); +} + +/* VCHIQ stuff */ +static void +bcm2835_audio_init(struct bcm2835_audio_info *sc) +{ + int status; + + /* Initialize and create a VCHI connection */ + status = vchi_initialise(&sc->vchi_instance); + if (status != 0) { + printf("vchi_initialise failed: %d\n", status); + return; + } + + status = vchi_connect(NULL, 0, sc->vchi_instance); + if (status != 0) { + printf("vchi_connect failed: %d\n", status); + return; + } + + SERVICE_CREATION_T params = { + VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER), + VC_AUDIO_SERVER_NAME, /* 4cc service code */ + sc->vchi_connection, /* passed in fn pointers */ + 0, /* rx fifo size */ + 0, /* tx fifo size */ + bcm2835_audio_callback, /* service callback */ + sc, /* service callback parameter */ + 1, + 1, + 0 /* want crc check on bulk transfers */ + }; + + status = vchi_service_open(sc->vchi_instance, ¶ms, + &sc->vchi_handle); + + if (status == 0) + /* Finished with the service for now */ + vchi_service_release(sc->vchi_handle); + else + sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID; +} + +static void +bcm2835_audio_release(struct bcm2835_audio_info *sc) +{ + int success; + + if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { + vchi_service_use(sc->vchi_handle); + success = vchi_service_close(sc->vchi_handle); + if (success != 0) + printf("vchi_service_close failed: %d\n", success); + sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID; + } + + vchi_disconnect(sc->vchi_instance); +} + +static void +bcm2835_audio_reset_channel(struct bcm2835_audio_chinfo *ch) +{ + ch->free_buffer = VCHIQ_AUDIO_BUFFER_SIZE; + ch->playback_state = 0; + ch->buffered_ptr = 0; + ch->complete_pos = 0; + + sndbuf_reset(ch->buffer); +} + +static void +bcm2835_audio_start(struct bcm2835_audio_chinfo *ch) +{ + VC_AUDIO_MSG_T m; + int ret; + struct bcm2835_audio_info *sc = ch->parent; + + VCHIQ_VCHI_LOCK(sc); + if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { + vchi_service_use(sc->vchi_handle); + + bcm2835_audio_reset_channel(ch); + + m.type = VC_AUDIO_MSG_TYPE_START; + ret = vchi_msg_queue(sc->vchi_handle, + &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + + if (ret != 0) + printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); + + vchi_service_release(sc->vchi_handle); + } + VCHIQ_VCHI_UNLOCK(sc); + +} + +static void +bcm2835_audio_stop(struct bcm2835_audio_chinfo *ch) +{ + VC_AUDIO_MSG_T m; + int ret; + struct bcm2835_audio_info *sc = ch->parent; + + VCHIQ_VCHI_LOCK(sc); + if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { + vchi_service_use(sc->vchi_handle); + + m.type = VC_AUDIO_MSG_TYPE_STOP; + m.u.stop.draining = 0; + + ret = vchi_msg_queue(sc->vchi_handle, + &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + + if (ret != 0) + printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); + + vchi_service_release(sc->vchi_handle); + } + VCHIQ_VCHI_UNLOCK(sc); +} + +static void +bcm2835_audio_open(struct bcm2835_audio_info *sc) +{ + VC_AUDIO_MSG_T m; + int ret; + + VCHIQ_VCHI_LOCK(sc); + if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { + vchi_service_use(sc->vchi_handle); + + m.type = VC_AUDIO_MSG_TYPE_OPEN; + ret = vchi_msg_queue(sc->vchi_handle, + &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + + if (ret != 0) + printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); + + vchi_service_release(sc->vchi_handle); + } + VCHIQ_VCHI_UNLOCK(sc); +} + +static void +bcm2835_audio_update_controls(struct bcm2835_audio_info *sc) +{ + VC_AUDIO_MSG_T m; + int ret, db; + + VCHIQ_VCHI_LOCK(sc); + if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { + vchi_service_use(sc->vchi_handle); + + sc->msg_result = -1; + + m.type = VC_AUDIO_MSG_TYPE_CONTROL; + m.u.control.dest = sc->dest; + if (sc->volume > 99) + sc->volume = 99; + db = db_levels[sc->volume/5]; + m.u.control.volume = VCHIQ_AUDIO_VOLUME(db); + + ret = vchi_msg_queue(sc->vchi_handle, + &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + + if (ret != 0) + printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); + + mtx_lock(&sc->msg_avail_lock); + cv_wait_sig(&sc->msg_avail_cv, &sc->msg_avail_lock); + if (sc->msg_result) + printf("%s failed: %d\n", __func__, sc->msg_result); + mtx_unlock(&sc->msg_avail_lock); + + vchi_service_release(sc->vchi_handle); + } + VCHIQ_VCHI_UNLOCK(sc); +} + +static void +bcm2835_audio_update_params(struct bcm2835_audio_info *sc, struct bcm2835_audio_chinfo *ch) +{ + VC_AUDIO_MSG_T m; + int ret; + + VCHIQ_VCHI_LOCK(sc); + if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { + vchi_service_use(sc->vchi_handle); + + sc->msg_result = -1; + + m.type = VC_AUDIO_MSG_TYPE_CONFIG; + m.u.config.channels = AFMT_CHANNEL(ch->fmt); + m.u.config.samplerate = ch->spd; + m.u.config.bps = AFMT_BIT(ch->fmt); + + ret = vchi_msg_queue(sc->vchi_handle, + &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + + if (ret != 0) + printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); + + mtx_lock(&sc->msg_avail_lock); + cv_wait_sig(&sc->msg_avail_cv, &sc->msg_avail_lock); + if (sc->msg_result) + printf("%s failed: %d\n", __func__, sc->msg_result); + mtx_unlock(&sc->msg_avail_lock); + + vchi_service_release(sc->vchi_handle); + } + VCHIQ_VCHI_UNLOCK(sc); +} + +static __inline uint32_t +vchiq_unbuffered_bytes(struct bcm2835_audio_chinfo *ch) +{ + uint32_t size, ready, readyptr, readyend; + + size = sndbuf_getsize(ch->buffer); + readyptr = sndbuf_getreadyptr(ch->buffer); + ready = sndbuf_getready(ch->buffer); + + readyend = readyptr + ready; + /* Normal case */ + if (ch->buffered_ptr >= readyptr) { + if (readyend > ch->buffered_ptr) + return readyend - ch->buffered_ptr; + else + return 0; + } + else { /* buffered_ptr overflow */ + if (readyend > ch->buffered_ptr + size) + return readyend - ch->buffered_ptr - size; + else + return 0; + } +} + +static void +bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch) +{ + struct bcm2835_audio_info *sc = ch->parent; + VC_AUDIO_MSG_T m; + void *buf; + uint32_t count, size; + int ret; + + VCHIQ_VCHI_LOCK(sc); + if (sc->vchi_handle == VCHIQ_SERVICE_HANDLE_INVALID) { + VCHIQ_VCHI_UNLOCK(sc); + return; + } + + vchi_service_use(sc->vchi_handle); + + size = sndbuf_getsize(ch->buffer); + count = vchiq_unbuffered_bytes(ch); + buf = (uint8_t*)sndbuf_getbuf(ch->buffer) + ch->buffered_ptr; + + if (ch->buffered_ptr + count > size) + count = size - ch->buffered_ptr; + + if (count < VCHIQ_AUDIO_PACKET_SIZE) + goto done; + + count = min(count, ch->free_buffer); + count -= count % VCHIQ_AUDIO_PACKET_SIZE; + + m.type = VC_AUDIO_MSG_TYPE_WRITE; + m.u.write.count = count; + m.u.write.max_packet = VCHIQ_AUDIO_PACKET_SIZE; + m.u.write.callback = NULL; + m.u.write.cookie = ch; + if (buf) + m.u.write.silence = 0; + else + m.u.write.silence = 1; + + ret = vchi_msg_queue(sc->vchi_handle, + &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + + if (ret != 0) + printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); + + if (buf) { + while (count > 0) { + int bytes = MIN((int)m.u.write.max_packet, (int)count); + ch->free_buffer -= bytes; + ch->buffered_ptr += bytes; + ch->buffered_ptr = ch->buffered_ptr % size; + ret = vchi_msg_queue(sc->vchi_handle, + buf, bytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + if (ret != 0) + printf("%s: vchi_msg_queue failed: %d\n", + __func__, ret); + buf = (char *)buf + bytes; + count -= bytes; + } + } +done: + + vchi_service_release(sc->vchi_handle); + VCHIQ_VCHI_UNLOCK(sc); +} + +static void +bcm2835_audio_worker(void *data) +{ + struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)data; + struct bcm2835_audio_chinfo *ch = &sc->pch; + mtx_lock(&sc->data_lock); + while(1) { + + if (sc->unloading) + break; + + if ((ch->playback_state == PLAYBACK_PLAYING) && + (vchiq_unbuffered_bytes(ch) >= VCHIQ_AUDIO_PACKET_SIZE) + && (ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE)) { + bcm2835_audio_write_samples(ch); + } else { + if (ch->playback_state == PLAYBACK_STOPPING) { + bcm2835_audio_reset_channel(&sc->pch); + ch->playback_state = PLAYBACK_IDLE; + } + + cv_wait_sig(&sc->data_cv, &sc->data_lock); + + if (ch->playback_state == PLAYBACK_STARTING) { + /* Give it initial kick */ + chn_intr(sc->pch.channel); + ch->playback_state = PLAYBACK_PLAYING; + } + } + } + mtx_unlock(&sc->data_lock); + + kproc_exit(0); +} + +static void +bcm2835_audio_create_worker(struct bcm2835_audio_info *sc) +{ + struct proc *newp; + + if (kproc_create(bcm2835_audio_worker, (void*)sc, &newp, 0, 0, + "bcm2835_audio_worker") != 0) { + printf("failed to create bcm2835_audio_worker\n"); + } +} + +/* -------------------------------------------------------------------- */ +/* channel interface for ESS18xx */ +static void * +bcmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) +{ + struct bcm2835_audio_info *sc = devinfo; + struct bcm2835_audio_chinfo *ch = &sc->pch; + void *buffer; + + if (dir == PCMDIR_REC) + return NULL; + + ch->parent = sc; + ch->channel = c; + ch->buffer = b; + + /* default values */ + ch->spd = 44100; + ch->fmt = SND_FORMAT(AFMT_S16_LE, 2, 0); + ch->blksz = VCHIQ_AUDIO_PACKET_SIZE; + + buffer = malloc(sc->bufsz, M_DEVBUF, M_WAITOK | M_ZERO); + + if (sndbuf_setup(ch->buffer, buffer, sc->bufsz) != 0) { + free(buffer, M_DEVBUF); + return NULL; + } + + bcm2835_audio_update_params(sc, ch); + + return ch; +} + +static int +bcmchan_free(kobj_t obj, void *data) +{ + struct bcm2835_audio_chinfo *ch = data; + void *buffer; + + buffer = sndbuf_getbuf(ch->buffer); + if (buffer) + free(buffer, M_DEVBUF); + + return (0); +} + +static int +bcmchan_setformat(kobj_t obj, void *data, uint32_t format) +{ + struct bcm2835_audio_chinfo *ch = data; + struct bcm2835_audio_info *sc = ch->parent; + + bcm2835_audio_lock(sc); + + ch->fmt = format; + bcm2835_audio_update_params(sc, ch); + + bcm2835_audio_unlock(sc); + + return 0; +} + +static uint32_t +bcmchan_setspeed(kobj_t obj, void *data, uint32_t speed) +{ + struct bcm2835_audio_chinfo *ch = data; + struct bcm2835_audio_info *sc = ch->parent; + + bcm2835_audio_lock(sc); + + ch->spd = speed; + bcm2835_audio_update_params(sc, ch); + + bcm2835_audio_unlock(sc); + + return ch->spd; +} + +static uint32_t +bcmchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) +{ + struct bcm2835_audio_chinfo *ch = data; + + return ch->blksz; +} + +static int +bcmchan_trigger(kobj_t obj, void *data, int go) +{ + struct bcm2835_audio_chinfo *ch = data; + struct bcm2835_audio_info *sc = ch->parent; + + if (!PCMTRIG_COMMON(go)) + return (0); + + bcm2835_audio_lock(sc); + + switch (go) { + case PCMTRIG_START: + bcm2835_audio_start(ch); + ch->playback_state = PLAYBACK_STARTING; + /* wakeup worker thread */ + cv_signal(&sc->data_cv); + break; + + case PCMTRIG_STOP: + case PCMTRIG_ABORT: + ch->playback_state = 1; + bcm2835_audio_stop(ch); + break; + + default: + break; + } + + bcm2835_audio_unlock(sc); + return 0; +} + +static uint32_t +bcmchan_getptr(kobj_t obj, void *data) +{ + struct bcm2835_audio_chinfo *ch = data; + struct bcm2835_audio_info *sc = ch->parent; + uint32_t ret; + + bcm2835_audio_lock(sc); + + ret = ch->complete_pos - (ch->complete_pos % VCHIQ_AUDIO_PACKET_SIZE); + + bcm2835_audio_unlock(sc); + + return ret; +} + +static struct pcmchan_caps * +bcmchan_getcaps(kobj_t obj, void *data) +{ + + return &bcm2835_audio_playcaps; +} + +static kobj_method_t bcmchan_methods[] = { + KOBJMETHOD(channel_init, bcmchan_init), + KOBJMETHOD(channel_free, bcmchan_free), + KOBJMETHOD(channel_setformat, bcmchan_setformat), + KOBJMETHOD(channel_setspeed, bcmchan_setspeed), + KOBJMETHOD(channel_setblocksize, bcmchan_setblocksize), + KOBJMETHOD(channel_trigger, bcmchan_trigger), + KOBJMETHOD(channel_getptr, bcmchan_getptr), + KOBJMETHOD(channel_getcaps, bcmchan_getcaps), + KOBJMETHOD_END +}; +CHANNEL_DECLARE(bcmchan); + +/************************************************************/ + +static int +bcmmix_init(struct snd_mixer *m) +{ + + mix_setdevs(m, SOUND_MASK_VOLUME); + + return (0); +} + +static int +bcmmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) +{ + struct bcm2835_audio_info *sc = mix_getdevinfo(m); + + switch (dev) { + case SOUND_MIXER_VOLUME: + sc->volume = left; + bcm2835_audio_update_controls(sc); + break; + + default: + break; + } + + return left | (left << 8); +} + +static kobj_method_t bcmmixer_methods[] = { + KOBJMETHOD(mixer_init, bcmmix_init), + KOBJMETHOD(mixer_set, bcmmix_set), + KOBJMETHOD_END +}; + +MIXER_DECLARE(bcmmixer); + +static int +sysctl_bcm2835_audio_dest(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_audio_info *sc = arg1; + int val; + int err; + + val = sc->dest; + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + if ((val < 0) || (val > 2)) + return (EINVAL); + + sc->dest = val; + device_printf(sc->dev, "destination set to %s\n", dest_description(val)); + bcm2835_audio_update_controls(sc); + + return (0); +} + +static void +vchi_audio_sysctl_init(struct bcm2835_audio_info *sc) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid *tree_node; + struct sysctl_oid_list *tree; + + /* + * Add system sysctl tree/handlers. + */ + ctx = device_get_sysctl_ctx(sc->dev); + tree_node = device_get_sysctl_tree(sc->dev); + tree = SYSCTL_CHILDREN(tree_node); + SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "dest", + CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc), + sysctl_bcm2835_audio_dest, "IU", "audio destination, " + "0 - auto, 1 - headphones, 2 - HDMI"); +} + +static void +bcm2835_audio_identify(driver_t *driver, device_t parent) +{ + + BUS_ADD_CHILD(parent, 0, "pcm", 0); +} + +static int +bcm2835_audio_probe(device_t dev) +{ + + device_set_desc(dev, "VCHQI audio"); + return (BUS_PROBE_DEFAULT); +} + + +static void +bcm2835_audio_delayed_init(void *xsc) +{ + struct bcm2835_audio_info *sc; + char status[SND_STATUSLEN]; + + sc = xsc; + + config_intrhook_disestablish(&sc->intr_hook); + + bcm2835_audio_init(sc); + bcm2835_audio_open(sc); + sc->volume = 75; + sc->dest = DEST_AUTO; + + if (mixer_init(sc->dev, &bcmmixer_class, sc)) { + device_printf(sc->dev, "mixer_init failed\n"); + goto no; + } + + if (pcm_register(sc->dev, sc, 1, 1)) { + device_printf(sc->dev, "pcm_register failed\n"); + goto no; + } + + pcm_addchan(sc->dev, PCMDIR_PLAY, &bcmchan_class, sc); + snprintf(status, SND_STATUSLEN, "at VCHIQ"); + pcm_setstatus(sc->dev, status); + + bcm2835_audio_reset_channel(&sc->pch); + bcm2835_audio_create_worker(sc); + + vchi_audio_sysctl_init(sc); + +no: + ; +} + +static int +bcm2835_audio_attach(device_t dev) +{ + struct bcm2835_audio_info *sc; + + sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); + + sc->dev = dev; + sc->bufsz = VCHIQ_AUDIO_BUFFER_SIZE; + + sc->lock = snd_mtxcreate(device_get_nameunit(dev), "bcm2835_audio softc"); + + mtx_init(&sc->vchi_lock, "bcm2835_audio", "vchi_lock", MTX_DEF); + mtx_init(&sc->msg_avail_lock, "msg_avail_mtx", "msg_avail_mtx", MTX_DEF); + cv_init(&sc->msg_avail_cv, "msg_avail_cv"); + mtx_init(&sc->data_lock, "data_mtx", "data_mtx", MTX_DEF); + cv_init(&sc->data_cv, "data_cv"); + sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID; + + /* + * We need interrupts enabled for VCHI to work properly, + * so delay intialization until it happens + */ + sc->intr_hook.ich_func = bcm2835_audio_delayed_init; + sc->intr_hook.ich_arg = sc; + + if (config_intrhook_establish(&sc->intr_hook) != 0) + goto no; + + return 0; + +no: + return ENXIO; +} + +static int +bcm2835_audio_detach(device_t dev) +{ + int r; + struct bcm2835_audio_info *sc; + sc = pcm_getdevinfo(dev); + + /* Stop worker thread */ + sc->unloading = 1; + cv_signal(&sc->data_cv); + + r = pcm_unregister(dev); + if (r) + return r; + + mtx_destroy(&sc->vchi_lock); + mtx_destroy(&sc->msg_avail_lock); + cv_destroy(&sc->msg_avail_cv); + mtx_destroy(&sc->data_lock); + cv_destroy(&sc->data_cv); + + bcm2835_audio_release(sc); + + if (sc->lock) { + snd_mtxfree(sc->lock); + sc->lock = NULL; + } + + free(sc, M_DEVBUF); + + return 0; +} + +static device_method_t bcm2835_audio_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, bcm2835_audio_identify), + DEVMETHOD(device_probe, bcm2835_audio_probe), + DEVMETHOD(device_attach, bcm2835_audio_attach), + DEVMETHOD(device_detach, bcm2835_audio_detach), + + { 0, 0 } +}; + +static driver_t bcm2835_audio_driver = { + "pcm", + bcm2835_audio_methods, + PCM_SOFTC_SIZE, +}; + +DRIVER_MODULE(bcm2835_audio, vchiq, bcm2835_audio_driver, pcm_devclass, 0, 0); +MODULE_DEPEND(bcm2835_audio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); +MODULE_DEPEND(bcm2835_audio, vchiq, 1, 1, 1); +MODULE_VERSION(bcm2835_audio, 1); diff --git a/sys/arm/broadcom/bcm2835/files.bcm2835 b/sys/arm/broadcom/bcm2835/files.bcm2835 index 416fb4adb7e2..89d6584fa321 100644 --- a/sys/arm/broadcom/bcm2835/files.bcm2835 +++ b/sys/arm/broadcom/bcm2835/files.bcm2835 @@ -28,6 +28,9 @@ kern/kern_clocksource.c standard dev/mbox/mbox_if.m standard dev/ofw/ofw_cpu.c standard +arm/broadcom/bcm2835/bcm2835_audio.c optional sound vchiq \ + compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" + # VideoCore driver contrib/vchiq/interface/compat/vchi_bsd.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" diff --git a/sys/arm/broadcom/bcm2835/vc_vchi_audioserv_defs.h b/sys/arm/broadcom/bcm2835/vc_vchi_audioserv_defs.h new file mode 100644 index 000000000000..143c54385916 --- /dev/null +++ b/sys/arm/broadcom/bcm2835/vc_vchi_audioserv_defs.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2012, Broadcom Europe Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _VC_AUDIO_DEFS_H_ +#define _VC_AUDIO_DEFS_H_ + +#define VC_AUDIOSERV_MIN_VER 1 +#define VC_AUDIOSERV_VER 2 + +/* FourCC code used for VCHI connection */ +#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS") + +/* Maximum message length */ +#define VC_AUDIO_MAX_MSG_LEN (sizeof( VC_AUDIO_MSG_T )) + +/* + * List of screens that are currently supported + * All message types supported for HOST->VC direction + */ +typedef enum +{ + VC_AUDIO_MSG_TYPE_RESULT, /* Generic result */ + VC_AUDIO_MSG_TYPE_COMPLETE, /* playback of samples complete */ + VC_AUDIO_MSG_TYPE_CONFIG, /* Configure */ + VC_AUDIO_MSG_TYPE_CONTROL, /* control */ + VC_AUDIO_MSG_TYPE_OPEN, /* open */ + VC_AUDIO_MSG_TYPE_CLOSE, /* close/shutdown */ + VC_AUDIO_MSG_TYPE_START, /* start output (i.e. resume) */ + VC_AUDIO_MSG_TYPE_STOP, /* stop output (i.e. pause) */ + VC_AUDIO_MSG_TYPE_WRITE, /* write samples */ + VC_AUDIO_MSG_TYPE_MAX + +} VC_AUDIO_MSG_TYPE; + +static const char *vc_audio_msg_type_names[] = { + "VC_AUDIO_MSG_TYPE_RESULT", + "VC_AUDIO_MSG_TYPE_COMPLETE", + "VC_AUDIO_MSG_TYPE_CONFIG", + "VC_AUDIO_MSG_TYPE_CONTROL", + "VC_AUDIO_MSG_TYPE_OPEN", + "VC_AUDIO_MSG_TYPE_CLOSE", + "VC_AUDIO_MSG_TYPE_START", + "VC_AUDIO_MSG_TYPE_STOP", + "VC_AUDIO_MSG_TYPE_WRITE", + "VC_AUDIO_MSG_TYPE_MAX" +}; + +/* configure the audio */ +typedef struct +{ + uint32_t channels; + uint32_t samplerate; + uint32_t bps; + +} VC_AUDIO_CONFIG_T; + +typedef struct +{ + uint32_t volume; + uint32_t dest; + +} VC_AUDIO_CONTROL_T; + +typedef struct +{ + uint32_t dummy; + +} VC_AUDIO_OPEN_T; + +typedef struct +{ + uint32_t dummy; + +} VC_AUDIO_CLOSE_T; + +typedef struct +{ + uint32_t dummy; + +} VC_AUDIO_START_T; + +typedef struct +{ + uint32_t draining; + +} VC_AUDIO_STOP_T; + +typedef struct +{ + uint32_t count; /* in bytes */ + void *callback; + void *cookie; + uint16_t silence; + uint16_t max_packet; +} VC_AUDIO_WRITE_T; + +/* Generic result for a request (VC->HOST) */ +typedef struct +{ + int32_t success; /* Success value */ + +} VC_AUDIO_RESULT_T; + +/* Generic result for a request (VC->HOST) */ +typedef struct +{ + int32_t count; /* Success value */ + void *callback; + void *cookie; +} VC_AUDIO_COMPLETE_T; + +/* Message header for all messages in HOST->VC direction */ +typedef struct +{ + int32_t type; /* Message type (VC_AUDIO_MSG_TYPE) */ + union + { + VC_AUDIO_CONFIG_T config; + VC_AUDIO_CONTROL_T control; + VC_AUDIO_OPEN_T open; + VC_AUDIO_CLOSE_T close; + VC_AUDIO_START_T start; + VC_AUDIO_STOP_T stop; + VC_AUDIO_WRITE_T write; + VC_AUDIO_RESULT_T result; + VC_AUDIO_COMPLETE_T complete; + } u; +} VC_AUDIO_MSG_T; + +#endif /* _VC_AUDIO_DEFS_H_ */ diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B index 41566efecc6c..77c6fa0290eb 100644 --- a/sys/arm/conf/RPI-B +++ b/sys/arm/conf/RPI-B @@ -130,6 +130,7 @@ device spibus device bcm2835_spi device vchiq +device sound # Flattened Device Tree options FDT # Configure using FDT/DTB data From 3277b9a25761a4a61e0c978cf6068742bc49c341 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Sun, 8 Feb 2015 03:55:12 +0000 Subject: [PATCH 14/75] Fix a typo in r278137: make sure to free provider state. X-MFC-With: r278136 --- sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index 68e81616a5a7..dcf33c6e9829 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -16881,7 +16881,7 @@ dtrace_dtr(void *data) #ifdef illumos dtrace_state_destroy(state); #else - if (state == NULL) { + if (state != NULL) { dtrace_state_destroy(state); kmem_free(state, 0); } From d86a5ff91728f0242c47e235811c3c233d7ea567 Mon Sep 17 00:00:00 2001 From: Navdeep Parhar Date: Sun, 8 Feb 2015 08:42:45 +0000 Subject: [PATCH 15/75] cxgbe(4): a change to the synchronization rules within the the driver. This is purely cosmetic because the new rules are already followed. MFC after: 1 week --- sys/dev/cxgbe/adapter.h | 1 - sys/dev/cxgbe/t4_main.c | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h index 62ff9af000aa..3e65d91a39c7 100644 --- a/sys/dev/cxgbe/adapter.h +++ b/sys/dev/cxgbe/adapter.h @@ -812,7 +812,6 @@ struct adapter { #define ADAPTER_LOCK_ASSERT_OWNED(sc) mtx_assert(&(sc)->sc_lock, MA_OWNED) #define ADAPTER_LOCK_ASSERT_NOTOWNED(sc) mtx_assert(&(sc)->sc_lock, MA_NOTOWNED) -/* XXX: not bulletproof, but much better than nothing */ #define ASSERT_SYNCHRONIZED_OP(sc) \ KASSERT(IS_BUSY(sc) && \ (mtx_owned(&(sc)->sc_lock) || sc->last_op_thr == curthread), \ diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index e2f3c594df4b..4f9172144600 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -3139,6 +3139,9 @@ update_mac_settings(struct ifnet *ifp, int flags) return (rc); } +/* + * {begin|end}_synchronized_op must be called from the same thread. + */ int begin_synchronized_op(struct adapter *sc, struct port_info *pi, int flags, char *wmesg) @@ -3194,6 +3197,9 @@ begin_synchronized_op(struct adapter *sc, struct port_info *pi, int flags, return (rc); } +/* + * {begin|end}_synchronized_op must be called from the same thread. + */ void end_synchronized_op(struct adapter *sc, int flags) { From 319f290030ff0f83fe2f80b05ffb695fa14e846e Mon Sep 17 00:00:00 2001 From: Navdeep Parhar Date: Sun, 8 Feb 2015 08:52:18 +0000 Subject: [PATCH 16/75] cxgbe(4): adapter_full_init is always a synchronized operation. MFC after: 1 week --- sys/dev/cxgbe/t4_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index 4f9172144600..09ea9d2f9704 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -3432,6 +3432,7 @@ adapter_full_init(struct adapter *sc) { int rc, i; + ASSERT_SYNCHRONIZED_OP(sc); ADAPTER_LOCK_ASSERT_NOTOWNED(sc); KASSERT((sc->flags & FULL_INIT_DONE) == 0, ("%s: FULL_INIT_DONE already", __func__)); From b3d44a6800fa991404684bf21a3ad3a0a865db80 Mon Sep 17 00:00:00 2001 From: Navdeep Parhar Date: Sun, 8 Feb 2015 09:28:55 +0000 Subject: [PATCH 17/75] cxgbe(4): tidy up some of the interaction between the Upper Layer Drivers (ULDs) and the base if_cxgbe driver. Track the per-adapter activation of ULDs in a new "active_ulds" field. This was done pretty arbitrarily before this change -- via TOM_INIT_DONE in adapter->flags for TOM, and the (1 << MAX_NPORTS) bit in adapter->offload_map for iWARP. iWARP and hw-accelerated iSCSI rely on the TOE (supported by the TOM ULD). The rules are: a) If the iWARP and/or iSCSI ULDs are available when TOE is enabled then iWARP and/or iSCSI are enabled too. b) When the iWARP and iSCSI modules are loaded they go looking for adapters with TOE enabled and enable themselves on that adapter. c) You cannot deactivate or unload the TOM module from underneath iWARP or iSCSI. Any such attempt will fail with EBUSY. MFC after: 2 weeks --- sys/dev/cxgbe/adapter.h | 5 ++-- sys/dev/cxgbe/iw_cxgbe/device.c | 13 ++++---- sys/dev/cxgbe/offload.h | 8 +++-- sys/dev/cxgbe/t4_main.c | 53 +++++++++++++++++++++++++-------- sys/dev/cxgbe/tom/t4_listen.c | 2 +- sys/dev/cxgbe/tom/t4_tom.c | 9 +++--- 6 files changed, 60 insertions(+), 30 deletions(-) diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h index 3e65d91a39c7..31e8f393e0c1 100644 --- a/sys/dev/cxgbe/adapter.h +++ b/sys/dev/cxgbe/adapter.h @@ -192,7 +192,7 @@ enum { /* INTR_DIRECT = (1 << 2), No longer used. */ MASTER_PF = (1 << 3), ADAP_SYSCTL_CTX = (1 << 4), - TOM_INIT_DONE = (1 << 5), + /* TOM_INIT_DONE= (1 << 5), No longer used */ BUF_PACKING_OK = (1 << 6), CXGBE_BUSY = (1 << 9), @@ -758,7 +758,8 @@ struct adapter { uint16_t doorbells; int open_device_map; #ifdef TCP_OFFLOAD - int offload_map; + int offload_map; /* ports with IFCAP_TOE enabled */ + int active_ulds; /* ULDs activated on this adapter */ #endif int flags; diff --git a/sys/dev/cxgbe/iw_cxgbe/device.c b/sys/dev/cxgbe/iw_cxgbe/device.c index 92a574215b2a..29378ae9d377 100644 --- a/sys/dev/cxgbe/iw_cxgbe/device.c +++ b/sys/dev/cxgbe/iw_cxgbe/device.c @@ -213,7 +213,7 @@ c4iw_activate(struct adapter *sc) ASSERT_SYNCHRONIZED_OP(sc); - if (isset(&sc->offload_map, MAX_NPORTS)) { + if (uld_active(sc, ULD_IWARP)) { KASSERT(0, ("%s: RDMA already eanbled on sc %p", __func__, sc)); return (0); } @@ -265,9 +265,9 @@ c4iw_activate_all(struct adapter *sc, void *arg __unused) if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4iwact") != 0) return; - if (!isset(&sc->offload_map, MAX_NPORTS) && - t4_activate_uld(sc, ULD_IWARP) == 0) - setbit(&sc->offload_map, MAX_NPORTS); + /* Activate iWARP if any port on this adapter has IFCAP_TOE enabled. */ + if (sc->offload_map && !uld_active(sc, ULD_IWARP)) + (void) t4_activate_uld(sc, ULD_IWARP); end_synchronized_op(sc, 0); } @@ -279,9 +279,8 @@ c4iw_deactivate_all(struct adapter *sc, void *arg __unused) if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4iwdea") != 0) return; - if (isset(&sc->offload_map, MAX_NPORTS) && - t4_deactivate_uld(sc, ULD_IWARP) == 0) - clrbit(&sc->offload_map, MAX_NPORTS); + if (uld_active(sc, ULD_IWARP)) + (void) t4_deactivate_uld(sc, ULD_IWARP); end_synchronized_op(sc, 0); } diff --git a/sys/dev/cxgbe/offload.h b/sys/dev/cxgbe/offload.h index e097b8fcc916..2a1228332b23 100644 --- a/sys/dev/cxgbe/offload.h +++ b/sys/dev/cxgbe/offload.h @@ -127,9 +127,10 @@ struct t4_virt_res { /* virtualized HW resources */ #ifdef TCP_OFFLOAD enum { - ULD_TOM = 1, - ULD_IWARP = 2, - ULD_ISCSI = 3, + ULD_TOM = 0, + ULD_IWARP, + ULD_ISCSI, + ULD_MAX = ULD_ISCSI }; struct adapter; @@ -156,5 +157,6 @@ int t4_unregister_uld(struct uld_info *); int t4_activate_uld(struct adapter *, int); int t4_deactivate_uld(struct adapter *, int); void t4_iscsi_init(struct ifnet *, unsigned int, const unsigned int *); +int uld_active(struct adapter *, int); #endif #endif diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index 09ea9d2f9704..dc20855eed80 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -7144,7 +7144,7 @@ set_filter_mode(struct adapter *sc, uint32_t mode) } #ifdef TCP_OFFLOAD - if (sc->offload_map) { + if (uld_active(sc, ULD_TOM)) { rc = EBUSY; goto done; } @@ -8236,7 +8236,7 @@ toe_capability(struct port_info *pi, int enable) if (isset(&sc->offload_map, pi->port_id)) return (0); - if (!(sc->flags & TOM_INIT_DONE)) { + if (!uld_active(sc, ULD_TOM)) { rc = t4_activate_uld(sc, ULD_TOM); if (rc == EAGAIN) { log(LOG_WARNING, @@ -8247,16 +8247,22 @@ toe_capability(struct port_info *pi, int enable) return (rc); KASSERT(sc->tom_softc != NULL, ("%s: TOM activated but softc NULL", __func__)); - KASSERT(sc->flags & TOM_INIT_DONE, + KASSERT(uld_active(sc, ULD_TOM), ("%s: TOM activated but flag not set", __func__)); } + /* Activate iWARP and iSCSI too, if the modules are loaded. */ + if (!uld_active(sc, ULD_IWARP)) + (void) t4_activate_uld(sc, ULD_IWARP); + if (!uld_active(sc, ULD_ISCSI)) + (void) t4_activate_uld(sc, ULD_ISCSI); + setbit(&sc->offload_map, pi->port_id); } else { if (!isset(&sc->offload_map, pi->port_id)) return (0); - KASSERT(sc->flags & TOM_INIT_DONE, + KASSERT(uld_active(sc, ULD_TOM), ("%s: TOM never initialized?", __func__)); clrbit(&sc->offload_map, pi->port_id); } @@ -8316,11 +8322,15 @@ t4_unregister_uld(struct uld_info *ui) int t4_activate_uld(struct adapter *sc, int id) { - int rc = EAGAIN; + int rc; struct uld_info *ui; ASSERT_SYNCHRONIZED_OP(sc); + if (id < 0 || id > ULD_MAX) + return (EINVAL); + rc = EAGAIN; /* kldoad the module with this ULD and try again. */ + sx_slock(&t4_uld_list_lock); SLIST_FOREACH(ui, &t4_uld_list, link) { @@ -8328,16 +8338,18 @@ t4_activate_uld(struct adapter *sc, int id) if (!(sc->flags & FULL_INIT_DONE)) { rc = adapter_full_init(sc); if (rc != 0) - goto done; + break; } rc = ui->activate(sc); - if (rc == 0) + if (rc == 0) { + setbit(&sc->active_ulds, id); ui->refcount++; - goto done; + } + break; } } -done: + sx_sunlock(&t4_uld_list_lock); return (rc); @@ -8346,26 +8358,41 @@ t4_activate_uld(struct adapter *sc, int id) int t4_deactivate_uld(struct adapter *sc, int id) { - int rc = EINVAL; + int rc; struct uld_info *ui; ASSERT_SYNCHRONIZED_OP(sc); + if (id < 0 || id > ULD_MAX) + return (EINVAL); + rc = ENXIO; + sx_slock(&t4_uld_list_lock); SLIST_FOREACH(ui, &t4_uld_list, link) { if (ui->uld_id == id) { rc = ui->deactivate(sc); - if (rc == 0) + if (rc == 0) { + clrbit(&sc->active_ulds, id); ui->refcount--; - goto done; + } + break; } } -done: + sx_sunlock(&t4_uld_list_lock); return (rc); } + +int +uld_active(struct adapter *sc, int uld_id) +{ + + MPASS(uld_id >= 0 && uld_id <= ULD_MAX); + + return (isset(&sc->active_ulds, uld_id)); +} #endif /* diff --git a/sys/dev/cxgbe/tom/t4_listen.c b/sys/dev/cxgbe/tom/t4_listen.c index 4380c9ee92ac..e6cbfe4c9579 100644 --- a/sys/dev/cxgbe/tom/t4_listen.c +++ b/sys/dev/cxgbe/tom/t4_listen.c @@ -523,7 +523,7 @@ t4_listen_start(struct toedev *tod, struct tcpcb *tp) goto done; } - KASSERT(sc->flags & TOM_INIT_DONE, + KASSERT(uld_active(sc, ULD_TOM), ("%s: TOM not initialized", __func__)); #endif diff --git a/sys/dev/cxgbe/tom/t4_tom.c b/sys/dev/cxgbe/tom/t4_tom.c index 71ea1df58857..a980fba80a77 100644 --- a/sys/dev/cxgbe/tom/t4_tom.c +++ b/sys/dev/cxgbe/tom/t4_tom.c @@ -746,7 +746,7 @@ update_clip(struct adapter *sc, void *arg __unused) if (begin_synchronized_op(sc, NULL, HOLD_LOCK, "t4tomuc")) return; - if (sc->flags & TOM_INIT_DONE) + if (uld_active(sc, ULD_TOM)) update_clip_table(sc, sc->tom_softc); end_synchronized_op(sc, LOCK_HELD); @@ -1025,7 +1025,6 @@ t4_tom_activate(struct adapter *sc) TOEDEV(sc->port[i]->ifp) = &td->tod; sc->tom_softc = td; - sc->flags |= TOM_INIT_DONE; register_toedev(sc->tom_softc); done: @@ -1048,6 +1047,9 @@ t4_tom_deactivate(struct adapter *sc) if (sc->offload_map != 0) return (EBUSY); /* at least one port has IFCAP_TOE enabled */ + if (uld_active(sc, ULD_IWARP) || uld_active(sc, ULD_ISCSI)) + return (EBUSY); /* both iWARP and iSCSI rely on the TOE. */ + mtx_lock(&td->toep_list_lock); if (!TAILQ_EMPTY(&td->toep_list)) rc = EBUSY; @@ -1068,7 +1070,6 @@ t4_tom_deactivate(struct adapter *sc) unregister_toedev(sc->tom_softc); free_tom_data(sc, td); sc->tom_softc = NULL; - sc->flags &= ~TOM_INIT_DONE; } return (rc); @@ -1122,7 +1123,7 @@ tom_uninit(struct adapter *sc, void *arg __unused) return; /* Try to free resources (works only if no port has IFCAP_TOE) */ - if (sc->flags & TOM_INIT_DONE) + if (uld_active(sc, ULD_TOM)) t4_deactivate_uld(sc, ULD_TOM); end_synchronized_op(sc, 0); From d4b195d315907a711640f8a11a2dd636b3ec70ff Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sun, 8 Feb 2015 10:58:25 +0000 Subject: [PATCH 18/75] Make output of "iscsictl -v" and "ctladm islist -v" a little prettier by capitalizing "None". MFC after: 1 month Sponsored by: The FreeBSD Foundation --- sys/dev/iscsi/icl.c | 2 +- sys/dev/iscsi/icl_soft.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/dev/iscsi/icl.c b/sys/dev/iscsi/icl.c index a60313cf857b..2e92f2a4ed91 100644 --- a/sys/dev/iscsi/icl.c +++ b/sys/dev/iscsi/icl.c @@ -96,7 +96,7 @@ icl_find(const char *name) } TAILQ_FOREACH(im, &sc->sc_modules, im_next) { - if (strcmp(im->im_name, name) == 0) + if (strcasecmp(im->im_name, name) == 0) return (im); } diff --git a/sys/dev/iscsi/icl_soft.c b/sys/dev/iscsi/icl_soft.c index da8c926a963b..9d4747133103 100644 --- a/sys/dev/iscsi/icl_soft.c +++ b/sys/dev/iscsi/icl_soft.c @@ -1183,7 +1183,7 @@ icl_soft_new_conn(const char *name, struct mtx *lock) #endif ic->ic_max_data_segment_length = ICL_MAX_DATA_SEGMENT_LENGTH; ic->ic_name = name; - ic->ic_offload = "none"; + ic->ic_offload = "None"; return (ic); } From 5fea5a57b6284b16dd5af9e5586e4df66761a1bc Mon Sep 17 00:00:00 2001 From: Dmitry Chagin Date: Sun, 8 Feb 2015 11:55:29 +0000 Subject: [PATCH 19/75] Add Neoway WM620 module ID. MFC after: 1 Week --- sys/dev/usb/serial/u3g.c | 1 + sys/dev/usb/usbdevs | 1 + 2 files changed, 2 insertions(+) diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c index 2de5831cf0c4..c2d65c790cd4 100644 --- a/sys/dev/usb/serial/u3g.c +++ b/sys/dev/usb/serial/u3g.c @@ -399,6 +399,7 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = { U3G_DEV(QUALCOMM2, AC8700, 0), U3G_DEV(QUALCOMM2, MF330, 0), U3G_DEV(QUALCOMM2, SIM5218, 0), + U3G_DEV(QUALCOMM2, WM620, 0), U3G_DEV(QUALCOMM2, VW110L, U3GINIT_SCSIEJECT), U3G_DEV(QUALCOMM2, GOBI2000_QDL, 0), U3G_DEV(QUALCOMM2, GOBI2000, 0), diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index 53057e02d6a3..a40c913b20ad 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -3577,6 +3577,7 @@ product QUALCOMM2 CDMA_MSM 0x3196 CDMA Technologies MSM modem product QUALCOMM2 AC8700 0x6000 AC8700 product QUALCOMM2 VW110L 0x1000 Vertex Wireless 110L modem product QUALCOMM2 SIM5218 0x9000 SIM5218 +product QUALCOMM2 WM620 0x9002 Neoway WM620 product QUALCOMM2 GOBI2000_QDL 0x9204 Qualcomm Gobi 2000 QDL product QUALCOMM2 GOBI2000 0x9205 Qualcomm Gobi 2000 modem product QUALCOMM2 VT80N 0x6500 Venus VT80N From a840d2f5b82741d3415e81f9bf00223f70ac0f3d Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Sun, 8 Feb 2015 16:50:00 +0000 Subject: [PATCH 20/75] Add some error checking on the supplied page size list. This makes sure that we (a) get the correct large page size to provide to pmap and (b) we can alert the user if running under incorrectly-configured PowerKVM on POWER7 and POWER8 systems. MFC after: 1 week --- sys/powerpc/pseries/mmu_phyp.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/sys/powerpc/pseries/mmu_phyp.c b/sys/powerpc/pseries/mmu_phyp.c index cdf5dfefea55..c9d06e39ad3e 100644 --- a/sys/powerpc/pseries/mmu_phyp.c +++ b/sys/powerpc/pseries/mmu_phyp.c @@ -102,6 +102,7 @@ mphyp_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) char buf[8]; uint32_t prop[2]; uint32_t nptlp, shift = 0, slb_encoding = 0; + uint32_t lp_size, lp_encoding; phandle_t dev, node, root; int idx, len, res; @@ -148,9 +149,9 @@ mphyp_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) * We have to use a variable length array on the stack * since we have very limited stack space. */ - cell_t arr[len/sizeof(cell_t)]; - res = OF_getprop(node, "ibm,segment-page-sizes", &arr, - sizeof(arr)); + pcell_t arr[len/sizeof(cell_t)]; + res = OF_getencprop(node, "ibm,segment-page-sizes", arr, + sizeof(arr)); len /= 4; idx = 0; while (len > 0) { @@ -160,18 +161,26 @@ mphyp_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) idx += 3; len -= 3; while (len > 0 && nptlp) { + lp_size = arr[idx]; + lp_encoding = arr[idx+1]; + if (slb_encoding == SLBV_L && lp_encoding == 0) + break; + idx += 2; len -= 2; nptlp--; } + if (nptlp && slb_encoding == SLBV_L && lp_encoding == 0) + break; } - /* For now we allow shift only to be <= 0x18. */ - if (shift >= 0x18) - shift = 0x18; + if (len == 0) + panic("Standard large pages (SLB[L] = 1, PTE[LP] = 0) " + "not supported by this system. Please enable huge " + "page backing if running under PowerKVM."); moea64_large_page_shift = shift; - moea64_large_page_size = 1ULL << shift; + moea64_large_page_size = 1ULL << lp_size; } moea64_mid_bootstrap(mmup, kernelstart, kernelend); From 7a03d007cfcd2dba45cbe1bc1affe938fd375af6 Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sun, 8 Feb 2015 19:15:14 +0000 Subject: [PATCH 21/75] Extend ICL to add receive offload methods. For software ICL backend they are no-ops. MFC after: 1 month Sponsored by: The FreeBSD Foundation --- sys/cam/ctl/ctl_frontend_iscsi.c | 68 +++++++++++++++++++++++----- sys/cam/ctl/ctl_frontend_iscsi.h | 1 + sys/dev/iscsi/icl_conn_if.m | 24 ++++++++++ sys/dev/iscsi/icl_soft.c | 34 ++++++++++++++ sys/dev/iscsi/icl_wrappers.h | 30 +++++++++++++ sys/dev/iscsi/iscsi.c | 76 +++++++++++++++++++------------- sys/dev/iscsi/iscsi.h | 1 + 7 files changed, 193 insertions(+), 41 deletions(-) diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c index 4b8b4923d304..29054725d5ea 100644 --- a/sys/cam/ctl/ctl_frontend_iscsi.c +++ b/sys/cam/ctl/ctl_frontend_iscsi.c @@ -164,6 +164,12 @@ static void cfiscsi_pdu_handle_task_request(struct icl_pdu *request); static void cfiscsi_pdu_handle_data_out(struct icl_pdu *request); static void cfiscsi_pdu_handle_logout_request(struct icl_pdu *request); static void cfiscsi_session_terminate(struct cfiscsi_session *cs); +static struct cfiscsi_data_wait *cfiscsi_data_wait_new( + struct cfiscsi_session *cs, union ctl_io *io, + uint32_t initiator_task_tag, + uint32_t *target_transfer_tagp); +static void cfiscsi_data_wait_free(struct cfiscsi_session *cs, + struct cfiscsi_data_wait *cdw); static struct cfiscsi_target *cfiscsi_target_find(struct cfiscsi_softc *softc, const char *name, uint16_t tag); static struct cfiscsi_target *cfiscsi_target_find_or_create( @@ -929,7 +935,7 @@ cfiscsi_pdu_handle_data_out(struct icl_pdu *request) CFISCSI_SESSION_UNLOCK(cs); done = (io->scsiio.ext_data_filled != cdw->cdw_r2t_end || io->scsiio.ext_data_filled == io->scsiio.kern_data_len); - uma_zfree(cfiscsi_data_wait_zone, cdw); + cfiscsi_data_wait_free(cs, cdw); if (done) io->scsiio.be_move_done(io); else @@ -1067,6 +1073,45 @@ cfiscsi_callout(void *context) cfiscsi_pdu_queue(cp); } +static struct cfiscsi_data_wait * +cfiscsi_data_wait_new(struct cfiscsi_session *cs, union ctl_io *io, + uint32_t initiator_task_tag, uint32_t *target_transfer_tagp) +{ + struct cfiscsi_data_wait *cdw; + int error; + + cdw = uma_zalloc(cfiscsi_data_wait_zone, M_NOWAIT | M_ZERO); + if (cdw == NULL) { + CFISCSI_SESSION_WARN(cs, + "failed to allocate %zd bytes", sizeof(*cdw)); + return (NULL); + } + + error = icl_conn_transfer_setup(cs->cs_conn, io, target_transfer_tagp, + &cdw->cdw_icl_prv); + if (error != 0) { + CFISCSI_SESSION_WARN(cs, + "icl_conn_transfer_setup() failed with error %d", error); + uma_zfree(cfiscsi_data_wait_zone, cdw); + return (NULL); + } + + cdw->cdw_ctl_io = io; + cdw->cdw_target_transfer_tag = *target_transfer_tagp; + cdw->cdw_initiator_task_tag = initiator_task_tag; + + return (cdw); +} + +static void +cfiscsi_data_wait_free(struct cfiscsi_session *cs, + struct cfiscsi_data_wait *cdw) +{ + + icl_conn_transfer_done(cs->cs_conn, cdw->cdw_icl_prv); + uma_zfree(cfiscsi_data_wait_zone, cdw); +} + static void cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs) { @@ -1106,7 +1151,7 @@ cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs) */ cdw->cdw_ctl_io->scsiio.io_hdr.port_status = 42; cdw->cdw_ctl_io->scsiio.be_move_done(cdw->cdw_ctl_io); - uma_zfree(cfiscsi_data_wait_zone, cdw); + cfiscsi_data_wait_free(cs, cdw); CFISCSI_SESSION_LOCK(cs); } CFISCSI_SESSION_UNLOCK(cs); @@ -2600,13 +2645,8 @@ cfiscsi_datamove_out(union ctl_io *io) target_transfer_tag = atomic_fetchadd_32(&cs->cs_target_transfer_tag, 1); - -#if 0 - CFISCSI_SESSION_DEBUG(cs, "expecting Data-Out with initiator " - "task tag 0x%x, target transfer tag 0x%x", - bhssc->bhssc_initiator_task_tag, target_transfer_tag); -#endif - cdw = uma_zalloc(cfiscsi_data_wait_zone, M_NOWAIT | M_ZERO); + cdw = cfiscsi_data_wait_new(cs, io, bhssc->bhssc_initiator_task_tag, + &target_transfer_tag); if (cdw == NULL) { CFISCSI_SESSION_WARN(cs, "failed to " "allocate memory; dropping connection"); @@ -2615,6 +2655,12 @@ cfiscsi_datamove_out(union ctl_io *io) cfiscsi_session_terminate(cs); return; } +#if 0 + CFISCSI_SESSION_DEBUG(cs, "expecting Data-Out with initiator " + "task tag 0x%x, target transfer tag 0x%x", + bhssc->bhssc_initiator_task_tag, target_transfer_tag); +#endif + cdw->cdw_ctl_io = io; cdw->cdw_target_transfer_tag = target_transfer_tag; cdw->cdw_initiator_task_tag = bhssc->bhssc_initiator_task_tag; @@ -2651,7 +2697,7 @@ cfiscsi_datamove_out(union ctl_io *io) icl_pdu_data_segment_length(request)) { done = cfiscsi_handle_data_segment(request, cdw); if (done) { - uma_zfree(cfiscsi_data_wait_zone, cdw); + cfiscsi_data_wait_free(cs, cdw); io->scsiio.be_move_done(io); return; } @@ -2854,7 +2900,7 @@ cfiscsi_task_management_done(union ctl_io *io) TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next); cdw->cdw_ctl_io->scsiio.be_move_done(cdw->cdw_ctl_io); - uma_zfree(cfiscsi_data_wait_zone, cdw); + cfiscsi_data_wait_free(cs, cdw); } CFISCSI_SESSION_UNLOCK(cs); } diff --git a/sys/cam/ctl/ctl_frontend_iscsi.h b/sys/cam/ctl/ctl_frontend_iscsi.h index e1a094974378..140aa5223cee 100644 --- a/sys/cam/ctl/ctl_frontend_iscsi.h +++ b/sys/cam/ctl/ctl_frontend_iscsi.h @@ -59,6 +59,7 @@ struct cfiscsi_data_wait { size_t cdw_sg_len; uint32_t cdw_r2t_end; uint32_t cdw_datasn; + void *cdw_icl_prv; }; #define CFISCSI_SESSION_STATE_INVALID 0 diff --git a/sys/dev/iscsi/icl_conn_if.m b/sys/dev/iscsi/icl_conn_if.m index d3ac57f0420d..1a52882dd649 100644 --- a/sys/dev/iscsi/icl_conn_if.m +++ b/sys/dev/iscsi/icl_conn_if.m @@ -85,3 +85,27 @@ METHOD void close { METHOD bool connected { struct icl_conn *_ic; }; + +METHOD int task_setup { + struct icl_conn *_ic; + struct ccb_scsiio *_csio; + uint32_t *_task_tag; + void **_prvp; +}; + +METHOD void task_done { + struct icl_conn *_ic; + void *_prv; +}; + +METHOD int transfer_setup { + struct icl_conn *_ic; + union ctl_io *_io; + uint32_t *_transfer_tag; + void **_prvp; +}; + +METHOD void transfer_done { + struct icl_conn *_ic; + void *_prv; +}; diff --git a/sys/dev/iscsi/icl_soft.c b/sys/dev/iscsi/icl_soft.c index 9d4747133103..2dd5e5c40044 100644 --- a/sys/dev/iscsi/icl_soft.c +++ b/sys/dev/iscsi/icl_soft.c @@ -98,6 +98,10 @@ static icl_conn_handoff_t icl_soft_conn_handoff; static icl_conn_free_t icl_soft_conn_free; static icl_conn_close_t icl_soft_conn_close; static icl_conn_connected_t icl_soft_conn_connected; +static icl_conn_task_setup_t icl_soft_conn_task_setup; +static icl_conn_task_done_t icl_soft_conn_task_done; +static icl_conn_transfer_setup_t icl_soft_conn_transfer_setup; +static icl_conn_transfer_done_t icl_soft_conn_transfer_done; static kobj_method_t icl_soft_methods[] = { KOBJMETHOD(icl_conn_new_pdu, icl_soft_conn_new_pdu), @@ -111,6 +115,10 @@ static kobj_method_t icl_soft_methods[] = { KOBJMETHOD(icl_conn_free, icl_soft_conn_free), KOBJMETHOD(icl_conn_close, icl_soft_conn_close), KOBJMETHOD(icl_conn_connected, icl_soft_conn_connected), + KOBJMETHOD(icl_conn_task_setup, icl_soft_conn_task_setup), + KOBJMETHOD(icl_conn_task_done, icl_soft_conn_task_done), + KOBJMETHOD(icl_conn_transfer_setup, icl_soft_conn_transfer_setup), + KOBJMETHOD(icl_conn_transfer_done, icl_soft_conn_transfer_done), { 0, 0 } }; @@ -1435,6 +1443,32 @@ icl_soft_conn_connected(struct icl_conn *ic) return (true); } +int +icl_soft_conn_task_setup(struct icl_conn *ic, struct ccb_scsiio *csio, + uint32_t *task_tagp, void **prvp) +{ + + return (0); +} + +void +icl_soft_conn_task_done(struct icl_conn *ic, void *prv) +{ +} + +int +icl_soft_conn_transfer_setup(struct icl_conn *ic, union ctl_io *io, + uint32_t *transfer_tag, void **prvp) +{ + + return (0); +} + +void +icl_soft_conn_transfer_done(struct icl_conn *ic, void *prv) +{ +} + static int icl_soft_limits(size_t *limitp) { diff --git a/sys/dev/iscsi/icl_wrappers.h b/sys/dev/iscsi/icl_wrappers.h index 22cf0a6e2214..2cf7d96446fc 100644 --- a/sys/dev/iscsi/icl_wrappers.h +++ b/sys/dev/iscsi/icl_wrappers.h @@ -112,4 +112,34 @@ icl_conn_connected(struct icl_conn *ic) return (ICL_CONN_CONNECTED(ic)); } +static inline int +icl_conn_task_setup(struct icl_conn *ic, struct ccb_scsiio *csio, + uint32_t *task_tagp, void **prvp) +{ + + return (ICL_CONN_TASK_SETUP(ic, csio, task_tagp, prvp)); +} + +static inline void +icl_conn_task_done(struct icl_conn *ic, void *prv) +{ + + ICL_CONN_TASK_DONE(ic, prv); +} + +static inline int +icl_conn_transfer_setup(struct icl_conn *ic, union ctl_io *io, + uint32_t *transfer_tagp, void **prvp) +{ + + return (ICL_CONN_TRANSFER_SETUP(ic, io, transfer_tagp, prvp)); +} + +static inline void +icl_conn_transfer_done(struct icl_conn *ic, void *prv) +{ + + ICL_CONN_TRANSFER_DONE(ic, prv); +} + #endif /* !ICL_WRAPPERS_H */ diff --git a/sys/dev/iscsi/iscsi.c b/sys/dev/iscsi/iscsi.c index 0b2dcb279574..5188ac827664 100644 --- a/sys/dev/iscsi/iscsi.c +++ b/sys/dev/iscsi/iscsi.c @@ -169,7 +169,7 @@ static void iscsi_poll(struct cam_sim *sim); static struct iscsi_outstanding *iscsi_outstanding_find(struct iscsi_session *is, uint32_t initiator_task_tag); static struct iscsi_outstanding *iscsi_outstanding_add(struct iscsi_session *is, - uint32_t initiator_task_tag, union ccb *ccb); + union ccb *ccb, uint32_t *initiator_task_tagp); static void iscsi_outstanding_remove(struct iscsi_session *is, struct iscsi_outstanding *io); @@ -1993,21 +1993,33 @@ iscsi_outstanding_find_ccb(struct iscsi_session *is, union ccb *ccb) static struct iscsi_outstanding * iscsi_outstanding_add(struct iscsi_session *is, - uint32_t initiator_task_tag, union ccb *ccb) + union ccb *ccb, uint32_t *initiator_task_tagp) { struct iscsi_outstanding *io; + int error; ISCSI_SESSION_LOCK_ASSERT(is); - KASSERT(iscsi_outstanding_find(is, initiator_task_tag) == NULL, - ("initiator_task_tag 0x%x already added", initiator_task_tag)); - io = uma_zalloc(iscsi_outstanding_zone, M_NOWAIT | M_ZERO); if (io == NULL) { - ISCSI_SESSION_WARN(is, "failed to allocate %zd bytes", sizeof(*io)); + ISCSI_SESSION_WARN(is, "failed to allocate %zd bytes", + sizeof(*io)); return (NULL); } - io->io_initiator_task_tag = initiator_task_tag; + + error = icl_conn_task_setup(is->is_conn, &ccb->csio, + initiator_task_tagp, &io->io_icl_prv); + if (error != 0) { + ISCSI_SESSION_WARN(is, + "icl_conn_task_setup() failed with error %d", error); + uma_zfree(iscsi_outstanding_zone, io); + return (NULL); + } + + KASSERT(iscsi_outstanding_find(is, *initiator_task_tagp) == NULL, + ("initiator_task_tag 0x%x already added", *initiator_task_tagp)); + + io->io_initiator_task_tag = *initiator_task_tagp; io->io_ccb = ccb; TAILQ_INSERT_TAIL(&is->is_outstanding, io, io_next); return (io); @@ -2019,6 +2031,7 @@ iscsi_outstanding_remove(struct iscsi_session *is, struct iscsi_outstanding *io) ISCSI_SESSION_LOCK_ASSERT(is); + icl_conn_task_done(is->is_conn, io->io_icl_prv); TAILQ_REMOVE(&is->is_outstanding, io, io_next); uma_zfree(iscsi_outstanding_zone, io); } @@ -2030,6 +2043,7 @@ iscsi_action_abort(struct iscsi_session *is, union ccb *ccb) struct iscsi_bhs_task_management_request *bhstmr; struct ccb_abort *cab = &ccb->cab; struct iscsi_outstanding *io, *aio; + uint32_t initiator_task_tag; ISCSI_SESSION_LOCK_ASSERT(is); @@ -2057,16 +2071,9 @@ iscsi_action_abort(struct iscsi_session *is, union ccb *ccb) return; } - bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs; - bhstmr->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_REQUEST; - bhstmr->bhstmr_function = 0x80 | BHSTMR_FUNCTION_ABORT_TASK; + initiator_task_tag = is->is_initiator_task_tag++; - bhstmr->bhstmr_lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun)); - bhstmr->bhstmr_initiator_task_tag = is->is_initiator_task_tag; - is->is_initiator_task_tag++; - bhstmr->bhstmr_referenced_task_tag = aio->io_initiator_task_tag; - - io = iscsi_outstanding_add(is, bhstmr->bhstmr_initiator_task_tag, NULL); + io = iscsi_outstanding_add(is, NULL, &initiator_task_tag); if (io == NULL) { icl_pdu_free(request); ccb->ccb_h.status = CAM_RESRC_UNAVAIL; @@ -2074,6 +2081,14 @@ iscsi_action_abort(struct iscsi_session *is, union ccb *ccb) return; } io->io_datasn = aio->io_initiator_task_tag; + + bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs; + bhstmr->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_REQUEST; + bhstmr->bhstmr_function = 0x80 | BHSTMR_FUNCTION_ABORT_TASK; + bhstmr->bhstmr_lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun)); + bhstmr->bhstmr_initiator_task_tag = initiator_task_tag; + bhstmr->bhstmr_referenced_task_tag = aio->io_initiator_task_tag; + iscsi_pdu_queue_locked(request); } @@ -2085,6 +2100,7 @@ iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb) struct ccb_scsiio *csio; struct iscsi_outstanding *io; size_t len; + uint32_t initiator_task_tag; int error; ISCSI_SESSION_LOCK_ASSERT(is); @@ -2115,6 +2131,19 @@ iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb) return; } + initiator_task_tag = is->is_initiator_task_tag++; + io = iscsi_outstanding_add(is, ccb, &initiator_task_tag); + if (io == NULL) { + icl_pdu_free(request); + if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { + xpt_freeze_devq(ccb->ccb_h.path, 1); + ISCSI_SESSION_DEBUG(is, "freezing devq"); + } + ccb->ccb_h.status = CAM_RESRC_UNAVAIL | CAM_DEV_QFRZN; + xpt_done(ccb); + return; + } + csio = &ccb->csio; bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs; bhssc->bhssc_opcode = ISCSI_BHS_OPCODE_SCSI_COMMAND; @@ -2148,8 +2177,7 @@ iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb) bhssc->bhssc_flags |= BHSSC_FLAGS_ATTR_UNTAGGED; bhssc->bhssc_lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun)); - bhssc->bhssc_initiator_task_tag = is->is_initiator_task_tag; - is->is_initiator_task_tag++; + bhssc->bhssc_initiator_task_tag = initiator_task_tag; bhssc->bhssc_expected_data_transfer_length = htonl(csio->dxfer_len); KASSERT(csio->cdb_len <= sizeof(bhssc->bhssc_cdb), ("unsupported CDB size %zd", (size_t)csio->cdb_len)); @@ -2159,18 +2187,6 @@ iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb) else memcpy(&bhssc->bhssc_cdb, csio->cdb_io.cdb_bytes, csio->cdb_len); - io = iscsi_outstanding_add(is, bhssc->bhssc_initiator_task_tag, ccb); - if (io == NULL) { - icl_pdu_free(request); - if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { - xpt_freeze_devq(ccb->ccb_h.path, 1); - ISCSI_SESSION_DEBUG(is, "freezing devq"); - } - ccb->ccb_h.status = CAM_RESRC_UNAVAIL | CAM_DEV_QFRZN; - xpt_done(ccb); - return; - } - if (is->is_immediate_data && (csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { len = csio->dxfer_len; diff --git a/sys/dev/iscsi/iscsi.h b/sys/dev/iscsi/iscsi.h index 0fe1515c2b6d..fd52fa87a954 100644 --- a/sys/dev/iscsi/iscsi.h +++ b/sys/dev/iscsi/iscsi.h @@ -45,6 +45,7 @@ struct iscsi_outstanding { size_t io_received; uint32_t io_initiator_task_tag; uint32_t io_datasn; + void *io_icl_prv; }; struct iscsi_session { From d5153415b8c1a25e4b28baae992e319924431d3c Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sun, 8 Feb 2015 19:18:23 +0000 Subject: [PATCH 22/75] Fix ordering of "*logout" and "*terminate"; no functional changes. MFC after: 1 month Sponsored by: The FreeBSD Foundation --- sys/cam/ctl/ctl_frontend_iscsi.c | 104 +++++++++++++++---------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c index 29054725d5ea..2742c3da4893 100644 --- a/sys/cam/ctl/ctl_frontend_iscsi.c +++ b/sys/cam/ctl/ctl_frontend_iscsi.c @@ -1701,6 +1701,55 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci) sbuf_delete(sb); } +static void +cfiscsi_ioctl_logout(struct ctl_iscsi *ci) +{ + struct icl_pdu *response; + struct iscsi_bhs_asynchronous_message *bhsam; + struct ctl_iscsi_logout_params *cilp; + struct cfiscsi_session *cs; + struct cfiscsi_softc *softc; + int found = 0; + + cilp = (struct ctl_iscsi_logout_params *)&(ci->data); + softc = &cfiscsi_softc; + + mtx_lock(&softc->lock); + TAILQ_FOREACH(cs, &softc->sessions, cs_next) { + if (cilp->all == 0 && cs->cs_id != cilp->connection_id && + strcmp(cs->cs_initiator_name, cilp->initiator_name) != 0 && + strcmp(cs->cs_initiator_addr, cilp->initiator_addr) != 0) + continue; + + response = icl_pdu_new(cs->cs_conn, M_NOWAIT); + if (response == NULL) { + ci->status = CTL_ISCSI_ERROR; + snprintf(ci->error_str, sizeof(ci->error_str), + "Unable to allocate memory"); + mtx_unlock(&softc->lock); + return; + } + bhsam = + (struct iscsi_bhs_asynchronous_message *)response->ip_bhs; + bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE; + bhsam->bhsam_flags = 0x80; + bhsam->bhsam_async_event = BHSAM_EVENT_TARGET_REQUESTS_LOGOUT; + bhsam->bhsam_parameter3 = htons(10); + cfiscsi_pdu_queue(response); + found++; + } + mtx_unlock(&softc->lock); + + if (found == 0) { + ci->status = CTL_ISCSI_SESSION_NOT_FOUND; + snprintf(ci->error_str, sizeof(ci->error_str), + "No matching connections found"); + return; + } + + ci->status = CTL_ISCSI_OK; +} + static void cfiscsi_ioctl_terminate(struct ctl_iscsi *ci) { @@ -1751,55 +1800,6 @@ cfiscsi_ioctl_terminate(struct ctl_iscsi *ci) ci->status = CTL_ISCSI_OK; } -static void -cfiscsi_ioctl_logout(struct ctl_iscsi *ci) -{ - struct icl_pdu *response; - struct iscsi_bhs_asynchronous_message *bhsam; - struct ctl_iscsi_logout_params *cilp; - struct cfiscsi_session *cs; - struct cfiscsi_softc *softc; - int found = 0; - - cilp = (struct ctl_iscsi_logout_params *)&(ci->data); - softc = &cfiscsi_softc; - - mtx_lock(&softc->lock); - TAILQ_FOREACH(cs, &softc->sessions, cs_next) { - if (cilp->all == 0 && cs->cs_id != cilp->connection_id && - strcmp(cs->cs_initiator_name, cilp->initiator_name) != 0 && - strcmp(cs->cs_initiator_addr, cilp->initiator_addr) != 0) - continue; - - response = icl_pdu_new(cs->cs_conn, M_NOWAIT); - if (response == NULL) { - ci->status = CTL_ISCSI_ERROR; - snprintf(ci->error_str, sizeof(ci->error_str), - "Unable to allocate memory"); - mtx_unlock(&softc->lock); - return; - } - bhsam = - (struct iscsi_bhs_asynchronous_message *)response->ip_bhs; - bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE; - bhsam->bhsam_flags = 0x80; - bhsam->bhsam_async_event = BHSAM_EVENT_TARGET_REQUESTS_LOGOUT; - bhsam->bhsam_parameter3 = htons(10); - cfiscsi_pdu_queue(response); - found++; - } - mtx_unlock(&softc->lock); - - if (found == 0) { - ci->status = CTL_ISCSI_SESSION_NOT_FOUND; - snprintf(ci->error_str, sizeof(ci->error_str), - "No matching connections found"); - return; - } - - ci->status = CTL_ISCSI_OK; -} - static void cfiscsi_ioctl_limits(struct ctl_iscsi *ci) { @@ -2241,12 +2241,12 @@ cfiscsi_ioctl(struct cdev *dev, case CTL_ISCSI_LIST: cfiscsi_ioctl_list(ci); break; - case CTL_ISCSI_TERMINATE: - cfiscsi_ioctl_terminate(ci); - break; case CTL_ISCSI_LOGOUT: cfiscsi_ioctl_logout(ci); break; + case CTL_ISCSI_TERMINATE: + cfiscsi_ioctl_terminate(ci); + break; case CTL_ISCSI_LIMITS: cfiscsi_ioctl_limits(ci); break; From f4c6aea395327227f18046d494115d46b00e90f0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 8 Feb 2015 21:00:51 +0000 Subject: [PATCH 23/75] Preset the object's color, or alignment, to maximize superpage usage. MFC after: 5 days --- sys/kern/uipc_shm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c index 7829620a7be6..1df89ad61e6f 100644 --- a/sys/kern/uipc_shm.c +++ b/sys/kern/uipc_shm.c @@ -531,9 +531,10 @@ shm_alloc(struct ucred *ucred, mode_t mode) shmfd->shm_object = vm_pager_allocate(OBJT_DEFAULT, NULL, shmfd->shm_size, VM_PROT_DEFAULT, 0, ucred); KASSERT(shmfd->shm_object != NULL, ("shm_create: vm_pager_allocate")); + shmfd->shm_object->pg_color = 0; VM_OBJECT_WLOCK(shmfd->shm_object); vm_object_clear_flag(shmfd->shm_object, OBJ_ONEMAPPING); - vm_object_set_flag(shmfd->shm_object, OBJ_NOSPLIT); + vm_object_set_flag(shmfd->shm_object, OBJ_COLORED | OBJ_NOSPLIT); VM_OBJECT_WUNLOCK(shmfd->shm_object); vfs_timestamp(&shmfd->shm_birthtime); shmfd->shm_atime = shmfd->shm_mtime = shmfd->shm_ctime = From 6062b7ccd9b89c31308cf7044f42e9f5db5deff8 Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Sun, 8 Feb 2015 22:24:18 +0000 Subject: [PATCH 24/75] Reapply r255891 --- lib/libedit/readline.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/libedit/readline.c b/lib/libedit/readline.c index a7d13506a2bc..990270fc90ec 100644 --- a/lib/libedit/readline.c +++ b/lib/libedit/readline.c @@ -395,6 +395,9 @@ readline(const char *p) char *buf; static int used_event_hook; + if (line == NULL) + return 0; + if (e == NULL || h == NULL) rl_initialize(); From 0f638f5385c5ebce5fa97db7c9797bd780bcb81c Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Sun, 8 Feb 2015 23:03:41 +0000 Subject: [PATCH 25/75] revert r278414 Reported by: bz --- lib/libedit/readline.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/libedit/readline.c b/lib/libedit/readline.c index 990270fc90ec..a7d13506a2bc 100644 --- a/lib/libedit/readline.c +++ b/lib/libedit/readline.c @@ -395,9 +395,6 @@ readline(const char *p) char *buf; static int used_event_hook; - if (line == NULL) - return 0; - if (e == NULL || h == NULL) rl_initialize(); From 0eb1bfa5e7051939e76be07de1e872e467246c30 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Mon, 9 Feb 2015 02:12:38 +0000 Subject: [PATCH 26/75] Simplify trapcode setup by placing a copy of the generic trap handler at every possible trap address by default. This also makes sure the kernel notices (and panics at) traps from newer CPUs that the kernel was not expecting rather than executing gibberish memory. --- sys/powerpc/aim/machdep.c | 67 +++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index 020c07ab48f1..2980b0997783 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -256,6 +256,7 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) vm_offset_t startkernel, endkernel; void *generictrap; size_t trap_offset, trapsize; + vm_offset_t trap; void *kmdp; char *env; register_t msr, scratch; @@ -480,20 +481,6 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) bcopy(&rfid_patch,&rfi_patch2,4); #endif - /* - * Copy a code snippet to restore 32-bit bridge mode - * to the top of every non-generic trap handler - */ - - trap_offset += (size_t)&restorebridgesize; - bcopy(&restorebridge, (void *)EXC_RST, trap_offset); - bcopy(&restorebridge, (void *)EXC_DSI, trap_offset); - bcopy(&restorebridge, (void *)EXC_ALI, trap_offset); - bcopy(&restorebridge, (void *)EXC_PGM, trap_offset); - bcopy(&restorebridge, (void *)EXC_MCHK, trap_offset); - bcopy(&restorebridge, (void *)EXC_TRC, trap_offset); - bcopy(&restorebridge, (void *)EXC_BPT, trap_offset); - /* * Set the common trap entry point to the one that * knows to restore 32-bit operation on execution. @@ -507,14 +494,35 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) #else /* powerpc64 */ cpu_features |= PPC_FEATURE_64; generictrap = &trapcode; - - /* Set TOC base so that the interrupt code can get at it */ - *((void **)TRAP_GENTRAP) = &trapcode2; - *((register_t *)TRAP_TOCBASE) = toc; #endif trapsize = (size_t)&trapcodeend - (size_t)&trapcode; + /* + * Copy generic handler into every possible trap. Special cases will get + * different ones in a minute. + */ + for (trap = EXC_RST; trap < EXC_LAST; trap += 0x20) + bcopy(generictrap, (void *)trap, trapsize); + + #ifndef __powerpc64__ + if (cpu_features & PPC_FEATURE_64) { + /* + * Copy a code snippet to restore 32-bit bridge mode + * to the top of every non-generic trap handler + */ + + trap_offset += (size_t)&restorebridgesize; + bcopy(&restorebridge, (void *)EXC_RST, trap_offset); + bcopy(&restorebridge, (void *)EXC_DSI, trap_offset); + bcopy(&restorebridge, (void *)EXC_ALI, trap_offset); + bcopy(&restorebridge, (void *)EXC_PGM, trap_offset); + bcopy(&restorebridge, (void *)EXC_MCHK, trap_offset); + bcopy(&restorebridge, (void *)EXC_TRC, trap_offset); + bcopy(&restorebridge, (void *)EXC_BPT, trap_offset); + } + #endif + bcopy(&rstcode, (void *)(EXC_RST + trap_offset), (size_t)&rstcodeend - (size_t)&rstcode); @@ -527,31 +535,20 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) (size_t)&dblow); bcopy(&dblow, (void *)(EXC_BPT + trap_offset), (size_t)&dbend - (size_t)&dblow); -#else - bcopy(generictrap, (void *)EXC_MCHK, trapsize); - bcopy(generictrap, (void *)EXC_PGM, trapsize); - bcopy(generictrap, (void *)EXC_TRC, trapsize); - bcopy(generictrap, (void *)EXC_BPT, trapsize); #endif bcopy(&alitrap, (void *)(EXC_ALI + trap_offset), (size_t)&aliend - (size_t)&alitrap); bcopy(&dsitrap, (void *)(EXC_DSI + trap_offset), (size_t)&dsiend - (size_t)&dsitrap); - bcopy(generictrap, (void *)EXC_ISI, trapsize); + #ifdef __powerpc64__ + /* Set TOC base so that the interrupt code can get at it */ + *((void **)TRAP_GENTRAP) = &trapcode2; + *((register_t *)TRAP_TOCBASE) = toc; + bcopy(&slbtrap, (void *)EXC_DSE,(size_t)&slbtrapend - (size_t)&slbtrap); bcopy(&slbtrap, (void *)EXC_ISE,(size_t)&slbtrapend - (size_t)&slbtrap); - #endif - bcopy(generictrap, (void *)EXC_EXI, trapsize); - bcopy(generictrap, (void *)EXC_FPU, trapsize); - bcopy(generictrap, (void *)EXC_DECR, trapsize); - bcopy(generictrap, (void *)EXC_SC, trapsize); - bcopy(generictrap, (void *)EXC_FPA, trapsize); - bcopy(generictrap, (void *)EXC_VEC, trapsize); - bcopy(generictrap, (void *)EXC_PERF, trapsize); - bcopy(generictrap, (void *)EXC_VECAST_G4, trapsize); - bcopy(generictrap, (void *)EXC_VECAST_G5, trapsize); - #ifndef __powerpc64__ + #else /* G2-specific TLB miss helper handlers */ bcopy(&imisstrap, (void *)EXC_IMISS, (size_t)&imisssize); bcopy(&dlmisstrap, (void *)EXC_DLMISS, (size_t)&dlmisssize); From f1e484179757d5fe3c43ed31972b6bf6e034c012 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Mon, 9 Feb 2015 02:13:36 +0000 Subject: [PATCH 27/75] Technically speaking, using one virtal processor area for all CPUs is a violation of the spec. Make duplicate entries for each CPU. --- sys/powerpc/pseries/platform_chrp.c | 32 ++++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/sys/powerpc/pseries/platform_chrp.c b/sys/powerpc/pseries/platform_chrp.c index 115d062b480d..eb86ec74ce29 100644 --- a/sys/powerpc/pseries/platform_chrp.c +++ b/sys/powerpc/pseries/platform_chrp.c @@ -58,7 +58,7 @@ extern void *ap_pcpu; #endif #ifdef __powerpc64__ -static uint8_t splpar_vpa[640] __aligned(64); +static uint8_t splpar_vpa[MAXCPU][640] __aligned(128); /* XXX: dpcpu */ #endif static vm_offset_t realmaxaddr = VM_MAX_ADDRESS; @@ -124,6 +124,8 @@ chrp_probe(platform_t plat) static int chrp_attach(platform_t plat) { + int i; + #ifdef __powerpc64__ /* XXX: check for /rtas/ibm,hypertas-functions? */ if (!(mfmsr() & PSL_HV)) { @@ -136,14 +138,19 @@ chrp_attach(platform_t plat) cpu_idle_hook = phyp_cpu_idle; /* Set up important VPA fields */ - bzero(splpar_vpa, sizeof(splpar_vpa)); - splpar_vpa[4] = (uint8_t)((sizeof(splpar_vpa) >> 8) & 0xff); - splpar_vpa[5] = (uint8_t)(sizeof(splpar_vpa) & 0xff); - splpar_vpa[0xba] = 1; /* Maintain FPRs */ - splpar_vpa[0xbb] = 1; /* Maintain PMCs */ - splpar_vpa[0xfc] = 0xff; /* Maintain full SLB */ - splpar_vpa[0xfd] = 0xff; - splpar_vpa[0xff] = 1; /* Maintain Altivec */ + for (i = 0; i < MAXCPU; i++) { + bzero(splpar_vpa[i], sizeof(splpar_vpa)); + /* First two: VPA size */ + splpar_vpa[i][4] = + (uint8_t)((sizeof(splpar_vpa[i]) >> 8) & 0xff); + splpar_vpa[i][5] = + (uint8_t)(sizeof(splpar_vpa[i]) & 0xff); + splpar_vpa[i][0xba] = 1; /* Maintain FPRs */ + splpar_vpa[i][0xbb] = 1; /* Maintain PMCs */ + splpar_vpa[i][0xfc] = 0xff; /* Maintain full SLB */ + splpar_vpa[i][0xfd] = 0xff; + splpar_vpa[i][0xff] = 1; /* Maintain Altivec */ + } mb(); /* Set up hypervisor CPU stuff */ @@ -492,11 +499,12 @@ static void chrp_smp_ap_init(platform_t platform) { if (!(mfmsr() & PSL_HV)) { + /* Register VPA */ + phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(cpuid), + splpar_vpa[PCPU_GET(cpuid)]); + /* Set interrupt priority */ phyp_hcall(H_CPPR, 0xff); - - /* Register VPA */ - phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(cpuid), splpar_vpa); } } #else From 53607fe3cc8d46cfc7dd2399f1adc8b9581dc5a9 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Mon, 9 Feb 2015 02:17:21 +0000 Subject: [PATCH 28/75] Fix an extremely subtle concurrency bug triggered by running on 32-thread POWER8 systems. During thread switch, there was a very small window when the stack pointer was set to the stack pointer of the outgoing thread, but after the lock on that thread had already been released. If, during that window, the outgoing thread were rescheduled on another CPU and begin execution and an exception were taken on the original CPU, the trap handler and the outgoing thread would simultaneously execute on the same stack, causing memory corruption. Fix this by making sure to release the old thread only after cpu_switch() is done with its stack. MFC after: 2 weeks Sponsored by: FreeBSD Foundation --- sys/powerpc/powerpc/swtch64.S | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sys/powerpc/powerpc/swtch64.S b/sys/powerpc/powerpc/swtch64.S index 6722bb642135..ffecd1eb7b26 100644 --- a/sys/powerpc/powerpc/swtch64.S +++ b/sys/powerpc/powerpc/swtch64.S @@ -72,6 +72,8 @@ TOC_ENTRY(blocked_lock) */ ENTRY(cpu_throw) mr %r13, %r4 + li %r14,0 /* Tell cpu_switchin not to release a thread */ + b cpu_switchin /* @@ -139,10 +141,7 @@ ENTRY(cpu_switch) bl pmap_deactivate /* Deactivate the current pmap */ nop - addi %r1,%r1,48 - sync /* Make sure all of that finished */ - std %r16,TD_LOCK(%r14) /* ULE: update old thread's lock */ cpu_switchin: #if defined(SMP) && defined(SCHED_ULE) @@ -154,14 +153,20 @@ blocked_loop: beq- blocked_loop isync #endif + + ld %r17,TD_PCB(%r13) /* Get new PCB */ + ld %r1,PCB_SP(%r17) /* Load the stack pointer */ - mfsprg %r7,0 /* Get the pcpu pointer */ + /* Release old thread now that we have a stack pointer set up */ + cmpdi %r14,0 + beq- 1f + std %r16,TD_LOCK(%r14) /* ULE: update old thread's lock */ + +1: mfsprg %r7,0 /* Get the pcpu pointer */ std %r13,PC_CURTHREAD(%r7) /* Store new current thread */ ld %r17,TD_PCB(%r13) /* Store new current PCB */ std %r17,PC_CURPCB(%r7) - stdu %r1,-48(%r1) - mr %r3,%r13 /* Get new thread ptr */ bl pmap_activate /* Activate the new address space */ nop From e6bf0bdb36523147e7667fdd6ecc99a31a3203e7 Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Mon, 9 Feb 2015 02:27:33 +0000 Subject: [PATCH 29/75] Remove unused variables --- sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c | 2 -- sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c | 1 - 2 files changed, 3 deletions(-) diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c index a036ef41d746..a7c9683a39dc 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c @@ -252,7 +252,6 @@ VCHIQ_STATUS_T vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle, void *offset, int size, int dir) { - PAGELIST_T *pagelist; BULKINFO_T *bi; int ret; @@ -518,7 +517,6 @@ free_pagelist(BULKINFO_T *bi, int actual) { vm_page_t*pages; unsigned int num_pages, i; - void *page_address; PAGELIST_T *pagelist; pagelist = bi->pagelist; diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c index ff89ef11396b..d534a7fa755f 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c @@ -2387,7 +2387,6 @@ vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service) VCHIQ_STATUS_T ret = VCHIQ_SUCCESS; char entity[16]; int *entity_uc; - int local_uc, local_entity_uc; if (!arm_state) goto out; From 10e99e605728c341e59f41255fc3dd326d647938 Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Mon, 9 Feb 2015 02:31:27 +0000 Subject: [PATCH 30/75] Do not mark shared structures as __packed, it leads to race condition If structure packed as __packed clang (and probably gcc) generates code that loads word fields (e.g. tx_pos) byte-by-byte and if it's modified by VideoCore in the same time as ARM loads the value result is going to be mixed combination of bytes from previous value and new one. --- sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h index 298a0cc2f2c8..fb50e85f2d88 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h @@ -280,7 +280,7 @@ typedef struct vchiq_slot_info_struct { /* Use two counters rather than one to avoid the need for a mutex. */ short use_count; short release_count; -} __packed VCHIQ_SLOT_INFO_T; /* XXXGONZO: check it */ +} VCHIQ_SLOT_INFO_T; typedef struct vchiq_service_struct { VCHIQ_SERVICE_BASE_T base; @@ -381,7 +381,7 @@ typedef struct vchiq_shared_state_struct { /* Debugging state */ int debug[DEBUG_MAX]; -} __packed VCHIQ_SHARED_STATE_T; +} VCHIQ_SHARED_STATE_T; typedef struct vchiq_slot_zero_struct { int magic; @@ -395,7 +395,7 @@ typedef struct vchiq_slot_zero_struct { VCHIQ_SHARED_STATE_T master; VCHIQ_SHARED_STATE_T slave; VCHIQ_SLOT_INFO_T slots[VCHIQ_MAX_SLOTS]; -} __packed VCHIQ_SLOT_ZERO_T; +} VCHIQ_SLOT_ZERO_T; struct vchiq_state_struct { int id; From 07e765cd81991c749b02113ec753da7eec5a84e0 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Mon, 9 Feb 2015 07:08:54 +0000 Subject: [PATCH 31/75] Fix typo in PTE insertion overflow handling: use the page we're actually returning, not the one we just looked at. --- sys/powerpc/pseries/mmu_phyp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/powerpc/pseries/mmu_phyp.c b/sys/powerpc/pseries/mmu_phyp.c index c9d06e39ad3e..5f7db69f62ed 100644 --- a/sys/powerpc/pseries/mmu_phyp.c +++ b/sys/powerpc/pseries/mmu_phyp.c @@ -299,7 +299,10 @@ mphyp_pte_spillable_ident(u_int ptegidx, struct lpte *to_evict) } } - phyp_pft_hcall(H_READ, 0, slot, 0, 0, &to_evict->pte_hi, + if (k == -1) + return (k); + + phyp_pft_hcall(H_READ, 0, k, 0, 0, &to_evict->pte_hi, &to_evict->pte_lo, &junk); return (k); } From a6ebe06637516b22a9f077bd65ae4e0ab6e02fbd Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Mon, 9 Feb 2015 07:56:50 +0000 Subject: [PATCH 32/75] After r278004 was committed, Bruce Evans noted that the casts were actually completely unnecessary, here: https://lists.freebsd.org/pipermail/svn-src-all/2015-February/098478.html Remove the casts, and just assign &xxx_io_mc_regs[0][0] directly. Reviewed by: dumbbell MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D1748 --- sys/dev/drm2/radeon/ni.c | 8 ++++---- sys/dev/drm2/radeon/si.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sys/dev/drm2/radeon/ni.c b/sys/dev/drm2/radeon/ni.c index 6f9a9668ba87..1484b3ed59a2 100644 --- a/sys/dev/drm2/radeon/ni.c +++ b/sys/dev/drm2/radeon/ni.c @@ -190,23 +190,23 @@ int ni_mc_load_microcode(struct radeon_device *rdev) switch (rdev->family) { case CHIP_BARTS: - io_mc_regs = (const u32 *)&barts_io_mc_regs; + io_mc_regs = &barts_io_mc_regs[0][0]; ucode_size = BTC_MC_UCODE_SIZE; regs_size = BTC_IO_MC_REGS_SIZE; break; case CHIP_TURKS: - io_mc_regs = (const u32 *)&turks_io_mc_regs; + io_mc_regs = &turks_io_mc_regs[0][0]; ucode_size = BTC_MC_UCODE_SIZE; regs_size = BTC_IO_MC_REGS_SIZE; break; case CHIP_CAICOS: default: - io_mc_regs = (const u32 *)&caicos_io_mc_regs; + io_mc_regs = &caicos_io_mc_regs[0][0]; ucode_size = BTC_MC_UCODE_SIZE; regs_size = BTC_IO_MC_REGS_SIZE; break; case CHIP_CAYMAN: - io_mc_regs = (const u32 *)&cayman_io_mc_regs; + io_mc_regs = &cayman_io_mc_regs[0][0]; ucode_size = CAYMAN_MC_UCODE_SIZE; regs_size = BTC_IO_MC_REGS_SIZE; break; diff --git a/sys/dev/drm2/radeon/si.c b/sys/dev/drm2/radeon/si.c index 7bf7721cfcff..0fdefd2a6b6d 100644 --- a/sys/dev/drm2/radeon/si.c +++ b/sys/dev/drm2/radeon/si.c @@ -190,18 +190,18 @@ static int si_mc_load_microcode(struct radeon_device *rdev) switch (rdev->family) { case CHIP_TAHITI: - io_mc_regs = (const u32 *)&tahiti_io_mc_regs; + io_mc_regs = &tahiti_io_mc_regs[0][0]; ucode_size = SI_MC_UCODE_SIZE; regs_size = TAHITI_IO_MC_REGS_SIZE; break; case CHIP_PITCAIRN: - io_mc_regs = (const u32 *)&pitcairn_io_mc_regs; + io_mc_regs = &pitcairn_io_mc_regs[0][0]; ucode_size = SI_MC_UCODE_SIZE; regs_size = TAHITI_IO_MC_REGS_SIZE; break; case CHIP_VERDE: default: - io_mc_regs = (const u32 *)&verde_io_mc_regs; + io_mc_regs = &verde_io_mc_regs[0][0]; ucode_size = SI_MC_UCODE_SIZE; regs_size = TAHITI_IO_MC_REGS_SIZE; break; From 6df0b7b48572643e894c07065e5236ed86c806bb Mon Sep 17 00:00:00 2001 From: Xin LI Date: Mon, 9 Feb 2015 09:17:00 +0000 Subject: [PATCH 33/75] Chase r278433: bump __FreeBSD_version for xz 5.2.0 which adds multi-thread capability to liblzma. --- sys/sys/param.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/sys/param.h b/sys/sys/param.h index c61cbf8f2b8f..aba65aca1972 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1100058 /* Master, propagated to newvers */ +#define __FreeBSD_version 1100059 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, From 7bdb2409ca9ee73dce575b0e11a9a5bc728c7a35 Mon Sep 17 00:00:00 2001 From: Glen Barber Date: Mon, 9 Feb 2015 09:56:21 +0000 Subject: [PATCH 34/75] Define FREEBSD_VERSION in release/Makefile, derived from sys/sys/param.h. Sponsored by: The FreeBSD Foundation --- release/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/release/Makefile b/release/Makefile index 4672a91511a8..0dffc1bbea44 100644 --- a/release/Makefile +++ b/release/Makefile @@ -54,6 +54,10 @@ TARGET_ARCH= ${TARGET} IMAKE= ${MAKE} TARGET_ARCH=${TARGET_ARCH} TARGET=${TARGET} DISTDIR= dist +# Get the __FreeBSD_version for the build +FREEBSD_VERSION!= awk '/^\#define __FreeBSD_version/ {print $$3}' \ + ${.CURDIR}/../sys/sys/param.h + # Define OSRELEASE by using newvars.sh .if !defined(OSRELEASE) || empty(OSRELEASE) .for _V in TYPE BRANCH REVISION From 7ffa77fa95be1bbf5756647a0b8b089921223940 Mon Sep 17 00:00:00 2001 From: Glen Barber Date: Mon, 9 Feb 2015 10:42:27 +0000 Subject: [PATCH 35/75] Enable multi-threaded xz(1) compression, after r278433. Allow multi-threaded xz(1) to be turned off by specifying NO_XZTHREADS, and allow number of threads to be overridden by specifying XZ_THREADS=N. MFC after: 1 week X-MFC-needs: r278433 Sponsored by: The FreeBSD Foundation --- release/Makefile | 16 +++++++++++++++- release/Makefile.vm | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/release/Makefile b/release/Makefile index 0dffc1bbea44..b28546c0d71c 100644 --- a/release/Makefile +++ b/release/Makefile @@ -33,6 +33,9 @@ # with xz(1) (extremely time consuming) # WITH_CLOUDWARE: if set, build cloud hosting disk images with the release # TARGET/TARGET_ARCH: architecture of built release +# XZ_FLAGS: Additional arguments to pass to xz(1) +# XZ_THREADS: Number of xz(1) threads to use +# NO_XZTHREADS: Disable multi-threaded xz(1) compression # WORLDDIR?= ${.CURDIR}/.. @@ -40,6 +43,8 @@ PORTSDIR?= /usr/ports DOCDIR?= /usr/doc RELNOTES_LANG?= en_US.ISO8859-1 XZCMD?= /usr/bin/xz +XZ_FLAGS?= +XZ_THREADS?= .if !defined(TARGET) || empty(TARGET) TARGET= ${MACHINE} @@ -58,6 +63,15 @@ DISTDIR= dist FREEBSD_VERSION!= awk '/^\#define __FreeBSD_version/ {print $$3}' \ ${.CURDIR}/../sys/sys/param.h +.if !defined(NO_XZTHREADS) && empty(XZ_THREADS) +XZ_THREADS= 0 +.else +XZ_THREADS= ${XZ_THREADS} +.endif +.if !empty(XZ_THREADS) +XZ_FLAGS+= -T ${XZ_THREADS} +.endif + # Define OSRELEASE by using newvars.sh .if !defined(OSRELEASE) || empty(OSRELEASE) .for _V in TYPE BRANCH REVISION @@ -299,7 +313,7 @@ release-install: .for I in ${IMAGES} cp -p ${I} ${DESTDIR}/${OSRELEASE}-${I} . if defined(WITH_COMPRESSED_IMAGES) && !empty(WITH_COMPRESSED_IMAGES) - ${XZCMD} -k ${DESTDIR}/${OSRELEASE}-${I} + ${XZCMD} ${XZ_FLAGS} -k ${DESTDIR}/${OSRELEASE}-${I} . endif .endfor cd ${DESTDIR} && sha256 ${OSRELEASE}* > ${DESTDIR}/CHECKSUM.SHA256 diff --git a/release/Makefile.vm b/release/Makefile.vm index fe955d30d8c1..34f31665fbce 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -101,7 +101,7 @@ vm-install: # the DESTDIR. . for FORMAT in ${VMFORMATS} # Don't keep the originals. There is a copy in ${.OBJDIR} if needed. - ${XZCMD} ${DESTDIR}/vmimages/${OSRELEASE}.${FORMAT} + ${XZCMD} ${XZ_FLAGS} ${DESTDIR}/vmimages/${OSRELEASE}.${FORMAT} . endfor . endif cd ${DESTDIR}/vmimages && sha256 ${OSRELEASE}* > \ From b6fdce7ea78bee4e8ec92949e051dee966eb63bb Mon Sep 17 00:00:00 2001 From: Glen Barber Date: Mon, 9 Feb 2015 10:46:39 +0000 Subject: [PATCH 36/75] Revert r278445. I was going to use __FreeBSD_version to determine if xz(1) should be multi-threaded by default, but doing this will cause problems if/when the changes are merged from head. Sponsored by: The FreeBSD Foundation --- release/Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/release/Makefile b/release/Makefile index b28546c0d71c..0a3f50972d15 100644 --- a/release/Makefile +++ b/release/Makefile @@ -59,10 +59,6 @@ TARGET_ARCH= ${TARGET} IMAKE= ${MAKE} TARGET_ARCH=${TARGET_ARCH} TARGET=${TARGET} DISTDIR= dist -# Get the __FreeBSD_version for the build -FREEBSD_VERSION!= awk '/^\#define __FreeBSD_version/ {print $$3}' \ - ${.CURDIR}/../sys/sys/param.h - .if !defined(NO_XZTHREADS) && empty(XZ_THREADS) XZ_THREADS= 0 .else From 66fe94642d9eaed23f6187a1cd9d0f327f918caa Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Mon, 9 Feb 2015 11:34:45 +0000 Subject: [PATCH 37/75] Properly hide a variable under #ifdef as it is only used inside the specific #ifdef block otherwise leaving an unused variable and breaking other kernel builds. --- sys/powerpc/pseries/platform_chrp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/powerpc/pseries/platform_chrp.c b/sys/powerpc/pseries/platform_chrp.c index eb86ec74ce29..b1fc948bf541 100644 --- a/sys/powerpc/pseries/platform_chrp.c +++ b/sys/powerpc/pseries/platform_chrp.c @@ -124,9 +124,9 @@ chrp_probe(platform_t plat) static int chrp_attach(platform_t plat) { +#ifdef __powerpc64__ int i; -#ifdef __powerpc64__ /* XXX: check for /rtas/ibm,hypertas-functions? */ if (!(mfmsr() & PSL_HV)) { struct mem_region *phys, *avail; From 3b33679869fc9898c7f0b731dde7561680466343 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Mon, 9 Feb 2015 15:58:27 +0000 Subject: [PATCH 38/75] Mark invalid page table entries correctly for PMAP as well as for the hypervisor. This prevents an infinite loop where processes with evicted pages would page fault forever when PMAP decided the evicted pages on which the process was faulting was actually present and did not need to be restored. Found while building LLVM with make -j32. Sponsored by: FreeBSD Foundation --- sys/powerpc/pseries/mmu_phyp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/powerpc/pseries/mmu_phyp.c b/sys/powerpc/pseries/mmu_phyp.c index 5f7db69f62ed..af3b4e598cb2 100644 --- a/sys/powerpc/pseries/mmu_phyp.c +++ b/sys/powerpc/pseries/mmu_phyp.c @@ -240,6 +240,7 @@ mphyp_pte_unset(mmu_t mmu, uintptr_t slot, struct lpte *pvo_pt, uint64_t vpn) uint64_t junk; int err; + pvo_pt->pte_hi &= ~LPTE_VALID; err = phyp_pft_hcall(H_REMOVE, 1UL << 31, slot, pvo_pt->pte_hi & LPTE_AVPN_MASK, 0, &pte.pte_hi, &pte.pte_lo, &junk); @@ -265,6 +266,7 @@ mphyp_pte_change(mmu_t mmu, uintptr_t slot, struct lpte *pvo_pt, uint64_t vpn) /* XXX: optimization using H_PROTECT for common case? */ mphyp_pte_unset(mmu, slot, pvo_pt, vpn); + pvo_pt->pte_hi |= LPTE_VALID; result = phyp_pft_hcall(H_ENTER, H_EXACT, slot, pvo_pt->pte_hi, pvo_pt->pte_lo, &index, &evicted.pte_lo, &junk); if (result != H_SUCCESS) @@ -286,7 +288,7 @@ mphyp_pte_spillable_ident(u_int ptegidx, struct lpte *to_evict) phyp_pft_hcall(H_READ, 0, slot, 0, 0, &pt.pte_hi, &pt.pte_lo, &junk); - if (pt.pte_hi & LPTE_SWBITS) + if (pt.pte_hi & LPTE_WIRED) continue; /* This is a candidate, so remember it */ @@ -391,7 +393,7 @@ mphyp_pte_insert(mmu_t mmu, u_int ptegidx, struct lpte *pvo_pt) } } - KASSERT(pvo->pvo_pte.lpte.pte_hi == evicted.pte_hi, + KASSERT((pvo->pvo_pte.lpte.pte_hi | LPTE_VALID) == evicted.pte_hi, ("Unable to find PVO for spilled PTE")); /* From a469e551a41b79b8aa9d8cb09ba995b1a2a808fb Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 9 Feb 2015 16:03:55 +0000 Subject: [PATCH 39/75] Enforce that MK_foo options shall be either "yes" or "no" and nothing else. --- share/mk/bsd.mkopt.mk | 8 ++++++++ sys/conf/kern.opts.mk | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/share/mk/bsd.mkopt.mk b/share/mk/bsd.mkopt.mk index 46f835b86dca..9cfe1bf09d07 100644 --- a/share/mk/bsd.mkopt.mk +++ b/share/mk/bsd.mkopt.mk @@ -33,7 +33,11 @@ MK_${var}:= no .else MK_${var}:= yes .endif +.else +.if ${MK_${var}} != "yes" && ${MK_${var}} != "no" +.error "Illegal value for MK_${var}: ${MK_${var}}" .endif +.endif # !defined(MK_${var}) .endfor .undef __DEFAULT_YES_OPTIONS @@ -47,6 +51,10 @@ MK_${var}:= yes .else MK_${var}:= no .endif +.else +.if ${MK_${var}} != "yes" && ${MK_${var}} != "no" +.error "Illegal value for MK_${var}: ${MK_${var}}" .endif +.endif # !defined(MK_${var}) .endfor .undef __DEFAULT_NO_OPTIONS diff --git a/sys/conf/kern.opts.mk b/sys/conf/kern.opts.mk index 81d91afc374e..112c217e2da1 100644 --- a/sys/conf/kern.opts.mk +++ b/sys/conf/kern.opts.mk @@ -58,7 +58,11 @@ MK_${var}:= no .else MK_${var}:= yes .endif +.else +.if ${MK_${var}} != "yes" && ${MK_${var}} != "no" +.error "Illegal value for MK_${var}: ${MK_${var}}" .endif +.endif # !defined(MK_${var}) .endfor .undef __DEFAULT_YES_OPTIONS @@ -70,7 +74,11 @@ MK_${var}:= yes .else MK_${var}:= no .endif +.else +.if ${MK_${var}} != "yes" && ${MK_${var}} != "no" +.error "Illegal value for MK_${var}: ${MK_${var}}" .endif +.endif # !defined(MK_${var}) .endfor .undef __DEFAULT_NO_OPTIONS From 3e7ec4b67d14bbd587f3068c924ac4e11cd15ee6 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 9 Feb 2015 16:03:59 +0000 Subject: [PATCH 40/75] Pass MODULES_EXTRA to the modules build. While I'm here, also always pass WITHOUT_MODULES down. There's no need to make this conditional. Submitted by: Guy Yur --- sys/conf/kern.pre.mk | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk index f0e57361d3a5..4c167ca1f29c 100644 --- a/sys/conf/kern.pre.mk +++ b/sys/conf/kern.pre.mk @@ -186,15 +186,13 @@ SYSTEM_DEP+= ${LDSCRIPT} MKMODULESENV+= MAKEOBJDIRPREFIX=${.OBJDIR}/modules KMODDIR=${KODIR} MKMODULESENV+= MACHINE_CPUARCH=${MACHINE_CPUARCH} MKMODULESENV+= MACHINE=${MACHINE} MACHINE_ARCH=${MACHINE_ARCH} +MKMODULESENV+= MODULES_EXTRA=${MODULES_EXTRA} WITHOUT_MODULES=${WITHOUT_MODULES} .if (${KERN_IDENT} == LINT) MKMODULESENV+= ALL_MODULES=LINT .endif .if defined(MODULES_OVERRIDE) MKMODULESENV+= MODULES_OVERRIDE="${MODULES_OVERRIDE}" .endif -.if defined(WITHOUT_MODULES) -MKMODULESENV+= WITHOUT_MODULES="${WITHOUT_MODULES}" -.endif .if defined(DEBUG) MKMODULESENV+= DEBUG_FLAGS="${DEBUG}" .endif From ef6fcdc6512e9983dde85680d77e77bb4213c5ae Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 9 Feb 2015 16:04:01 +0000 Subject: [PATCH 41/75] Make sure that we define DTB{OWN,GRP,MODE} so install works. Submitted by: Guy Yur --- sys/conf/dtb.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/conf/dtb.mk b/sys/conf/dtb.mk index 9ba22cd505dd..52b1b23539c2 100644 --- a/sys/conf/dtb.mk +++ b/sys/conf/dtb.mk @@ -46,6 +46,9 @@ SYSDIR= ${_dir} .PATH: ${SYSDIR}/gnu/dts/${MACHINE} ${SYSDIR}/boot/fdt/dts/${MACHINE} DTBDIR?=/boot/dtb +DTBOWN?=root +DTBGRP?=wheel +DTBMODE?=444 DTB=${DTS:R:S/$/.dtb/} all: ${DTB} From 2d29166779c2d7ab4c073d8ebcbc2d85973519e7 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 9 Feb 2015 16:04:08 +0000 Subject: [PATCH 42/75] We need to create /boot/dtb since some use cases don't create a full root with BSD.root.mtree, so it often times will not exist. Rather than force the latter for an installkernel, just create the directory with a comment about why. Submitted by: Guy Yur --- sys/conf/dtb.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/conf/dtb.mk b/sys/conf/dtb.mk index 52b1b23539c2..cc579d21ece4 100644 --- a/sys/conf/dtb.mk +++ b/sys/conf/dtb.mk @@ -67,6 +67,10 @@ CLEANFILES+=${_dts:R:S/$/.dtb/} realinstall: _dtbinstall .ORDER: beforeinstall _kmodinstall _dtbinstall: +# Need to create this because installkernel doens't invoke mtree with BSD.root.mtree +# to make sure the tree is setup properly. This may break ownership of ${DTBDIR} +# for no-root build. + mkdir -p ${DESTDIR}${DTBDIR} .for _dtb in ${DTB} ${INSTALL} -o ${DTBOWN} -g ${DTBGRP} -m ${DTBMODE} \ ${_INSTALLFLAGS} ${_dtb} ${DESTDIR}${DTBDIR} From 2cfaebb6818c86ee6a4164663d66fca5d37bf212 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 9 Feb 2015 16:10:30 +0000 Subject: [PATCH 43/75] Fix typo. Submitted by: jhb@ --- sys/conf/dtb.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/conf/dtb.mk b/sys/conf/dtb.mk index cc579d21ece4..1ff3eb444b62 100644 --- a/sys/conf/dtb.mk +++ b/sys/conf/dtb.mk @@ -67,7 +67,7 @@ CLEANFILES+=${_dts:R:S/$/.dtb/} realinstall: _dtbinstall .ORDER: beforeinstall _kmodinstall _dtbinstall: -# Need to create this because installkernel doens't invoke mtree with BSD.root.mtree +# Need to create this because installkernel doesn't invoke mtree with BSD.root.mtree # to make sure the tree is setup properly. This may break ownership of ${DTBDIR} # for no-root build. mkdir -p ${DESTDIR}${DTBDIR} From 9f78f7b262e99b7a8d0a7946b4a0dcbc9256f9ca Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 9 Feb 2015 16:21:49 +0000 Subject: [PATCH 44/75] Move these definitions to bsd.own.mk along side the kernel directory / user defines. Make this work with WITH_INSTALL_AS_USER as well. Noticed by: ian@ --- share/mk/bsd.own.mk | 6 +++++- sys/conf/dtb.mk | 4 ---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk index 486914bc19bf..ca77f859705f 100644 --- a/share/mk/bsd.own.mk +++ b/share/mk/bsd.own.mk @@ -141,7 +141,7 @@ _uid!= id -u USER!= id -un .endif _gid!= id -gn -.for x in BIN CONF DOC INFO KMOD LIB MAN NLS SHARE +.for x in BIN CONF DOC DTB INFO KMOD LIB MAN NLS SHARE $xOWN= ${USER} $xGRP= ${_gid} .endfor @@ -164,6 +164,10 @@ KMODDIR?= /boot/kernel KMODOWN?= ${BINOWN} KMODGRP?= ${BINGRP} KMODMODE?= ${BINMODE} +DTBDIR?= /boot/dtb +DTBOWN?= root +DTBGRP?= wheel +DTBMODE?= 444 LIBDIR?= /usr/lib LIBCOMPATDIR?= /usr/lib/compat diff --git a/sys/conf/dtb.mk b/sys/conf/dtb.mk index 1ff3eb444b62..ea1baefe99ef 100644 --- a/sys/conf/dtb.mk +++ b/sys/conf/dtb.mk @@ -45,10 +45,6 @@ SYSDIR= ${_dir} .PATH: ${SYSDIR}/gnu/dts/${MACHINE} ${SYSDIR}/boot/fdt/dts/${MACHINE} -DTBDIR?=/boot/dtb -DTBOWN?=root -DTBGRP?=wheel -DTBMODE?=444 DTB=${DTS:R:S/$/.dtb/} all: ${DTB} From cbe6c25d2e62d6e4b93a0566ebf4d9274779f3b4 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 9 Feb 2015 16:29:44 +0000 Subject: [PATCH 45/75] Prefer install over mkdir to create the directory. Add test to ensure the directory doesn't exist before creating it. This makes the NO_ROOT case actually work. Suggested by: brooks@ --- sys/conf/dtb.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/conf/dtb.mk b/sys/conf/dtb.mk index ea1baefe99ef..41bc9bb20d8d 100644 --- a/sys/conf/dtb.mk +++ b/sys/conf/dtb.mk @@ -64,9 +64,9 @@ realinstall: _dtbinstall .ORDER: beforeinstall _kmodinstall _dtbinstall: # Need to create this because installkernel doesn't invoke mtree with BSD.root.mtree -# to make sure the tree is setup properly. This may break ownership of ${DTBDIR} -# for no-root build. - mkdir -p ${DESTDIR}${DTBDIR} +# to make sure the tree is setup properly. We don't recreate it to avoid duplicate +# entries in the NO_ROOT case. + test -d ${DESTDIR}${DTBDIR} || ${INSTALL} -d -o ${DTBOWN} -g ${DTBGRP} ${DESTDIR}${DTBDIR} .for _dtb in ${DTB} ${INSTALL} -o ${DTBOWN} -g ${DTBGRP} -m ${DTBMODE} \ ${_INSTALLFLAGS} ${_dtb} ${DESTDIR}${DTBDIR} From a831d7d1c538b93ffec095657d9a6e6e778db195 Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Mon, 9 Feb 2015 17:18:10 +0000 Subject: [PATCH 46/75] Replace the only instance of sed(1) in bsdconfig(8) with awk(1). MFC after: 3 days --- usr.sbin/bsdconfig/console/INDEX | 7 +++ usr.sbin/bsdconfig/includes/INDEX | 1 + usr.sbin/bsdconfig/share/keymap.subr | 2 +- .../bsdconfig/timezone/share/continents.subr | 45 ++++++++++++++----- .../bsdconfig/timezone/share/countries.subr | 43 ++++++++++++++---- usr.sbin/bsdconfig/usermgmt/share/user.subr | 3 +- 6 files changed, 78 insertions(+), 23 deletions(-) diff --git a/usr.sbin/bsdconfig/console/INDEX b/usr.sbin/bsdconfig/console/INDEX index 18763fdbfc14..b3bf975a518d 100644 --- a/usr.sbin/bsdconfig/console/INDEX +++ b/usr.sbin/bsdconfig/console/INDEX @@ -46,6 +46,13 @@ menu_help="Customize system console behavior" # can be i18n'ed but `command' is the name of a script. # menu_selection="console|console" +menu_selection="vt_font|font" +menu_selection="vt_keymap|keymap" +menu_selection="vt_repeat|repeat" +menu_selection="vt_saver|saver" +menu_selection="vt_screenmap|screenmap" +menu_selection="vt_ttys|ttys" +# For backward compatibility menu_selection="syscons_font|font" menu_selection="syscons_keymap|keymap" menu_selection="syscons_repeat|repeat" diff --git a/usr.sbin/bsdconfig/includes/INDEX b/usr.sbin/bsdconfig/includes/INDEX index 6e829be2f423..c32542de279e 100644 --- a/usr.sbin/bsdconfig/includes/INDEX +++ b/usr.sbin/bsdconfig/includes/INDEX @@ -45,6 +45,7 @@ menu_help="" # can be i18n'ed but `command' is the name of a script. # menu_selection="includes|includes" +menu_selection="api|includes" # # ------------ Items below this line do NOT need i18n translation ------------ diff --git a/usr.sbin/bsdconfig/share/keymap.subr b/usr.sbin/bsdconfig/share/keymap.subr index d4f391c8c8b8..41f59cf7a3ef 100644 --- a/usr.sbin/bsdconfig/share/keymap.subr +++ b/usr.sbin/bsdconfig/share/keymap.subr @@ -219,7 +219,7 @@ f_keymap_get_all() echo -n "$k " # NOTE: Translate '8x8' to '8x08' before sending to # sort(1) so that things work out as we might expect. - debug= keymap_$k get desc | sed -e 's/8x8/8x08/g' + debug= keymap_$k get desc | awk 'gsub(/8x8/,"8x08")||1' done | sort -k2 | awk '{ printf "%s%s", (started ? " " : ""), $1; started = 1 }' diff --git a/usr.sbin/bsdconfig/timezone/share/continents.subr b/usr.sbin/bsdconfig/timezone/share/continents.subr index 02c40717763e..11fd88d5f2a2 100644 --- a/usr.sbin/bsdconfig/timezone/share/continents.subr +++ b/usr.sbin/bsdconfig/timezone/share/continents.subr @@ -1,6 +1,6 @@ if [ ! "$_TIMEZONE_CONTINENTS_SUBR" ]; then _TIMEZONE_CONTINENTS_SUBR=1 # -# Copyright (c) 2011-2012 Devin Teske +# Copyright (c) 2011-2014 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -87,7 +87,7 @@ export continent_utc_title ############################################################ FUNCTIONS -# f_continent $cont $property +# f_continent $cont $property [$var_to_set] # # Returns a single property of a given continent. Available properties are: # @@ -102,37 +102,60 @@ export continent_utc_title # (which appears after continent selection). # menu_list Menu-list of regions for this continent. # +# If $var_to_set is missing or NULL, the value of $var_to_get is printed to +# standard output for capturing in a sub-shell (which is less-recommended +# because of performance degredation; for example, when called in a loop). +# f_continent() { - local cont="$1" property="$2" - eval echo \"\${continent_${cont}_$property}\" + f_getvar "continent_${1}_$2" $3 } -# f_find_continent $title +# f_find_continent $title [$var_to_set] # # Returns continent identifier given continent title. # +# If $var_to_set is missing or NULL, the value of $var_to_get is printed to +# standard output for capturing in a sub-shell (which is less-recommended +# because of performance degredation; for example, when called in a loop). +# f_find_continent() { - local cont - for cont in $CONTINENTS; do - if [ "$1" = "$( f_continent $cont title )" ]; then - echo "$cont" + local __cont __title + for __cont in $CONTINENTS; do + f_continent $__cont title __title + if [ "$1" = "$__title" ]; then + if [ "$2" ]; then + setvar "$2" $__cont + else + echo "$__cont" + fi return $SUCCESS fi done return $FAILURE } -# f_OCEANP $cont +# f_OCEANP $cont [$var_to_set] # # Returns "1" if the first argument is an ocean, otherwise NULL. # +# If $var_to_set is missing or NULL, the value of $var_to_get is printed to +# standard output for capturing in a sub-shell (which is less-recommended +# because of performance degredation; for example, when called in a loop). +# f_OCEANP() { case "$1" in arctic|atlantic|indian|pacific) - echo 1 + if [ "$2" ]; then + setvar "$2" 1 + else + echo 1 + fi + ;; + *) + [ "$2" ] && setvar "$2" "" esac } diff --git a/usr.sbin/bsdconfig/timezone/share/countries.subr b/usr.sbin/bsdconfig/timezone/share/countries.subr index ff05766ba27a..6cf7d4ff4d1a 100644 --- a/usr.sbin/bsdconfig/timezone/share/countries.subr +++ b/usr.sbin/bsdconfig/timezone/share/countries.subr @@ -1,6 +1,6 @@ if [ ! "$_TIMEZONE_COUNTRIES_SUBR" ]; then _TIMEZONE_COUNTRIES_SUBR=1 # -# Copyright (c) 2011-2012 Devin Teske +# Copyright (c) 2011-2014 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -25,8 +25,10 @@ if [ ! "$_TIMEZONE_COUNTRIES_SUBR" ]; then _TIMEZONE_COUNTRIES_SUBR=1 # SUCH DAMAGE. # # $FreeBSD$ +# +############################################################ FUNCTIONS -# f_country $code $property +# f_country $code $property [$var_to_set] # # Returns a single property of a given country. Available properties are: # @@ -44,10 +46,13 @@ if [ ! "$_TIMEZONE_COUNTRIES_SUBR" ]; then _TIMEZONE_COUNTRIES_SUBR=1 # descr_N Like name, but for the Nth zone when the country has # multiple zones (nzones > 0) # +# If $var_to_set is missing or NULL, the value of $var_to_get is printed to +# standard output for capturing in a sub-shell (which is less-recommended +# because of performance degredation; for example, when called in a loop). +# f_country() { - local code="$1" property="$2" - eval echo \"\${country_${code}_$property}\" + f_getvar "country_${1}_$2" $3 } # f_sort_countries @@ -59,22 +64,42 @@ f_country() # afterward is the sh(1) function which utilizes the below awk script. # f_sort_countries_awk=' +function _asorti(src, dest) { - split($0, array, /[[:space:]]+/) + k = nitems = 0 + for (i in src) dest[++nitems] = i + for (i = 1; i <= nitems; k = i++) { + idx = dest[i] + while ((k > 0) && (dest[k] > idx)) { + dest[k+1] = dest[k]; k-- + } + dest[k+1] = idx + } + return nitems +} +BEGIN { + split(ENVIRON["COUNTRIES"], array, /[[:space:]]+/) for (item in array) { tlc = array[item] - print ENVIRON["country_" tlc "_name"] " " tlc + name = ENVIRON["country_" tlc "_name"] + countries[name] = tlc } + n = _asorti(countries, sorted_countries) + for (i = 1, i <= n; i++) + print countries[sorted_countries[i]] + exit } ' f_sort_countries() { - COUNTRIES=$( echo "$COUNTRIES" | awk "$f_sort_countries_awk" | - sort | awk '{print $NF}' ) - export COUNTRIES + export COUNTRIES # for awk(1) ENVIRON[] visibility + COUNTRIES=$( awk "$f_sort_countries_awk" ) + export COUNTRIES # Pedantic } +############################################################ MAIN + f_dprintf "%s: Successfully loaded." timezone/countries.subr fi # ! $_TIMEZONE_COUNTRIES_SUBR diff --git a/usr.sbin/bsdconfig/usermgmt/share/user.subr b/usr.sbin/bsdconfig/usermgmt/share/user.subr index 5fd65fbe088b..e6beb54a6065 100644 --- a/usr.sbin/bsdconfig/usermgmt/share/user.subr +++ b/usr.sbin/bsdconfig/usermgmt/share/user.subr @@ -830,8 +830,7 @@ f_user_delete() f_eval_catch $funcname \ pw '%s -H 0' "$cmd" else - f_eval_catch $funcname \ - pw '%s -h -' "$cmd" + f_eval_catch $funcname pw '%s -h -' "$cmd" fi fi fi From dd8a17d45724092778a808a56e9c906a67da4bec Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Mon, 9 Feb 2015 17:22:54 +0000 Subject: [PATCH 47/75] Revert SVN r278464 -- fingers were in perforce mode (premature commit of future stuffs not yet ready). --- usr.sbin/bsdconfig/console/INDEX | 7 --- usr.sbin/bsdconfig/includes/INDEX | 1 - usr.sbin/bsdconfig/share/keymap.subr | 2 +- .../bsdconfig/timezone/share/continents.subr | 45 +++++-------------- .../bsdconfig/timezone/share/countries.subr | 43 ++++-------------- usr.sbin/bsdconfig/usermgmt/share/user.subr | 3 +- 6 files changed, 23 insertions(+), 78 deletions(-) diff --git a/usr.sbin/bsdconfig/console/INDEX b/usr.sbin/bsdconfig/console/INDEX index b3bf975a518d..18763fdbfc14 100644 --- a/usr.sbin/bsdconfig/console/INDEX +++ b/usr.sbin/bsdconfig/console/INDEX @@ -46,13 +46,6 @@ menu_help="Customize system console behavior" # can be i18n'ed but `command' is the name of a script. # menu_selection="console|console" -menu_selection="vt_font|font" -menu_selection="vt_keymap|keymap" -menu_selection="vt_repeat|repeat" -menu_selection="vt_saver|saver" -menu_selection="vt_screenmap|screenmap" -menu_selection="vt_ttys|ttys" -# For backward compatibility menu_selection="syscons_font|font" menu_selection="syscons_keymap|keymap" menu_selection="syscons_repeat|repeat" diff --git a/usr.sbin/bsdconfig/includes/INDEX b/usr.sbin/bsdconfig/includes/INDEX index c32542de279e..6e829be2f423 100644 --- a/usr.sbin/bsdconfig/includes/INDEX +++ b/usr.sbin/bsdconfig/includes/INDEX @@ -45,7 +45,6 @@ menu_help="" # can be i18n'ed but `command' is the name of a script. # menu_selection="includes|includes" -menu_selection="api|includes" # # ------------ Items below this line do NOT need i18n translation ------------ diff --git a/usr.sbin/bsdconfig/share/keymap.subr b/usr.sbin/bsdconfig/share/keymap.subr index 41f59cf7a3ef..d4f391c8c8b8 100644 --- a/usr.sbin/bsdconfig/share/keymap.subr +++ b/usr.sbin/bsdconfig/share/keymap.subr @@ -219,7 +219,7 @@ f_keymap_get_all() echo -n "$k " # NOTE: Translate '8x8' to '8x08' before sending to # sort(1) so that things work out as we might expect. - debug= keymap_$k get desc | awk 'gsub(/8x8/,"8x08")||1' + debug= keymap_$k get desc | sed -e 's/8x8/8x08/g' done | sort -k2 | awk '{ printf "%s%s", (started ? " " : ""), $1; started = 1 }' diff --git a/usr.sbin/bsdconfig/timezone/share/continents.subr b/usr.sbin/bsdconfig/timezone/share/continents.subr index 11fd88d5f2a2..02c40717763e 100644 --- a/usr.sbin/bsdconfig/timezone/share/continents.subr +++ b/usr.sbin/bsdconfig/timezone/share/continents.subr @@ -1,6 +1,6 @@ if [ ! "$_TIMEZONE_CONTINENTS_SUBR" ]; then _TIMEZONE_CONTINENTS_SUBR=1 # -# Copyright (c) 2011-2014 Devin Teske +# Copyright (c) 2011-2012 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -87,7 +87,7 @@ export continent_utc_title ############################################################ FUNCTIONS -# f_continent $cont $property [$var_to_set] +# f_continent $cont $property # # Returns a single property of a given continent. Available properties are: # @@ -102,60 +102,37 @@ export continent_utc_title # (which appears after continent selection). # menu_list Menu-list of regions for this continent. # -# If $var_to_set is missing or NULL, the value of $var_to_get is printed to -# standard output for capturing in a sub-shell (which is less-recommended -# because of performance degredation; for example, when called in a loop). -# f_continent() { - f_getvar "continent_${1}_$2" $3 + local cont="$1" property="$2" + eval echo \"\${continent_${cont}_$property}\" } -# f_find_continent $title [$var_to_set] +# f_find_continent $title # # Returns continent identifier given continent title. # -# If $var_to_set is missing or NULL, the value of $var_to_get is printed to -# standard output for capturing in a sub-shell (which is less-recommended -# because of performance degredation; for example, when called in a loop). -# f_find_continent() { - local __cont __title - for __cont in $CONTINENTS; do - f_continent $__cont title __title - if [ "$1" = "$__title" ]; then - if [ "$2" ]; then - setvar "$2" $__cont - else - echo "$__cont" - fi + local cont + for cont in $CONTINENTS; do + if [ "$1" = "$( f_continent $cont title )" ]; then + echo "$cont" return $SUCCESS fi done return $FAILURE } -# f_OCEANP $cont [$var_to_set] +# f_OCEANP $cont # # Returns "1" if the first argument is an ocean, otherwise NULL. # -# If $var_to_set is missing or NULL, the value of $var_to_get is printed to -# standard output for capturing in a sub-shell (which is less-recommended -# because of performance degredation; for example, when called in a loop). -# f_OCEANP() { case "$1" in arctic|atlantic|indian|pacific) - if [ "$2" ]; then - setvar "$2" 1 - else - echo 1 - fi - ;; - *) - [ "$2" ] && setvar "$2" "" + echo 1 esac } diff --git a/usr.sbin/bsdconfig/timezone/share/countries.subr b/usr.sbin/bsdconfig/timezone/share/countries.subr index 6cf7d4ff4d1a..ff05766ba27a 100644 --- a/usr.sbin/bsdconfig/timezone/share/countries.subr +++ b/usr.sbin/bsdconfig/timezone/share/countries.subr @@ -1,6 +1,6 @@ if [ ! "$_TIMEZONE_COUNTRIES_SUBR" ]; then _TIMEZONE_COUNTRIES_SUBR=1 # -# Copyright (c) 2011-2014 Devin Teske +# Copyright (c) 2011-2012 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -25,10 +25,8 @@ if [ ! "$_TIMEZONE_COUNTRIES_SUBR" ]; then _TIMEZONE_COUNTRIES_SUBR=1 # SUCH DAMAGE. # # $FreeBSD$ -# -############################################################ FUNCTIONS -# f_country $code $property [$var_to_set] +# f_country $code $property # # Returns a single property of a given country. Available properties are: # @@ -46,13 +44,10 @@ if [ ! "$_TIMEZONE_COUNTRIES_SUBR" ]; then _TIMEZONE_COUNTRIES_SUBR=1 # descr_N Like name, but for the Nth zone when the country has # multiple zones (nzones > 0) # -# If $var_to_set is missing or NULL, the value of $var_to_get is printed to -# standard output for capturing in a sub-shell (which is less-recommended -# because of performance degredation; for example, when called in a loop). -# f_country() { - f_getvar "country_${1}_$2" $3 + local code="$1" property="$2" + eval echo \"\${country_${code}_$property}\" } # f_sort_countries @@ -64,42 +59,22 @@ f_country() # afterward is the sh(1) function which utilizes the below awk script. # f_sort_countries_awk=' -function _asorti(src, dest) { - k = nitems = 0 - for (i in src) dest[++nitems] = i - for (i = 1; i <= nitems; k = i++) { - idx = dest[i] - while ((k > 0) && (dest[k] > idx)) { - dest[k+1] = dest[k]; k-- - } - dest[k+1] = idx - } - return nitems -} -BEGIN { - split(ENVIRON["COUNTRIES"], array, /[[:space:]]+/) + split($0, array, /[[:space:]]+/) for (item in array) { tlc = array[item] - name = ENVIRON["country_" tlc "_name"] - countries[name] = tlc + print ENVIRON["country_" tlc "_name"] " " tlc } - n = _asorti(countries, sorted_countries) - for (i = 1, i <= n; i++) - print countries[sorted_countries[i]] - exit } ' f_sort_countries() { - export COUNTRIES # for awk(1) ENVIRON[] visibility - COUNTRIES=$( awk "$f_sort_countries_awk" ) - export COUNTRIES # Pedantic + COUNTRIES=$( echo "$COUNTRIES" | awk "$f_sort_countries_awk" | + sort | awk '{print $NF}' ) + export COUNTRIES } -############################################################ MAIN - f_dprintf "%s: Successfully loaded." timezone/countries.subr fi # ! $_TIMEZONE_COUNTRIES_SUBR diff --git a/usr.sbin/bsdconfig/usermgmt/share/user.subr b/usr.sbin/bsdconfig/usermgmt/share/user.subr index e6beb54a6065..5fd65fbe088b 100644 --- a/usr.sbin/bsdconfig/usermgmt/share/user.subr +++ b/usr.sbin/bsdconfig/usermgmt/share/user.subr @@ -830,7 +830,8 @@ f_user_delete() f_eval_catch $funcname \ pw '%s -H 0' "$cmd" else - f_eval_catch $funcname pw '%s -h -' "$cmd" + f_eval_catch $funcname \ + pw '%s -h -' "$cmd" fi fi fi From 66ea550a7780eab65e2c31779b382c566a2b35ff Mon Sep 17 00:00:00 2001 From: Enji Cooper Date: Mon, 9 Feb 2015 17:53:16 +0000 Subject: [PATCH 48/75] Remove explicit routing/sendmail rc.d inclusion in FILES Reported by: Guy Yur MFC after: 14 days X-MFC with: r278249 Sponsored by: EMC / Isilon Storage Division --- etc/rc.d/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index 8c37a3001de9..a1f879e49a75 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -99,7 +99,6 @@ FILES= DAEMON \ rfcomm_pppd_server \ root \ route6d \ - routed \ routing \ rpcbind \ rtadvd \ @@ -107,7 +106,6 @@ FILES= DAEMON \ savecore \ sdpd \ securelevel \ - sendmail \ serial \ sppp \ ${_sshd} \ From 94f2a70e883affae1febff9c04cf25f1cfd5f02f Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Mon, 9 Feb 2015 19:16:19 +0000 Subject: [PATCH 49/75] Replace the only instance of sed(1) in bsdconfig(8) with awk(1). MFC after: 3 days --- usr.sbin/bsdconfig/share/keymap.subr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.sbin/bsdconfig/share/keymap.subr b/usr.sbin/bsdconfig/share/keymap.subr index d4f391c8c8b8..41f59cf7a3ef 100644 --- a/usr.sbin/bsdconfig/share/keymap.subr +++ b/usr.sbin/bsdconfig/share/keymap.subr @@ -219,7 +219,7 @@ f_keymap_get_all() echo -n "$k " # NOTE: Translate '8x8' to '8x08' before sending to # sort(1) so that things work out as we might expect. - debug= keymap_$k get desc | sed -e 's/8x8/8x08/g' + debug= keymap_$k get desc | awk 'gsub(/8x8/,"8x08")||1' done | sort -k2 | awk '{ printf "%s%s", (started ? " " : ""), $1; started = 1 }' From f967066a99dfe73caab878b040fe951dbcf75bfa Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Feb 2015 19:19:13 +0000 Subject: [PATCH 50/75] Add a few more instructions to xz/FREEBSD-upgrade. --- contrib/xz/FREEBSD-upgrade | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/xz/FREEBSD-upgrade b/contrib/xz/FREEBSD-upgrade index 8d48be29010b..986197c1463b 100644 --- a/contrib/xz/FREEBSD-upgrade +++ b/contrib/xz/FREEBSD-upgrade @@ -16,6 +16,9 @@ sh -c 'for F in `cat FREEBSD-Xlist | grep -v FreeBSD`; do rm -rf ./$F ; done' You may check if there are any new files that we don't need. +You should run ``configure'' to make sure you use a more recent +config.h. Running ``make check'' in the xz source tree is also useful. + The instructions for importing new release and merging to HEAD can be found at FreeBSD wiki: From d2854fa4884e90e47fbcb3e455703b2b4b8c4904 Mon Sep 17 00:00:00 2001 From: Randall Stewart Date: Mon, 9 Feb 2015 19:19:44 +0000 Subject: [PATCH 51/75] This fixes two conditions that can incur when migration is being done in the callout code and harmonizes the macro use.: 1) The callout_active() will lie. Basically if a migration is occuring and the callout is about to expire and the migration has been deferred, the callout_active will no longer return true until after the migration. This confuses and breaks callers that are doing callout_init(&c, 1); such as TCP. 2) The migration code had a bug in it where when migrating, if a two calls to callout_reset came in and they both collided with the callout on the wheel about to run, then the second call to callout_reset would corrupt the list the callout wheel uses putting the callout thread into a endless loop. 3) Per imp, I have fixed all the macro occurance in the code that were for the most part being ignored. Phabricator D1711 and looked at by lstewart and jhb and sbruno. Reviewed by: kostikbel, imp, adrian, hselasky MFC after: 3 days Sponsored by: Netflix Inc. --- sys/kern/kern_timeout.c | 240 ++++++++++++++++++++++++++-------------- sys/sys/callout.h | 1 + 2 files changed, 155 insertions(+), 86 deletions(-) diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c index 1d5d24faa40b..c8eb6d887b08 100644 --- a/sys/kern/kern_timeout.c +++ b/sys/kern/kern_timeout.c @@ -166,26 +166,16 @@ struct callout_cpu { char cc_ktr_event_name[20]; }; -#define cc_exec_curr cc_exec_entity[0].cc_curr -#define cc_exec_next cc_exec_entity[0].cc_next -#define cc_exec_cancel cc_exec_entity[0].cc_cancel -#define cc_exec_waiting cc_exec_entity[0].cc_waiting -#define cc_exec_curr_dir cc_exec_entity[1].cc_curr -#define cc_exec_next_dir cc_exec_entity[1].cc_next -#define cc_exec_cancel_dir cc_exec_entity[1].cc_cancel -#define cc_exec_waiting_dir cc_exec_entity[1].cc_waiting - +#define cc_exec_curr(cc, dir) cc->cc_exec_entity[dir].cc_curr +#define cc_exec_next(cc, dir) cc->cc_exec_entity[dir].cc_next +#define cc_exec_cancel(cc, dir) cc->cc_exec_entity[dir].cc_cancel +#define cc_exec_waiting(cc, dir) cc->cc_exec_entity[dir].cc_waiting #ifdef SMP -#define cc_migration_func cc_exec_entity[0].ce_migration_func -#define cc_migration_arg cc_exec_entity[0].ce_migration_arg -#define cc_migration_cpu cc_exec_entity[0].ce_migration_cpu -#define cc_migration_time cc_exec_entity[0].ce_migration_time -#define cc_migration_prec cc_exec_entity[0].ce_migration_prec -#define cc_migration_func_dir cc_exec_entity[1].ce_migration_func -#define cc_migration_arg_dir cc_exec_entity[1].ce_migration_arg -#define cc_migration_cpu_dir cc_exec_entity[1].ce_migration_cpu -#define cc_migration_time_dir cc_exec_entity[1].ce_migration_time -#define cc_migration_prec_dir cc_exec_entity[1].ce_migration_prec +#define cc_migration_func(cc, dir) cc->cc_exec_entity[dir].ce_migration_func +#define cc_migration_arg(cc, dir) cc->cc_exec_entity[dir].ce_migration_arg +#define cc_migration_cpu(cc, dir) cc->cc_exec_entity[dir].ce_migration_cpu +#define cc_migration_time(cc, dir) cc->cc_exec_entity[dir].ce_migration_time +#define cc_migration_prec(cc, dir) cc->cc_exec_entity[dir].ce_migration_prec struct callout_cpu cc_cpu[MAXCPU]; #define CPUBLOCK MAXCPU @@ -235,16 +225,16 @@ static void cc_cce_cleanup(struct callout_cpu *cc, int direct) { - cc->cc_exec_entity[direct].cc_curr = NULL; - cc->cc_exec_entity[direct].cc_next = NULL; - cc->cc_exec_entity[direct].cc_cancel = false; - cc->cc_exec_entity[direct].cc_waiting = false; + cc_exec_curr(cc, direct) = NULL; + cc_exec_next(cc, direct) = NULL; + cc_exec_cancel(cc, direct) = false; + cc_exec_waiting(cc, direct) = false; #ifdef SMP - cc->cc_exec_entity[direct].ce_migration_cpu = CPUBLOCK; - cc->cc_exec_entity[direct].ce_migration_time = 0; - cc->cc_exec_entity[direct].ce_migration_prec = 0; - cc->cc_exec_entity[direct].ce_migration_func = NULL; - cc->cc_exec_entity[direct].ce_migration_arg = NULL; + cc_migration_cpu(cc, direct) = CPUBLOCK; + cc_migration_time(cc, direct) = 0; + cc_migration_prec(cc, direct) = 0; + cc_migration_func(cc, direct) = NULL; + cc_migration_arg(cc, direct) = NULL; #endif } @@ -256,7 +246,7 @@ cc_cce_migrating(struct callout_cpu *cc, int direct) { #ifdef SMP - return (cc->cc_exec_entity[direct].ce_migration_cpu != CPUBLOCK); + return (cc_migration_cpu(cc, direct) != CPUBLOCK); #else return (0); #endif @@ -492,7 +482,7 @@ callout_process(sbintime_t now) #ifdef CALLOUT_PROFILING ++depth_dir; #endif - cc->cc_exec_next_dir = + cc_exec_next(cc, 1) = LIST_NEXT(tmp, c_links.le); cc->cc_bucket = firstb & callwheelmask; LIST_REMOVE(tmp, c_links.le); @@ -501,7 +491,7 @@ callout_process(sbintime_t now) &mpcalls_dir, &lockcalls_dir, NULL, #endif 1); - tmp = cc->cc_exec_next_dir; + tmp = cc_exec_next(cc, 1); } else { tmpn = LIST_NEXT(tmp, c_links.le); LIST_REMOVE(tmp, c_links.le); @@ -585,7 +575,7 @@ callout_lock(struct callout *c) static void callout_cc_add(struct callout *c, struct callout_cpu *cc, sbintime_t sbt, sbintime_t precision, void (*func)(void *), - void *arg, int cpu, int flags) + void *arg, int cpu, int flags, int direct) { int bucket; @@ -606,7 +596,7 @@ callout_cc_add(struct callout *c, struct callout_cpu *cc, (u_int)(c->c_precision & 0xffffffff)); LIST_INSERT_HEAD(&cc->cc_callwheel[bucket], c, c_links.le); if (cc->cc_bucket == bucket) - cc->cc_exec_next_dir = c; + cc_exec_next(cc, direct) = c; #ifndef NO_EVENTTIMERS /* * Inform the eventtimers(4) subsystem there's a new callout @@ -679,8 +669,9 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, c->c_flags = CALLOUT_LOCAL_ALLOC; else c->c_flags &= ~CALLOUT_PENDING; - cc->cc_exec_entity[direct].cc_curr = c; - cc->cc_exec_entity[direct].cc_cancel = false; + + cc_exec_curr(cc, direct) = c; + cc_exec_cancel(cc, direct) = false; CC_UNLOCK(cc); if (c_lock != NULL) { class->lc_lock(c_lock, lock_status); @@ -688,12 +679,12 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, * The callout may have been cancelled * while we switched locks. */ - if (cc->cc_exec_entity[direct].cc_cancel) { + if (cc_exec_cancel(cc, direct)) { class->lc_unlock(c_lock); goto skip; } /* The callout cannot be stopped now. */ - cc->cc_exec_entity[direct].cc_cancel = true; + cc_exec_cancel(cc, direct) = true; if (c_lock == &Giant.lock_object) { #ifdef CALLOUT_PROFILING (*gcalls)++; @@ -744,9 +735,9 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, class->lc_unlock(c_lock); skip: CC_LOCK(cc); - KASSERT(cc->cc_exec_entity[direct].cc_curr == c, ("mishandled cc_curr")); - cc->cc_exec_entity[direct].cc_curr = NULL; - if (cc->cc_exec_entity[direct].cc_waiting) { + KASSERT(cc_exec_curr(cc, direct) == c, ("mishandled cc_curr")); + cc_exec_curr(cc, direct) = NULL; + if (cc_exec_waiting(cc, direct)) { /* * There is someone waiting for the * callout to complete. @@ -762,9 +753,9 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, */ c->c_flags &= ~CALLOUT_DFRMIGRATION; } - cc->cc_exec_entity[direct].cc_waiting = false; + cc_exec_waiting(cc, direct) = false; CC_UNLOCK(cc); - wakeup(&cc->cc_exec_entity[direct].cc_waiting); + wakeup(&cc_exec_waiting(cc, direct)); CC_LOCK(cc); } else if (cc_cce_migrating(cc, direct)) { KASSERT((c_flags & CALLOUT_LOCAL_ALLOC) == 0, @@ -774,11 +765,11 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, * If the callout was scheduled for * migration just perform it now. */ - new_cpu = cc->cc_exec_entity[direct].ce_migration_cpu; - new_time = cc->cc_exec_entity[direct].ce_migration_time; - new_prec = cc->cc_exec_entity[direct].ce_migration_prec; - new_func = cc->cc_exec_entity[direct].ce_migration_func; - new_arg = cc->cc_exec_entity[direct].ce_migration_arg; + new_cpu = cc_migration_cpu(cc, direct); + new_time = cc_migration_time(cc, direct); + new_prec = cc_migration_prec(cc, direct); + new_func = cc_migration_func(cc, direct); + new_arg = cc_migration_arg(cc, direct); cc_cce_cleanup(cc, direct); /* @@ -787,7 +778,7 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, * * As first thing, handle deferred callout stops. */ - if ((c->c_flags & CALLOUT_DFRMIGRATION) == 0) { + if (!callout_migrating(c)) { CTR3(KTR_CALLOUT, "deferred cancelled %p func %p arg %p", c, new_func, new_arg); @@ -799,7 +790,7 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, new_cc = callout_cpu_switch(c, cc, new_cpu); flags = (direct) ? C_DIRECT_EXEC : 0; callout_cc_add(c, new_cc, new_time, new_prec, new_func, - new_arg, new_cpu, flags); + new_arg, new_cpu, flags, direct); CC_UNLOCK(new_cc); CC_LOCK(cc); #else @@ -1007,15 +998,15 @@ callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t precision, KASSERT(!direct || c->c_lock == NULL, ("%s: direct callout %p has lock", __func__, c)); cc = callout_lock(c); - if (cc->cc_exec_entity[direct].cc_curr == c) { + if (cc_exec_curr(cc, direct) == c) { /* * We're being asked to reschedule a callout which is * currently in progress. If there is a lock then we * can cancel the callout if it has not really started. */ - if (c->c_lock != NULL && !cc->cc_exec_entity[direct].cc_cancel) - cancelled = cc->cc_exec_entity[direct].cc_cancel = true; - if (cc->cc_exec_entity[direct].cc_waiting) { + if (c->c_lock != NULL && cc_exec_cancel(cc, direct)) + cancelled = cc_exec_cancel(cc, direct) = true; + if (cc_exec_waiting(cc, direct)) { /* * Someone has called callout_drain to kill this * callout. Don't reschedule. @@ -1026,11 +1017,30 @@ callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t precision, CC_UNLOCK(cc); return (cancelled); } +#ifdef SMP + if (callout_migrating(c)) { + /* + * This only occurs when a second callout_reset_sbt_on + * is made after a previous one moved it into + * deferred migration (below). Note we do *not* change + * the prev_cpu even though the previous target may + * be different. + */ + cc_migration_cpu(cc, direct) = cpu; + cc_migration_time(cc, direct) = to_sbt; + cc_migration_prec(cc, direct) = precision; + cc_migration_func(cc, direct) = ftn; + cc_migration_arg(cc, direct) = arg; + cancelled = 1; + CC_UNLOCK(cc); + return (cancelled); + } +#endif } if (c->c_flags & CALLOUT_PENDING) { if ((c->c_flags & CALLOUT_PROCESSED) == 0) { - if (cc->cc_exec_next_dir == c) - cc->cc_exec_next_dir = LIST_NEXT(c, c_links.le); + if (cc_exec_next(cc, direct) == c) + cc_exec_next(cc, direct) = LIST_NEXT(c, c_links.le); LIST_REMOVE(c, c_links.le); } else TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe); @@ -1045,15 +1055,29 @@ callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t precision, * to a more appropriate moment. */ if (c->c_cpu != cpu) { - if (cc->cc_exec_entity[direct].cc_curr == c) { - cc->cc_exec_entity[direct].ce_migration_cpu = cpu; - cc->cc_exec_entity[direct].ce_migration_time - = to_sbt; - cc->cc_exec_entity[direct].ce_migration_prec - = precision; - cc->cc_exec_entity[direct].ce_migration_func = ftn; - cc->cc_exec_entity[direct].ce_migration_arg = arg; - c->c_flags |= CALLOUT_DFRMIGRATION; + if (cc_exec_curr(cc, direct) == c) { + /* + * Pending will have been removed since we are + * actually executing the callout on another + * CPU. That callout should be waiting on the + * lock the caller holds. If we set both + * active/and/pending after we return and the + * lock on the executing callout proceeds, it + * will then see pending is true and return. + * At the return from the actual callout execution + * the migration will occur in softclock_call_cc + * and this new callout will be placed on the + * new CPU via a call to callout_cpu_switch() which + * will get the lock on the right CPU followed + * by a call callout_cc_add() which will add it there. + * (see above in softclock_call_cc()). + */ + cc_migration_cpu(cc, direct) = cpu; + cc_migration_time(cc, direct) = to_sbt; + cc_migration_prec(cc, direct) = precision; + cc_migration_func(cc, direct) = ftn; + cc_migration_arg(cc, direct) = arg; + c->c_flags |= (CALLOUT_DFRMIGRATION | CALLOUT_ACTIVE | CALLOUT_PENDING); CTR6(KTR_CALLOUT, "migration of %p func %p arg %p in %d.%08x to %u deferred", c, c->c_func, c->c_arg, (int)(to_sbt >> 32), @@ -1065,7 +1089,7 @@ callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t precision, } #endif - callout_cc_add(c, cc, to_sbt, precision, ftn, arg, cpu, flags); + callout_cc_add(c, cc, to_sbt, precision, ftn, arg, cpu, flags, direct); CTR6(KTR_CALLOUT, "%sscheduled %p func %p arg %p in %d.%08x", cancelled ? "re" : "", c, c->c_func, c->c_arg, (int)(to_sbt >> 32), (u_int)(to_sbt & 0xffffffff)); @@ -1095,6 +1119,7 @@ _callout_stop_safe(struct callout *c, int safe) struct callout_cpu *cc, *old_cc; struct lock_class *class; int direct, sq_locked, use_lock; + int not_on_a_list; if (safe) WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, c->c_lock, @@ -1120,6 +1145,26 @@ _callout_stop_safe(struct callout *c, int safe) again: cc = callout_lock(c); + if ((c->c_flags & (CALLOUT_DFRMIGRATION | CALLOUT_ACTIVE | CALLOUT_PENDING)) == + (CALLOUT_DFRMIGRATION | CALLOUT_ACTIVE | CALLOUT_PENDING)) { + /* + * Special case where this slipped in while we + * were migrating *as* the callout is about to + * execute. The caller probably holds the lock + * the callout wants. + * + * Get rid of the migration first. Then set + * the flag that tells this code *not* to + * try to remove it from any lists (its not + * on one yet). When the callout wheel runs, + * it will ignore this callout. + */ + c->c_flags &= ~(CALLOUT_PENDING|CALLOUT_ACTIVE); + not_on_a_list = 1; + } else { + not_on_a_list = 0; + } + /* * If the callout was migrating while the callout cpu lock was * dropped, just drop the sleepqueue lock and check the states @@ -1128,7 +1173,7 @@ _callout_stop_safe(struct callout *c, int safe) if (sq_locked != 0 && cc != old_cc) { #ifdef SMP CC_UNLOCK(cc); - sleepq_release(&old_cc->cc_exec_entity[direct].cc_waiting); + sleepq_release(&cc_exec_waiting(old_cc, direct)); sq_locked = 0; old_cc = NULL; goto again; @@ -1149,13 +1194,12 @@ _callout_stop_safe(struct callout *c, int safe) * If it wasn't on the queue and it isn't the current * callout, then we can't stop it, so just bail. */ - if (cc->cc_exec_entity[direct].cc_curr != c) { + if (cc_exec_curr(cc, direct) != c) { CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p", c, c->c_func, c->c_arg); CC_UNLOCK(cc); if (sq_locked) - sleepq_release( - &cc->cc_exec_entity[direct].cc_waiting); + sleepq_release(&cc_exec_waiting(cc, direct)); return (0); } @@ -1166,7 +1210,7 @@ _callout_stop_safe(struct callout *c, int safe) * just wait for the current invocation to * finish. */ - while (cc->cc_exec_entity[direct].cc_curr == c) { + while (cc_exec_curr(cc, direct) == c) { /* * Use direct calls to sleepqueue interface * instead of cv/msleep in order to avoid @@ -1187,7 +1231,7 @@ _callout_stop_safe(struct callout *c, int safe) if (!sq_locked) { CC_UNLOCK(cc); sleepq_lock( - &cc->cc_exec_entity[direct].cc_waiting); + &cc_exec_waiting(cc, direct)); sq_locked = 1; old_cc = cc; goto again; @@ -1199,15 +1243,15 @@ _callout_stop_safe(struct callout *c, int safe) * will be packed up, just let softclock() * take care of it. */ - cc->cc_exec_entity[direct].cc_waiting = true; + cc_exec_waiting(cc, direct) = true; DROP_GIANT(); CC_UNLOCK(cc); sleepq_add( - &cc->cc_exec_entity[direct].cc_waiting, + &cc_exec_waiting(cc, direct), &cc->cc_lock.lock_object, "codrain", SLEEPQ_SLEEP, 0); sleepq_wait( - &cc->cc_exec_entity[direct].cc_waiting, + &cc_exec_waiting(cc, direct), 0); sq_locked = 0; old_cc = NULL; @@ -1217,7 +1261,8 @@ _callout_stop_safe(struct callout *c, int safe) CC_LOCK(cc); } } else if (use_lock && - !cc->cc_exec_entity[direct].cc_cancel) { + !cc_exec_cancel(cc, direct)) { + /* * The current callout is waiting for its * lock which we hold. Cancel the callout @@ -1225,7 +1270,7 @@ _callout_stop_safe(struct callout *c, int safe) * lock, the callout will be skipped in * softclock(). */ - cc->cc_exec_entity[direct].cc_cancel = true; + cc_exec_cancel(cc, direct) = true; CTR3(KTR_CALLOUT, "cancelled %p func %p arg %p", c, c->c_func, c->c_arg); KASSERT(!cc_cce_migrating(cc, direct), @@ -1233,12 +1278,34 @@ _callout_stop_safe(struct callout *c, int safe) CC_UNLOCK(cc); KASSERT(!sq_locked, ("sleepqueue chain locked")); return (1); - } else if ((c->c_flags & CALLOUT_DFRMIGRATION) != 0) { + } else if (callout_migrating(c)) { + /* + * The callout is currently being serviced + * and the "next" callout is scheduled at + * its completion with a migration. We remove + * the migration flag so it *won't* get rescheduled, + * but we can't stop the one thats running so + * we return 0. + */ c->c_flags &= ~CALLOUT_DFRMIGRATION; +#ifdef SMP + /* + * We can't call cc_cce_cleanup here since + * if we do it will remove .ce_curr and + * its still running. This will prevent a + * reschedule of the callout when the + * execution completes. + */ + cc_migration_cpu(cc, direct) = CPUBLOCK; + cc_migration_time(cc, direct) = 0; + cc_migration_prec(cc, direct) = 0; + cc_migration_func(cc, direct) = NULL; + cc_migration_arg(cc, direct) = NULL; +#endif CTR3(KTR_CALLOUT, "postponing stop %p func %p arg %p", c, c->c_func, c->c_arg); CC_UNLOCK(cc); - return (1); + return (0); } CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p", c, c->c_func, c->c_arg); @@ -1247,20 +1314,21 @@ _callout_stop_safe(struct callout *c, int safe) return (0); } if (sq_locked) - sleepq_release(&cc->cc_exec_entity[direct].cc_waiting); + sleepq_release(&cc_exec_waiting(cc, direct)); c->c_flags &= ~(CALLOUT_ACTIVE | CALLOUT_PENDING); CTR3(KTR_CALLOUT, "cancelled %p func %p arg %p", c, c->c_func, c->c_arg); - if ((c->c_flags & CALLOUT_PROCESSED) == 0) { - if (cc->cc_exec_next_dir == c) - cc->cc_exec_next_dir = LIST_NEXT(c, c_links.le); - LIST_REMOVE(c, c_links.le); - } else - TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe); + if (not_on_a_list == 0) { + if ((c->c_flags & CALLOUT_PROCESSED) == 0) { + if (cc_exec_next(cc, direct) == c) + cc_exec_next(cc, direct) = LIST_NEXT(c, c_links.le); + LIST_REMOVE(c, c_links.le); + } else + TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe); + } callout_cc_del(c, cc); - CC_UNLOCK(cc); return (1); } diff --git a/sys/sys/callout.h b/sys/sys/callout.h index 1096cb26ff92..910d652f7dd1 100644 --- a/sys/sys/callout.h +++ b/sys/sys/callout.h @@ -64,6 +64,7 @@ struct callout_handle { #ifdef _KERNEL #define callout_active(c) ((c)->c_flags & CALLOUT_ACTIVE) +#define callout_migrating(c) ((c)->c_flags & CALLOUT_DFRMIGRATION) #define callout_deactivate(c) ((c)->c_flags &= ~CALLOUT_ACTIVE) #define callout_drain(c) _callout_stop_safe(c, 1) void callout_init(struct callout *, int); From fda64d7c85b55e49172c7a3ec496fe2c130a76d6 Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Mon, 9 Feb 2015 19:20:59 +0000 Subject: [PATCH 52/75] Add new alias "bsdconfig api" (same as "bsdconfig includes") NB: My fingers like typing "api" a lot more than "includes" MFC after: 3 days --- usr.sbin/bsdconfig/includes/INDEX | 1 + 1 file changed, 1 insertion(+) diff --git a/usr.sbin/bsdconfig/includes/INDEX b/usr.sbin/bsdconfig/includes/INDEX index 6e829be2f423..c32542de279e 100644 --- a/usr.sbin/bsdconfig/includes/INDEX +++ b/usr.sbin/bsdconfig/includes/INDEX @@ -45,6 +45,7 @@ menu_help="" # can be i18n'ed but `command' is the name of a script. # menu_selection="includes|includes" +menu_selection="api|includes" # # ------------ Items below this line do NOT need i18n translation ------------ From 0174acd43917f49a027a8d47811f8f91b99dc866 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Mon, 9 Feb 2015 19:21:54 +0000 Subject: [PATCH 53/75] Distribute interrupts across multiple CPUs in SMP configurations instead of sending them all to CPU 0. --- sys/powerpc/pseries/xics.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sys/powerpc/pseries/xics.c b/sys/powerpc/pseries/xics.c index b09079aaf111..f1a3c8b38c9a 100644 --- a/sys/powerpc/pseries/xics.c +++ b/sys/powerpc/pseries/xics.c @@ -197,13 +197,25 @@ xicp_bind(device_t dev, u_int irq, cpuset_t cpumask) { struct xicp_softc *sc = device_get_softc(dev); cell_t status, cpu; + int ncpus, i; /* - * This doesn't appear to actually support affinity groups, so just - * use the first CPU. + * This doesn't appear to actually support affinity groups, so pick a + * random CPU. */ CPU_FOREACH(cpu) - if (CPU_ISSET(cpu, &cpumask)) break; + if (CPU_ISSET(cpu, &cpumask)) ncpus++; + + i = mftb() % ncpus; + ncpus = 0; + CPU_FOREACH(cpu) { + if (!CPU_ISSET(cpu, &cpumask)) + continue; + if (ncpus == i) + break; + ncpus++; + } + rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, XICP_PRIORITY, &status); From 2575fbb82713dcfca8a5a8794119a7cd4c713405 Mon Sep 17 00:00:00 2001 From: Randall Stewart Date: Mon, 9 Feb 2015 19:28:11 +0000 Subject: [PATCH 54/75] This fixes a bug in the way that the LLE timers for nd6 and arp were being used. They basically would pass in the mutex to the callout_init. Because they used this method to the callout system, it was possible to "stop" the callout. When flushing the table and you stopped the running callout, the callout_stop code would return 1 indicating that it was going to stop the callout (that was about to run on the callout_wheel blocked by the function calling the stop). Now when 1 was returned, it would lower the reference count one extra time for the stopped timer, then a few lines later delete the memory. Of course the callout_wheel was stuck in the lock code and would then crash since it was accessing freed memory. By using callout_init(c, 1) we always get a 0 back and the reference counting bug does not rear its head. We do have to make a few adjustments to the callouts themselves though to make sure it does the proper thing if rescheduled as well as gets the lock. Commented upon by hiren and sbruno See Phabricator D1777 for more details. Commented upon by hiren and sbruno Reviewed by: adrian, jhb and bz Sponsored by: Netflix Inc. --- sys/netinet/if_ether.c | 22 ++++++++++++++++++++-- sys/netinet/in.c | 3 +-- sys/netinet6/in6.c | 3 +-- sys/netinet6/nd6.c | 23 +++++++++++++++++++++-- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 5011fc418d83..78ec2f40f781 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -166,10 +166,28 @@ arptimer(void *arg) struct ifnet *ifp; if (lle->la_flags & LLE_STATIC) { - LLE_WUNLOCK(lle); return; } - + LLE_WLOCK(lle); + if (callout_pending(&lle->la_timer)) { + /* + * Here we are a bit odd here in the treatment of + * active/pending. If the pending bit is set, it got + * rescheduled before I ran. The active + * bit we ignore, since if it was stopped + * in ll_tablefree() and was currently running + * it would have return 0 so the code would + * not have deleted it since the callout could + * not be stopped so we want to go through + * with the delete here now. If the callout + * was restarted, the pending bit will be back on and + * we just want to bail since the callout_reset would + * return 1 and our reference would have been removed + * by arpresolve() below. + */ + LLE_WUNLOCK(lle); + return; + } ifp = lle->lle_tbl->llt_ifp; CURVNET_SET(ifp->if_vnet); diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 42cf7e607e7b..bfcb33a641ad 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -962,8 +962,7 @@ in_lltable_new(const struct sockaddr *l3addr, u_int flags) lle->base.lle_refcnt = 1; lle->base.lle_free = in_lltable_free; LLE_LOCK_INIT(&lle->base); - callout_init_rw(&lle->base.la_timer, &lle->base.lle_lock, - CALLOUT_RETURNUNLOCKED); + callout_init(&lle->base.la_timer, 1); return (&lle->base); } diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 75ae4cb9e519..448f8f288060 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -2047,8 +2047,7 @@ in6_lltable_new(const struct sockaddr *l3addr, u_int flags) lle->base.lle_refcnt = 1; lle->base.lle_free = in6_lltable_free; LLE_LOCK_INIT(&lle->base); - callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock, - CALLOUT_RETURNUNLOCKED); + callout_init(&lle->base.ln_timer_ch, 1); return (&lle->base); } diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 8bcca398f09c..de1707fbb308 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -473,9 +473,28 @@ nd6_llinfo_timer(void *arg) KASSERT(arg != NULL, ("%s: arg NULL", __func__)); ln = (struct llentry *)arg; - LLE_WLOCK_ASSERT(ln); + LLE_WLOCK(ln); + if (callout_pending(&ln->la_timer)) { + /* + * Here we are a bit odd here in the treatment of + * active/pending. If the pending bit is set, it got + * rescheduled before I ran. The active + * bit we ignore, since if it was stopped + * in ll_tablefree() and was currently running + * it would have return 0 so the code would + * not have deleted it since the callout could + * not be stopped so we want to go through + * with the delete here now. If the callout + * was restarted, the pending bit will be back on and + * we just want to bail since the callout_reset would + * return 1 and our reference would have been removed + * by nd6_llinfo_settimer_locked above since canceled + * would have been 1. + */ + LLE_WUNLOCK(ln); + return; + } ifp = ln->lle_tbl->llt_ifp; - CURVNET_SET(ifp->if_vnet); if (ln->ln_ntick > 0) { From 4c918926cd538a36bb2d54a0f4eb4ca3ebbe16e4 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 9 Feb 2015 21:00:56 +0000 Subject: [PATCH 55/75] Add x2APIC support. Enable it by default if CPU is capable. The hw.x2apic_enable tunable allows disabling it from the loader prompt. To closely repeat effects of the uncached memory ops when accessing registers in the xAPIC mode, the x2APIC writes to MSRs are preceeded by mfence, except for the EOI notifications. This is probably too strict, only ICR writes to send IPI require serialization to ensure that other CPUs see the previous actions when IPI is delivered. This may be changed later. In vmm justreturn IPI handler, call doreti_iret instead of doing iretd inline, to handle corner conditions. Note that the patch only switches LAPICs into x2APIC mode. It does not enables FreeBSD to support > 255 CPUs, which requires parsing x2APIC MADT entries and doing interrupts remapping, but is the required step on the way. Reviewed by: neel Tested by: pho (real hardware), neel (on bhyve) Discussed with: jhb, grehan Sponsored by: The FreeBSD Foundation MFC after: 2 months --- sys/amd64/amd64/apic_vector.S | 45 ++- sys/amd64/amd64/genassym.c | 9 +- sys/amd64/amd64/mp_machdep.c | 7 +- sys/amd64/include/cpufunc.h | 10 + sys/amd64/vmm/vmm_support.S | 11 +- sys/contrib/dev/acpica/include/actbl2.h | 1 + sys/i386/i386/apic_vector.s | 50 ++-- sys/i386/i386/genassym.c | 9 +- sys/i386/i386/mp_machdep.c | 7 +- sys/i386/include/cpufunc.h | 9 + sys/x86/acpica/madt.c | 20 ++ sys/x86/include/apicreg.h | 60 ++++ sys/x86/include/apicvar.h | 14 + sys/x86/include/specialreg.h | 1 + sys/x86/x86/io_apic.c | 3 +- sys/x86/x86/local_apic.c | 381 +++++++++++++++++------- sys/x86/xen/xen_apic.c | 1 + 17 files changed, 470 insertions(+), 168 deletions(-) diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S index 4c87b4e80d37..d9f272439654 100644 --- a/sys/amd64/amd64/apic_vector.S +++ b/sys/amd64/amd64/apic_vector.S @@ -39,6 +39,7 @@ #include "opt_smp.h" #include +#include #include #include "assym.s" @@ -49,6 +50,22 @@ #define LK #endif + .text + SUPERALIGN_TEXT + /* End Of Interrupt to APIC */ +as_lapic_eoi: + cmpl $0,x2apic_mode + jne 1f + movq lapic_map,%rax + movl $0,LA_EOI(%rax) + ret +1: + movl $MSR_APIC_EOI,%ecx + xorl %eax,%eax + xorl %edx,%edx + wrmsr + ret + /* * I/O Interrupt Entry Point. Rather than having one entry point for * each interrupt source, we use one entry point for each 32-bit word @@ -62,15 +79,22 @@ IDTVEC(vec_name) ; \ PUSH_FRAME ; \ FAKE_MCOUNT(TF_RIP(%rsp)) ; \ - movq lapic, %rdx ; /* pointer to local APIC */ \ + cmpl $0,x2apic_mode ; \ + je 1f ; \ + movl $(MSR_APIC_ISR0 + index),%ecx ; \ + rdmsr ; \ + jmp 2f ; \ +1: ; \ + movq lapic_map, %rdx ; /* pointer to local APIC */ \ movl LA_ISR + 16 * (index)(%rdx), %eax ; /* load ISR */ \ +2: ; \ bsrl %eax, %eax ; /* index of highest set bit in ISR */ \ - jz 1f ; \ + jz 3f ; \ addl $(32 * index),%eax ; \ movq %rsp, %rsi ; \ movl %eax, %edi ; /* pass the IRQ */ \ call lapic_handle_intr ; \ -1: ; \ +3: ; \ MEXITCOUNT ; \ jmp doreti @@ -160,8 +184,7 @@ IDTVEC(xen_intr_upcall) SUPERALIGN_TEXT invltlb_ret: - movq lapic, %rax - movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */ + call as_lapic_eoi POP_FRAME jmp doreti_iret @@ -228,8 +251,7 @@ IDTVEC(invlcache) IDTVEC(ipi_intr_bitmap_handler) PUSH_FRAME - movq lapic, %rdx - movl $0, LA_EOI(%rdx) /* End Of Interrupt to APIC */ + call as_lapic_eoi FAKE_MCOUNT(TF_RIP(%rsp)) @@ -245,8 +267,7 @@ IDTVEC(ipi_intr_bitmap_handler) IDTVEC(cpustop) PUSH_FRAME - movq lapic, %rax - movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */ + call as_lapic_eoi call cpustop_handler jmp doreti @@ -260,8 +281,7 @@ IDTVEC(cpususpend) PUSH_FRAME call cpususpend_handler - movq lapic, %rax - movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */ + call as_lapic_eoi jmp doreti /* @@ -279,7 +299,6 @@ IDTVEC(rendezvous) incq (%rax) #endif call smp_rendezvous_action - movq lapic, %rax - movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */ + call as_lapic_eoi jmp doreti #endif /* SMP */ diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index aff685b2797b..3ffefc0e4c43 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -220,13 +220,8 @@ ASSYM(PC_COMMONTSSP, offsetof(struct pcpu, pc_commontssp)); ASSYM(PC_TSS, offsetof(struct pcpu, pc_tss)); ASSYM(PC_PM_SAVE_CNT, offsetof(struct pcpu, pc_pm_save_cnt)); -ASSYM(LA_VER, offsetof(struct LAPIC, version)); -ASSYM(LA_TPR, offsetof(struct LAPIC, tpr)); -ASSYM(LA_EOI, offsetof(struct LAPIC, eoi)); -ASSYM(LA_SVR, offsetof(struct LAPIC, svr)); -ASSYM(LA_ICR_LO, offsetof(struct LAPIC, icr_lo)); -ASSYM(LA_ICR_HI, offsetof(struct LAPIC, icr_hi)); -ASSYM(LA_ISR, offsetof(struct LAPIC, isr0)); +ASSYM(LA_EOI, LAPIC_EOI * LAPIC_MEM_MUL); +ASSYM(LA_ISR, LAPIC_ISR0 * LAPIC_MEM_MUL); ASSYM(KCSEL, GSEL(GCODE_SEL, SEL_KPL)); ASSYM(KDSEL, GSEL(GDATA_SEL, SEL_KPL)); diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index 91b5c9f002e3..13c3d4300e05 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -705,8 +705,11 @@ init_secondary(void) wrmsr(MSR_STAR, msr); wrmsr(MSR_SF_MASK, PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D); - /* Disable local APIC just to be sure. */ - lapic_disable(); + /* + * On real hardware, switch to x2apic mode if possible. + * Disable local APIC until BSP directed APs to run. + */ + lapic_xapic_mode(); /* signal our startup to the BSP. */ mp_naps++; diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h index 7464739cf43d..7ea4bcf48850 100644 --- a/sys/amd64/include/cpufunc.h +++ b/sys/amd64/include/cpufunc.h @@ -343,6 +343,15 @@ rdmsr(u_int msr) return (low | ((uint64_t)high << 32)); } +static __inline uint32_t +rdmsr32(u_int msr) +{ + uint32_t low; + + __asm __volatile("rdmsr" : "=a" (low) : "c" (msr) : "rdx"); + return (low); +} + static __inline uint64_t rdpmc(u_int pmc) { @@ -826,6 +835,7 @@ u_long rcr2(void); u_long rcr3(void); u_long rcr4(void); uint64_t rdmsr(u_int msr); +uint32_t rdmsr32(u_int msr); uint64_t rdpmc(u_int pmc); uint64_t rdr0(void); uint64_t rdr1(void); diff --git a/sys/amd64/vmm/vmm_support.S b/sys/amd64/vmm/vmm_support.S index 2afc608ae71e..7919511c3eab 100644 --- a/sys/amd64/vmm/vmm_support.S +++ b/sys/amd64/vmm/vmm_support.S @@ -30,13 +30,14 @@ #include -#define LA_EOI 0xB0 - .text SUPERALIGN_TEXT IDTVEC(justreturn) + pushq %rdx pushq %rax - movq lapic, %rax - movl $0, LA_EOI(%rax) + pushq %rcx + call as_lapic_eoi + popq %rcx popq %rax - iretq + popq %rdx + jmp doreti_iret diff --git a/sys/contrib/dev/acpica/include/actbl2.h b/sys/contrib/dev/acpica/include/actbl2.h index a6f2f2081f64..0f929eba4665 100644 --- a/sys/contrib/dev/acpica/include/actbl2.h +++ b/sys/contrib/dev/acpica/include/actbl2.h @@ -466,6 +466,7 @@ typedef struct acpi_table_dmar /* Masks for Flags field above */ #define ACPI_DMAR_INTR_REMAP (1) +#define ACPI_DMAR_X2APIC_OPT_OUT (2) /* DMAR subtable header */ diff --git a/sys/i386/i386/apic_vector.s b/sys/i386/i386/apic_vector.s index 3d1999e4a916..7cae22013a4d 100644 --- a/sys/i386/i386/apic_vector.s +++ b/sys/i386/i386/apic_vector.s @@ -39,10 +39,27 @@ #include "opt_smp.h" #include +#include #include #include "assym.s" + .text + SUPERALIGN_TEXT + /* End Of Interrupt to APIC */ +as_lapic_eoi: + cmpl $0,x2apic_mode + jne 1f + movl lapic_map,%eax + movl $0,LA_EOI(%eax) + ret +1: + movl $MSR_APIC_EOI,%ecx + xorl %eax,%eax + xorl %edx,%edx + wrmsr + ret + /* * I/O Interrupt Entry Point. Rather than having one entry point for * each interrupt source, we use one entry point for each 32-bit word @@ -58,16 +75,23 @@ IDTVEC(vec_name) ; \ SET_KERNEL_SREGS ; \ cld ; \ FAKE_MCOUNT(TF_EIP(%esp)) ; \ - movl lapic, %edx ; /* pointer to local APIC */ \ + cmpl $0,x2apic_mode ; \ + je 1f ; \ + movl $(MSR_APIC_ISR0 + index),%ecx ; \ + rdmsr ; \ + jmp 2f ; \ +1: ; \ + movl lapic_map, %edx ;/* pointer to local APIC */ \ movl LA_ISR + 16 * (index)(%edx), %eax ; /* load ISR */ \ +2: ; \ bsrl %eax, %eax ; /* index of highest set bit in ISR */ \ - jz 1f ; \ + jz 3f ; \ addl $(32 * index),%eax ; \ pushl %esp ; \ pushl %eax ; /* pass the IRQ */ \ call lapic_handle_intr ; \ addl $8, %esp ; /* discard parameter */ \ -1: ; \ +3: ; \ MEXITCOUNT ; \ jmp doreti @@ -164,8 +188,7 @@ IDTVEC(xen_intr_upcall) .text SUPERALIGN_TEXT invltlb_ret: - movl lapic, %eax - movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ + call as_lapic_eoi POP_FRAME iret @@ -232,8 +255,7 @@ IDTVEC(ipi_intr_bitmap_handler) SET_KERNEL_SREGS cld - movl lapic, %edx - movl $0, LA_EOI(%edx) /* End Of Interrupt to APIC */ + call as_lapic_eoi FAKE_MCOUNT(TF_EIP(%esp)) @@ -251,9 +273,7 @@ IDTVEC(cpustop) SET_KERNEL_SREGS cld - movl lapic, %eax - movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ - + call as_lapic_eoi call cpustop_handler POP_FRAME @@ -270,9 +290,7 @@ IDTVEC(cpususpend) SET_KERNEL_SREGS cld - movl lapic, %eax - movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ - + call as_lapic_eoi call cpususpend_handler POP_FRAME @@ -298,8 +316,7 @@ IDTVEC(rendezvous) #endif call smp_rendezvous_action - movl lapic, %eax - movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ + call as_lapic_eoi POP_FRAME iret @@ -315,8 +332,7 @@ IDTVEC(lazypmap) call pmap_lazyfix_action - movl lapic, %eax - movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */ + call as_lapic_eoi POP_FRAME iret #endif /* SMP */ diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c index 0994be9b3724..97e2e979bd20 100644 --- a/sys/i386/i386/genassym.c +++ b/sys/i386/i386/genassym.c @@ -219,13 +219,8 @@ ASSYM(PC_CURPMAP, offsetof(struct pcpu, pc_curpmap)); ASSYM(PC_PRIVATE_TSS, offsetof(struct pcpu, pc_private_tss)); #ifdef DEV_APIC -ASSYM(LA_VER, offsetof(struct LAPIC, version)); -ASSYM(LA_TPR, offsetof(struct LAPIC, tpr)); -ASSYM(LA_EOI, offsetof(struct LAPIC, eoi)); -ASSYM(LA_SVR, offsetof(struct LAPIC, svr)); -ASSYM(LA_ICR_LO, offsetof(struct LAPIC, icr_lo)); -ASSYM(LA_ICR_HI, offsetof(struct LAPIC, icr_hi)); -ASSYM(LA_ISR, offsetof(struct LAPIC, isr0)); +ASSYM(LA_EOI, LAPIC_EOI * LAPIC_MEM_MUL); +ASSYM(LA_ISR, LAPIC_ISR0 * LAPIC_MEM_MUL); #endif ASSYM(KCSEL, GSEL(GCODE_SEL, SEL_KPL)); diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c index 72d3fe94d5dc..32b954075d62 100644 --- a/sys/i386/i386/mp_machdep.c +++ b/sys/i386/i386/mp_machdep.c @@ -719,8 +719,11 @@ init_secondary(void) load_cr0(cr0); CHECK_WRITE(0x38, 5); - /* Disable local APIC just to be sure. */ - lapic_disable(); + /* + * On real hardware, switch to x2apic mode if possible. + * Disable local APIC until BSP directed APs to run. + */ + lapic_xapic_mode(); /* signal our startup to the BSP. */ mp_naps++; diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h index c625dcb1903f..f80a8983ab29 100644 --- a/sys/i386/include/cpufunc.h +++ b/sys/i386/include/cpufunc.h @@ -346,6 +346,15 @@ rdmsr(u_int msr) return (rv); } +static __inline uint32_t +rdmsr32(u_int msr) +{ + uint32_t low; + + __asm __volatile("rdmsr" : "=a" (low) : "c" (msr) : "edx"); + return (low); +} + static __inline uint64_t rdpmc(u_int pmc) { diff --git a/sys/x86/acpica/madt.c b/sys/x86/acpica/madt.c index b9cc895fbd06..f20b73521e9c 100644 --- a/sys/x86/acpica/madt.c +++ b/sys/x86/acpica/madt.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -127,8 +128,27 @@ madt_probe_cpus(void) static int madt_setup_local(void) { + ACPI_TABLE_DMAR *dmartbl; + vm_paddr_t dmartbl_physaddr; madt = pmap_mapbios(madt_physaddr, madt_length); + if ((cpu_feature2 & CPUID2_X2APIC) != 0) { + x2apic_mode = 1; + dmartbl_physaddr = acpi_find_table(ACPI_SIG_DMAR); + if (dmartbl_physaddr != 0) { + dmartbl = acpi_map_table(dmartbl_physaddr, + ACPI_SIG_DMAR); + if ((dmartbl->Flags & ACPI_DMAR_X2APIC_OPT_OUT) != 0) { + x2apic_mode = 0; + if (bootverbose) + printf( + "x2APIC available but disabled by DMAR table\n"); + } + acpi_unmap_table(dmartbl); + } + TUNABLE_INT_FETCH("hw.x2apic_enable", &x2apic_mode); + } + lapic_init(madt->Address); printf("ACPI APIC Table: <%.*s %.*s>\n", (int)sizeof(madt->Header.OemId), madt->Header.OemId, diff --git a/sys/x86/include/apicreg.h b/sys/x86/include/apicreg.h index 283d50e72226..35630c7d677a 100644 --- a/sys/x86/include/apicreg.h +++ b/sys/x86/include/apicreg.h @@ -193,6 +193,66 @@ struct LAPIC { typedef struct LAPIC lapic_t; +enum LAPIC_REGISTERS { + LAPIC_ID = 0x2, + LAPIC_VERSION = 0x3, + LAPIC_TPR = 0x8, + LAPIC_APR = 0x9, + LAPIC_PPR = 0xa, + LAPIC_EOI = 0xb, + LAPIC_LDR = 0xd, + LAPIC_DFR = 0xe, /* Not in x2APIC */ + LAPIC_SVR = 0xf, + LAPIC_ISR0 = 0x10, + LAPIC_ISR1 = 0x11, + LAPIC_ISR2 = 0x12, + LAPIC_ISR3 = 0x13, + LAPIC_ISR4 = 0x14, + LAPIC_ISR5 = 0x15, + LAPIC_ISR6 = 0x16, + LAPIC_ISR7 = 0x17, + LAPIC_TMR0 = 0x18, + LAPIC_TMR1 = 0x19, + LAPIC_TMR2 = 0x1a, + LAPIC_TMR3 = 0x1b, + LAPIC_TMR4 = 0x1c, + LAPIC_TMR5 = 0x1d, + LAPIC_TMR6 = 0x1e, + LAPIC_TMR7 = 0x1f, + LAPIC_IRR0 = 0x20, + LAPIC_IRR1 = 0x21, + LAPIC_IRR2 = 0x22, + LAPIC_IRR3 = 0x23, + LAPIC_IRR4 = 0x24, + LAPIC_IRR5 = 0x25, + LAPIC_IRR6 = 0x26, + LAPIC_IRR7 = 0x27, + LAPIC_ESR = 0x28, + LAPIC_LVT_CMCI = 0x2f, + LAPIC_ICR_LO = 0x30, + LAPIC_ICR_HI = 0x31, /* Not in x2APIC */ + LAPIC_LVT_TIMER = 0x32, + LAPIC_LVT_THERMAL = 0x33, + LAPIC_LVT_PCINT = 0x34, + LAPIC_LVT_LINT0 = 0x35, + LAPIC_LVT_LINT1 = 0x36, + LAPIC_LVT_ERROR = 0x37, + LAPIC_ICR_TIMER = 0x38, + LAPIC_CCR_TIMER = 0x39, + LAPIC_DCR_TIMER = 0x3e, + LAPIC_SELF_IPI = 0x3f, /* Only in x2APIC */ +}; + +/* + * The LAPIC_SELF_IPI register only exists in x2APIC mode. The + * formula below is applicable only to reserve the memory region, + * i.e. for xAPIC mode, where LAPIC_SELF_IPI finely serves as the + * address past end of the region. + */ +#define LAPIC_MEM_REGION (LAPIC_SELF_IPI * 0x10) + +#define LAPIC_MEM_MUL 0x10 + /****************************************************************************** * I/O APIC structure */ diff --git a/sys/x86/include/apicvar.h b/sys/x86/include/apicvar.h index 35603e8ce190..f7dfec816f12 100644 --- a/sys/x86/include/apicvar.h +++ b/sys/x86/include/apicvar.h @@ -189,6 +189,7 @@ int ioapic_set_smi(void *cookie, u_int pin); struct apic_ops { void (*create)(u_int, int); void (*init)(vm_paddr_t); + void (*xapic_mode)(void); void (*setup)(int); void (*dump)(const char *); void (*disable)(void); @@ -242,6 +243,13 @@ lapic_init(vm_paddr_t addr) apic_ops.init(addr); } +static inline void +lapic_xapic_mode(void) +{ + + apic_ops.xapic_mode(); +} + static inline void lapic_setup(int boot) { @@ -417,5 +425,11 @@ void lapic_handle_intr(int vector, struct trapframe *frame); void lapic_handle_timer(struct trapframe *frame); void xen_intr_handle_upcall(struct trapframe *frame); +extern int x2apic_mode; + +#ifdef _SYS_SYSCTL_H_ +SYSCTL_DECL(_hw_apic); +#endif + #endif /* !LOCORE */ #endif /* _X86_APICVAR_H_ */ diff --git a/sys/x86/include/specialreg.h b/sys/x86/include/specialreg.h index 4d1086eeae60..60f46fb68e59 100644 --- a/sys/x86/include/specialreg.h +++ b/sys/x86/include/specialreg.h @@ -470,6 +470,7 @@ /* * X2APIC MSRs */ +#define MSR_APIC_000 0x800 #define MSR_APIC_ID 0x802 #define MSR_APIC_VERSION 0x803 #define MSR_APIC_TPR 0x808 diff --git a/sys/x86/x86/io_apic.c b/sys/x86/x86/io_apic.c index 5667120661b4..ec0a71ec615b 100644 --- a/sys/x86/x86/io_apic.c +++ b/sys/x86/x86/io_apic.c @@ -130,7 +130,6 @@ struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source, static int next_ioapic_base; static u_int next_id; -static SYSCTL_NODE(_hw, OID_AUTO, apic, CTLFLAG_RD, 0, "APIC options"); static int enable_extint; SYSCTL_INT(_hw_apic, OID_AUTO, enable_extint, CTLFLAG_RDTUN, &enable_extint, 0, "Enable the ExtINT pin in the first I/O APIC"); @@ -896,7 +895,7 @@ apic_attach(device_t dev) int i; /* Reserve the local APIC. */ - apic_add_resource(dev, 0, lapic_paddr, sizeof(lapic_t)); + apic_add_resource(dev, 0, lapic_paddr, LAPIC_MEM_REGION); i = 1; STAILQ_FOREACH(io, &ioapic_list, io_next) { apic_add_resource(dev, i, io->io_paddr, IOAPIC_MEM_REGION); diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index 080822b29fd4..1809fa6da9d4 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -49,12 +49,14 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -154,11 +156,99 @@ static u_int32_t lapic_timer_divisors[] = { extern inthand_t IDTVEC(rsvd); -volatile lapic_t *lapic; +volatile char *lapic_map; vm_paddr_t lapic_paddr; +int x2apic_mode; static u_long lapic_timer_divisor; static struct eventtimer lapic_et; +SYSCTL_NODE(_hw, OID_AUTO, apic, CTLFLAG_RD, 0, "APIC options"); +SYSCTL_INT(_hw_apic, OID_AUTO, x2apic_mode, CTLFLAG_RD, &x2apic_mode, 0, ""); + +static uint32_t +lapic_read32(enum LAPIC_REGISTERS reg) +{ + uint32_t res; + + if (x2apic_mode) { + res = rdmsr32(MSR_APIC_000 + reg); + } else { + res = *(volatile uint32_t *)(lapic_map + reg * LAPIC_MEM_MUL); + } + return (res); +} + +static void +lapic_write32(enum LAPIC_REGISTERS reg, uint32_t val) +{ + + if (x2apic_mode) { + mfence(); + wrmsr(MSR_APIC_000 + reg, val); + } else { + *(volatile uint32_t *)(lapic_map + reg * LAPIC_MEM_MUL) = val; + } +} + +static void +lapic_write32_nofence(enum LAPIC_REGISTERS reg, uint32_t val) +{ + + if (x2apic_mode) { + wrmsr(MSR_APIC_000 + reg, val); + } else { + *(volatile uint32_t *)(lapic_map + reg * LAPIC_MEM_MUL) = val; + } +} + +static uint64_t +lapic_read_icr(void) +{ + uint64_t v; + uint32_t vhi, vlo; + + if (x2apic_mode) { + v = rdmsr(MSR_APIC_000 + LAPIC_ICR_LO); + } else { + vhi = lapic_read32(LAPIC_ICR_HI); + vlo = lapic_read32(LAPIC_ICR_LO); + v = ((uint64_t)vhi << 32) | vlo; + } + return (v); +} + +static uint64_t +lapic_read_icr_lo(void) +{ + + return (lapic_read32(LAPIC_ICR_LO)); +} + +static void +lapic_write_icr(uint32_t vhi, uint32_t vlo) +{ + uint64_t v; + + if (x2apic_mode) { + v = ((uint64_t)vhi << 32) | vlo; + mfence(); + wrmsr(MSR_APIC_000 + LAPIC_ICR_LO, v); + } else { + lapic_write32(LAPIC_ICR_HI, vhi); + lapic_write32(LAPIC_ICR_LO, vlo); + } +} + +static void +native_lapic_enable_x2apic(void) +{ + uint64_t apic_base; + + apic_base = rdmsr(MSR_APICBASE); + apic_base |= APICBASE_X2APIC | APICBASE_ENABLED; + wrmsr(MSR_APICBASE, apic_base); +} + static void lapic_enable(void); static void lapic_resume(struct pic *pic, bool suspend_cancelled); static void lapic_timer_oneshot(struct lapic *, @@ -179,6 +269,7 @@ struct pic lapic_pic = { .pic_resume = lapic_resume }; /* Forward declarations for apic_ops */ static void native_lapic_create(u_int apic_id, int boot_cpu); static void native_lapic_init(vm_paddr_t addr); +static void native_lapic_xapic_mode(void); static void native_lapic_setup(int boot); static void native_lapic_dump(const char *str); static void native_lapic_disable(void); @@ -213,6 +304,7 @@ static int native_lapic_set_lvt_triggermode(u_int apic_id, u_int lvt, struct apic_ops apic_ops = { .create = native_lapic_create, .init = native_lapic_init, + .xapic_mode = native_lapic_xapic_mode, .setup = native_lapic_setup, .dump = native_lapic_dump, .disable = native_lapic_disable, @@ -291,11 +383,20 @@ native_lapic_init(vm_paddr_t addr) u_int regs[4]; int i, arat; - /* Map the local APIC and setup the spurious interrupt handler. */ + /* + * Enable x2APIC mode if possible, otherwise map the local + * APIC registers page. + */ KASSERT(trunc_page(addr) == addr, ("local APIC not aligned on a page boundary")); - lapic_paddr = addr; - lapic = pmap_mapdev(addr, sizeof(lapic_t)); + if (x2apic_mode) { + native_lapic_enable_x2apic(); + } else { + lapic_paddr = addr; + lapic_map = pmap_mapdev(addr, PAGE_SIZE); + } + + /* Setup the spurious interrupt handler. */ setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_APIC, SEL_KPL, GSEL_APIC); @@ -398,33 +499,51 @@ native_lapic_dump(const char* str) { uint32_t maxlvt; - maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT; + maxlvt = (lapic_read32(LAPIC_VERSION) & APIC_VER_MAXLVT) >> MAXLVTSHIFT; printf("cpu%d %s:\n", PCPU_GET(cpuid), str); - printf(" ID: 0x%08x VER: 0x%08x LDR: 0x%08x DFR: 0x%08x\n", - lapic->id, lapic->version, lapic->ldr, lapic->dfr); - printf(" lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n", - lapic->lvt_lint0, lapic->lvt_lint1, lapic->tpr, lapic->svr); + printf(" ID: 0x%08x VER: 0x%08x LDR: 0x%08x DFR: 0x%08x", + lapic_read32(LAPIC_ID), lapic_read32(LAPIC_VERSION), + lapic_read32(LAPIC_LDR), x2apic_mode ? 0 : lapic_read32(LAPIC_DFR)); + if ((cpu_feature2 & CPUID2_X2APIC) != 0) + printf(" x2APIC: %d", x2apic_mode); + printf("\n lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n", + lapic_read32(LAPIC_LVT_LINT0), lapic_read32(LAPIC_LVT_LINT1), + lapic_read32(LAPIC_TPR), lapic_read32(LAPIC_SVR)); printf(" timer: 0x%08x therm: 0x%08x err: 0x%08x", - lapic->lvt_timer, lapic->lvt_thermal, lapic->lvt_error); + lapic_read32(LAPIC_LVT_TIMER), lapic_read32(LAPIC_LVT_THERMAL), + lapic_read32(LAPIC_LVT_ERROR)); if (maxlvt >= APIC_LVT_PMC) - printf(" pmc: 0x%08x", lapic->lvt_pcint); + printf(" pmc: 0x%08x", lapic_read32(LAPIC_LVT_PCINT)); printf("\n"); if (maxlvt >= APIC_LVT_CMCI) - printf(" cmci: 0x%08x\n", lapic->lvt_cmci); + printf(" cmci: 0x%08x\n", lapic_read32(LAPIC_LVT_CMCI)); +} + +static void +native_lapic_xapic_mode(void) +{ + register_t saveintr; + + saveintr = intr_disable(); + if (x2apic_mode) + native_lapic_enable_x2apic(); + native_lapic_disable(); + intr_restore(saveintr); } static void native_lapic_setup(int boot) { struct lapic *la; - u_int32_t maxlvt; + uint32_t maxlvt; register_t saveintr; char buf[MAXCOMLEN + 1]; + saveintr = intr_disable(); + la = &lapics[lapic_id()]; KASSERT(la->la_present, ("missing APIC structure")); - saveintr = intr_disable(); - maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT; + maxlvt = (lapic_read32(LAPIC_VERSION) & APIC_VER_MAXLVT) >> MAXLVTSHIFT; /* Initialize the TPR to allow all interrupts. */ lapic_set_tpr(0); @@ -433,16 +552,21 @@ native_lapic_setup(int boot) lapic_enable(); /* Program LINT[01] LVT entries. */ - lapic->lvt_lint0 = lvt_mode(la, APIC_LVT_LINT0, lapic->lvt_lint0); - lapic->lvt_lint1 = lvt_mode(la, APIC_LVT_LINT1, lapic->lvt_lint1); + lapic_write32(LAPIC_LVT_LINT0, lvt_mode(la, APIC_LVT_LINT0, + lapic_read32(LAPIC_LVT_LINT0))); + lapic_write32(LAPIC_LVT_LINT1, lvt_mode(la, APIC_LVT_LINT1, + lapic_read32(LAPIC_LVT_LINT1))); /* Program the PMC LVT entry if present. */ - if (maxlvt >= APIC_LVT_PMC) - lapic->lvt_pcint = lvt_mode(la, APIC_LVT_PMC, lapic->lvt_pcint); + if (maxlvt >= APIC_LVT_PMC) { + lapic_write32(LAPIC_LVT_PCINT, lvt_mode(la, APIC_LVT_PMC, + LAPIC_LVT_PCINT)); + } /* Program timer LVT and setup handler. */ - la->lvt_timer_cache = lapic->lvt_timer = - lvt_mode(la, APIC_LVT_TIMER, lapic->lvt_timer); + la->lvt_timer_cache = lvt_mode(la, APIC_LVT_TIMER, + lapic_read32(LAPIC_LVT_TIMER)); + lapic_write32(LAPIC_LVT_TIMER, la->lvt_timer_cache); if (boot) { snprintf(buf, sizeof(buf), "cpu%d:timer", PCPU_GET(cpuid)); intrcnt_add(buf, &la->la_timer_count); @@ -460,14 +584,17 @@ native_lapic_setup(int boot) } /* Program error LVT and clear any existing errors. */ - lapic->lvt_error = lvt_mode(la, APIC_LVT_ERROR, lapic->lvt_error); - lapic->esr = 0; + lapic_write32(LAPIC_LVT_ERROR, lvt_mode(la, APIC_LVT_ERROR, + lapic_read32(LAPIC_LVT_ERROR))); + lapic_write32(LAPIC_ESR, 0); /* XXX: Thermal LVT */ /* Program the CMCI LVT entry if present. */ - if (maxlvt >= APIC_LVT_CMCI) - lapic->lvt_cmci = lvt_mode(la, APIC_LVT_CMCI, lapic->lvt_cmci); + if (maxlvt >= APIC_LVT_CMCI) { + lapic_write32(LAPIC_LVT_CMCI, lvt_mode(la, APIC_LVT_CMCI, + lapic_read32(LAPIC_LVT_CMCI))); + } intr_restore(saveintr); } @@ -478,9 +605,9 @@ native_lapic_reenable_pmc(void) #ifdef HWPMC_HOOKS uint32_t value; - value = lapic->lvt_pcint; + value = lapic_read32(LAPIC_LVT_PCINT); value &= ~APIC_LVT_M; - lapic->lvt_pcint = value; + lapic_write32(LAPIC_LVT_PCINT, value); #endif } @@ -491,7 +618,8 @@ lapic_update_pmc(void *dummy) struct lapic *la; la = &lapics[lapic_id()]; - lapic->lvt_pcint = lvt_mode(la, APIC_LVT_PMC, lapic->lvt_pcint); + lapic_write32(LAPIC_LVT_PCINT, lvt_mode(la, APIC_LVT_PMC, + lapic_read32(LAPIC_LVT_PCINT))); } #endif @@ -502,11 +630,11 @@ native_lapic_enable_pmc(void) u_int32_t maxlvt; /* Fail if the local APIC is not present. */ - if (lapic == NULL) + if (!x2apic_mode && lapic_map == NULL) return (0); /* Fail if the PMC LVT is not present. */ - maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT; + maxlvt = (lapic_read32(LAPIC_VERSION) & APIC_VER_MAXLVT) >> MAXLVTSHIFT; if (maxlvt < APIC_LVT_PMC) return (0); @@ -536,11 +664,11 @@ native_lapic_disable_pmc(void) u_int32_t maxlvt; /* Fail if the local APIC is not present. */ - if (lapic == NULL) + if (!x2apic_mode && lapic_map == NULL) return; /* Fail if the PMC LVT is not present. */ - maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT; + maxlvt = (lapic_read32(LAPIC_VERSION) & APIC_VER_MAXLVT) >> MAXLVTSHIFT; if (maxlvt < APIC_LVT_PMC) return; @@ -569,7 +697,8 @@ lapic_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period) lapic_timer_set_divisor(lapic_timer_divisor); lapic_timer_oneshot(la, APIC_TIMER_MAX_COUNT, 0); DELAY(1000000); - value = APIC_TIMER_MAX_COUNT - lapic->ccr_timer; + value = APIC_TIMER_MAX_COUNT - + lapic_read32(LAPIC_CCR_TIMER); if (value != APIC_TIMER_MAX_COUNT) break; lapic_timer_divisor <<= 1; @@ -613,21 +742,21 @@ native_lapic_disable(void) uint32_t value; /* Software disable the local APIC. */ - value = lapic->svr; + value = lapic_read32(LAPIC_SVR); value &= ~APIC_SVR_SWEN; - lapic->svr = value; + lapic_write32(LAPIC_SVR, value); } static void lapic_enable(void) { - u_int32_t value; + uint32_t value; /* Program the spurious vector to enable the local APIC. */ - value = lapic->svr; + value = lapic_read32(LAPIC_SVR); value &= ~(APIC_SVR_VECTOR | APIC_SVR_FOCUS); - value |= (APIC_SVR_FEN | APIC_SVR_SWEN | APIC_SPURIOUS_INT); - lapic->svr = value; + value |= APIC_SVR_FEN | APIC_SVR_SWEN | APIC_SPURIOUS_INT; + lapic_write32(LAPIC_SVR, value); } /* Reset the local APIC on the BSP during resume. */ @@ -641,27 +770,29 @@ lapic_resume(struct pic *pic, bool suspend_cancelled) static int native_lapic_id(void) { + uint32_t v; - KASSERT(lapic != NULL, ("local APIC is not mapped")); - return (lapic->id >> APIC_ID_SHIFT); + KASSERT(x2apic_mode || lapic_map != NULL, ("local APIC is not mapped")); + v = lapic_read32(LAPIC_ID); + if (!x2apic_mode) + v >>= APIC_ID_SHIFT; + return (v); } static int native_lapic_intr_pending(u_int vector) { - volatile u_int32_t *irr; + uint32_t irr; /* - * The IRR registers are an array of 128-bit registers each of - * which only describes 32 interrupts in the low 32 bits.. Thus, - * we divide the vector by 32 to get the 128-bit index. We then - * multiply that index by 4 to get the equivalent index from - * treating the IRR as an array of 32-bit registers. Finally, we - * modulus the vector by 32 to determine the individual bit to - * test. + * The IRR registers are an array of registers each of which + * only describes 32 interrupts in the low 32 bits. Thus, we + * divide the vector by 32 to get the register index. + * Finally, we modulus the vector by 32 to determine the + * individual bit to test. */ - irr = &lapic->irr0; - return (irr[(vector / 32) * 4] & 1 << (vector % 32)); + irr = lapic_read32(LAPIC_IRR0 + vector / 32); + return (irr & 1 << (vector % 32)); } static void @@ -818,13 +949,13 @@ static void lapic_set_tpr(u_int vector) { #ifdef CHEAP_TPR - lapic->tpr = vector; + lapic_write32(LAPIC_TPR, vector); #else - u_int32_t tpr; + uint32_t tpr; - tpr = lapic->tpr & ~APIC_TPR_PRIO; + tpr = lapic_read32(LAPIC_TPR) & ~APIC_TPR_PRIO; tpr |= vector; - lapic->tpr = tpr; + lapic_write32(LAPIC_TPR, tpr); #endif } @@ -832,7 +963,7 @@ static void native_lapic_eoi(void) { - lapic->eoi = 0; + lapic_write32_nofence(LAPIC_EOI, 0); } void @@ -894,46 +1025,46 @@ lapic_timer_set_divisor(u_int divisor) KASSERT(powerof2(divisor), ("lapic: invalid divisor %u", divisor)); KASSERT(ffs(divisor) <= sizeof(lapic_timer_divisors) / sizeof(u_int32_t), ("lapic: invalid divisor %u", divisor)); - lapic->dcr_timer = lapic_timer_divisors[ffs(divisor) - 1]; + lapic_write32(LAPIC_DCR_TIMER, lapic_timer_divisors[ffs(divisor) - 1]); } static void lapic_timer_oneshot(struct lapic *la, u_int count, int enable_int) { - u_int32_t value; + uint32_t value; value = la->lvt_timer_cache; value &= ~APIC_LVTT_TM; value |= APIC_LVTT_TM_ONE_SHOT; if (enable_int) value &= ~APIC_LVT_M; - lapic->lvt_timer = value; - lapic->icr_timer = count; + lapic_write32(LAPIC_LVT_TIMER, value); + lapic_write32(LAPIC_ICR_TIMER, count); } static void lapic_timer_periodic(struct lapic *la, u_int count, int enable_int) { - u_int32_t value; + uint32_t value; value = la->lvt_timer_cache; value &= ~APIC_LVTT_TM; value |= APIC_LVTT_TM_PERIODIC; if (enable_int) value &= ~APIC_LVT_M; - lapic->lvt_timer = value; - lapic->icr_timer = count; + lapic_write32(LAPIC_LVT_TIMER, value); + lapic_write32(LAPIC_ICR_TIMER, count); } static void lapic_timer_stop(struct lapic *la) { - u_int32_t value; + uint32_t value; value = la->lvt_timer_cache; value &= ~APIC_LVTT_TM; value |= APIC_LVT_M; - lapic->lvt_timer = value; + lapic_write32(LAPIC_LVT_TIMER, value); } void @@ -956,7 +1087,7 @@ native_lapic_enable_cmc(void) u_int apic_id; #ifdef DEV_ATPIC - if (lapic == NULL) + if (!x2apic_mode && lapic_map == NULL) return; #endif apic_id = PCPU_GET(apic_id); @@ -971,7 +1102,7 @@ native_lapic_enable_cmc(void) void lapic_handle_error(void) { - u_int32_t esr; + uint32_t esr; /* * Read the contents of the error status register. Write to @@ -979,8 +1110,8 @@ lapic_handle_error(void) * to update its value to indicate any errors that have * occurred since the previous write to the register. */ - lapic->esr = 0; - esr = lapic->esr; + lapic_write32(LAPIC_ESR, 0); + esr = lapic_read32(LAPIC_ESR); printf("CPU%d: local APIC error 0x%x\n", PCPU_GET(cpuid), esr); lapic_eoi(); @@ -1252,48 +1383,49 @@ DB_SHOW_COMMAND(lapic, db_show_lapic) uint32_t v; db_printf("lapic ID = %d\n", lapic_id()); - v = lapic->version; + v = lapic_read32(LAPIC_VERSION); db_printf("version = %d.%d\n", (v & APIC_VER_VERSION) >> 4, v & 0xf); db_printf("max LVT = %d\n", (v & APIC_VER_MAXLVT) >> MAXLVTSHIFT); - v = lapic->svr; + v = lapic_read32(LAPIC_SVR); db_printf("SVR = %02x (%s)\n", v & APIC_SVR_VECTOR, v & APIC_SVR_ENABLE ? "enabled" : "disabled"); - db_printf("TPR = %02x\n", lapic->tpr); + db_printf("TPR = %02x\n", lapic_read32(LAPIC_TPR)); -#define dump_field(prefix, index) \ - dump_mask(__XSTRING(prefix ## index), lapic->prefix ## index, \ +#define dump_field(prefix, regn, index) \ + dump_mask(__XSTRING(prefix ## index), \ + lapic_read32(LAPIC_ ## regn ## index), \ index * 32) db_printf("In-service Interrupts:\n"); - dump_field(isr, 0); - dump_field(isr, 1); - dump_field(isr, 2); - dump_field(isr, 3); - dump_field(isr, 4); - dump_field(isr, 5); - dump_field(isr, 6); - dump_field(isr, 7); + dump_field(isr, ISR, 0); + dump_field(isr, ISR, 1); + dump_field(isr, ISR, 2); + dump_field(isr, ISR, 3); + dump_field(isr, ISR, 4); + dump_field(isr, ISR, 5); + dump_field(isr, ISR, 6); + dump_field(isr, ISR, 7); db_printf("TMR Interrupts:\n"); - dump_field(tmr, 0); - dump_field(tmr, 1); - dump_field(tmr, 2); - dump_field(tmr, 3); - dump_field(tmr, 4); - dump_field(tmr, 5); - dump_field(tmr, 6); - dump_field(tmr, 7); + dump_field(tmr, TMR, 0); + dump_field(tmr, TMR, 1); + dump_field(tmr, TMR, 2); + dump_field(tmr, TMR, 3); + dump_field(tmr, TMR, 4); + dump_field(tmr, TMR, 5); + dump_field(tmr, TMR, 6); + dump_field(tmr, TMR, 7); db_printf("IRR Interrupts:\n"); - dump_field(irr, 0); - dump_field(irr, 1); - dump_field(irr, 2); - dump_field(irr, 3); - dump_field(irr, 4); - dump_field(irr, 5); - dump_field(irr, 6); - dump_field(irr, 7); + dump_field(irr, IRR, 0); + dump_field(irr, IRR, 1); + dump_field(irr, IRR, 2); + dump_field(irr, IRR, 3); + dump_field(irr, IRR, 4); + dump_field(irr, IRR, 5); + dump_field(irr, IRR, 6); + dump_field(irr, IRR, 7); #undef dump_field } @@ -1454,18 +1586,24 @@ native_lapic_ipi_wait(int delay) { int x; + /* LAPIC_ICR.APIC_DELSTAT_MASK is undefined in x2APIC mode */ + if (x2apic_mode) + return (1); + /* * Wait delay microseconds for IPI to be sent. If delay is * -1, we wait forever. */ if (delay == -1) { - while ((lapic->icr_lo & APIC_DELSTAT_MASK) != APIC_DELSTAT_IDLE) + while ((lapic_read_icr_lo() & APIC_DELSTAT_MASK) != + APIC_DELSTAT_IDLE) ia32_pause(); return (1); } for (x = 0; x < delay; x += 5) { - if ((lapic->icr_lo & APIC_DELSTAT_MASK) == APIC_DELSTAT_IDLE) + if ((lapic_read_icr_lo() & APIC_DELSTAT_MASK) == + APIC_DELSTAT_IDLE) return (1); DELAY(5); } @@ -1475,29 +1613,45 @@ native_lapic_ipi_wait(int delay) static void native_lapic_ipi_raw(register_t icrlo, u_int dest) { - register_t value, saveintr; + uint64_t icr; + uint32_t vhi, vlo; + register_t saveintr; /* XXX: Need more sanity checking of icrlo? */ - KASSERT(lapic != NULL, ("%s called too early", __func__)); - KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0, + KASSERT(x2apic_mode || lapic_map != NULL, + ("%s called too early", __func__)); + KASSERT(x2apic_mode || + (dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0, ("%s: invalid dest field", __func__)); KASSERT((icrlo & APIC_ICRLO_RESV_MASK) == 0, ("%s: reserved bits set in ICR LO register", __func__)); /* Set destination in ICR HI register if it is being used. */ saveintr = intr_disable(); + if (!x2apic_mode) + icr = lapic_read_icr(); + if ((icrlo & APIC_DEST_MASK) == APIC_DEST_DESTFLD) { - value = lapic->icr_hi; - value &= ~APIC_ID_MASK; - value |= dest << APIC_ID_SHIFT; - lapic->icr_hi = value; + if (x2apic_mode) { + vhi = dest; + } else { + vhi = icr >> 32; + vhi &= ~APIC_ID_MASK; + vhi |= dest << APIC_ID_SHIFT; + } + } else { + vhi = 0; } /* Program the contents of the IPI and dispatch it. */ - value = lapic->icr_lo; - value &= APIC_ICRLO_RESV_MASK; - value |= icrlo; - lapic->icr_lo = value; + if (x2apic_mode) { + vlo = icrlo; + } else { + vlo = icr; + vlo &= APIC_ICRLO_RESV_MASK; + vlo |= icrlo; + } + lapic_write_icr(vhi, vlo); intr_restore(saveintr); } @@ -1537,7 +1691,8 @@ native_lapic_ipi_vectored(u_int vector, int dest) icrlo |= APIC_DEST_ALLESELF; break; default: - KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0, + KASSERT(x2apic_mode || + (dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0, ("%s: invalid destination 0x%x", __func__, dest)); destfield = dest; } @@ -1574,7 +1729,7 @@ native_lapic_ipi_vectored(u_int vector, int dest) printf("APIC: IPI might be stuck\n"); #else /* !needsattention */ /* Wait until mesage is sent without a timeout. */ - while (lapic->icr_lo & APIC_DELSTAT_PEND) + while (lapic_read_icr_lo() & APIC_DELSTAT_PEND) ia32_pause(); #endif /* needsattention */ } diff --git a/sys/x86/xen/xen_apic.c b/sys/x86/xen/xen_apic.c index 53083ac56ffd..ed86734f888c 100644 --- a/sys/x86/xen/xen_apic.c +++ b/sys/x86/xen/xen_apic.c @@ -350,6 +350,7 @@ xen_pv_lapic_set_lvt_triggermode(u_int apic_id, u_int lvt, struct apic_ops xen_apic_ops = { .create = xen_pv_lapic_create, .init = xen_pv_lapic_init, + .xapic_mode = xen_pv_lapic_disable, .setup = xen_pv_lapic_setup, .dump = xen_pv_lapic_dump, .disable = xen_pv_lapic_disable, From 070b49032340e0c14238a0f8e8c11cef76842535 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 9 Feb 2015 21:03:23 +0000 Subject: [PATCH 56/75] Use __builtin_popcnt() to implement a BIT_COUNT() operation for bitsets and use this to implement CPU_COUNT() to count the number of CPUs in a cpuset. MFC after: 2 weeks --- sys/sys/bitset.h | 10 ++++++++++ sys/sys/cpuset.h | 1 + 2 files changed, 11 insertions(+) diff --git a/sys/sys/bitset.h b/sys/sys/bitset.h index e6c4dc374a3d..9871c241f260 100644 --- a/sys/sys/bitset.h +++ b/sys/sys/bitset.h @@ -176,4 +176,14 @@ __bit; \ }) +#define BIT_COUNT(_s, p) __extension__ ({ \ + __size_t __i; \ + int __count; \ + \ + __count = 0; \ + for (__i = 0; __i < __bitset_words((_s)); __i++) \ + __count += __builtin_popcount((p)->__bits[__i]); \ + __count; \ +}) + #endif /* !_SYS_BITSET_H_ */ diff --git a/sys/sys/cpuset.h b/sys/sys/cpuset.h index d3d60e773ec3..9ccba5890216 100644 --- a/sys/sys/cpuset.h +++ b/sys/sys/cpuset.h @@ -60,6 +60,7 @@ #define CPU_OR_ATOMIC(d, s) BIT_OR_ATOMIC(CPU_SETSIZE, d, s) #define CPU_COPY_STORE_REL(f, t) BIT_COPY_STORE_REL(CPU_SETSIZE, f, t) #define CPU_FFS(p) BIT_FFS(CPU_SETSIZE, p) +#define CPU_COUNT(p) BIT_COUNT(CPU_SETSIZE, p) /* * Valid cpulevel_t values. From e9cc10049ec18bcf14efaeac466eaa7a22f1108f Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 9 Feb 2015 21:15:52 +0000 Subject: [PATCH 57/75] Add tests for `pw usernext'. PR: 197120 Submitted by: Robert O'Neil Approved by: will --- usr.sbin/pw/tests/Makefile | 3 ++- usr.sbin/pw/tests/pw_usernext.sh | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100755 usr.sbin/pw/tests/pw_usernext.sh diff --git a/usr.sbin/pw/tests/Makefile b/usr.sbin/pw/tests/Makefile index 1283ff2a7d27..37d9c71281ed 100644 --- a/usr.sbin/pw/tests/Makefile +++ b/usr.sbin/pw/tests/Makefile @@ -11,7 +11,8 @@ ATF_TESTS_SH= pw_etcdir \ pw_groupmod \ pw_useradd \ pw_userdel \ - pw_usermod + pw_usermod \ + pw_usernext .for tp in ${ATF_TESTS_SH} TEST_METADATA.${tp}+= required_user="root" diff --git a/usr.sbin/pw/tests/pw_usernext.sh b/usr.sbin/pw/tests/pw_usernext.sh new file mode 100755 index 000000000000..1cdadee90efb --- /dev/null +++ b/usr.sbin/pw/tests/pw_usernext.sh @@ -0,0 +1,42 @@ +# $FreeBSD$ + +# Import helper functions +. $(atf_get_srcdir)/helper_functions.shin + +# Test usernext after adding a random number of new users. +atf_test_case usernext +usernext_body() { + populate_etc_skel + + var0=1 + LIMIT=`jot -r 1 2 10` + while [ "$var0" -lt "$LIMIT" ] + do + atf_check -s exit:0 ${PW} useradd test$var0 + var0=`expr $var0 + 1` + done + atf_check -s exit:0 -o match:"100${LIMIT}:100${LIMIT}" \ + ${PW} usernext +} + +# Test usernext when multiple users are added to the same group so +# that group id doesn't increment at the same pace as new users. +atf_test_case usernext_assigned_group +usernext_assigned_group_body() { + populate_etc_skel + + var0=1 + LIMIT=`jot -r 1 2 10` + while [ "$var0" -lt "$LIMIT" ] + do + atf_check -s exit:0 ${PW} useradd -n test$var0 -g 0 + var0=`expr $var0 + 1` + done + atf_check -s exit:0 -o match:"100${LIMIT}:1001}" \ + ${PW} usernext +} + +atf_init_test_cases() { + atf_add_test_case usernext + atf_add_test_case usernext_assigned_group +} From 5329c0aec8b450a85841cb906991edff134a5829 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 9 Feb 2015 21:39:18 +0000 Subject: [PATCH 58/75] Use __builtin_popcountl() instead of __builtin_popcount(). Submitted by: jkim --- sys/sys/bitset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/sys/bitset.h b/sys/sys/bitset.h index 9871c241f260..5ad28d399128 100644 --- a/sys/sys/bitset.h +++ b/sys/sys/bitset.h @@ -182,7 +182,7 @@ \ __count = 0; \ for (__i = 0; __i < __bitset_words((_s)); __i++) \ - __count += __builtin_popcount((p)->__bits[__i]); \ + __count += __builtin_popcountl((p)->__bits[__i]); \ __count; \ }) From a2a78645647a8b2059a91f5382803c98b38bd68d Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Mon, 9 Feb 2015 21:47:12 +0000 Subject: [PATCH 59/75] Fix DMA address casts. Regression issue after r278279. MFC after: 3 days --- sys/dev/usb/controller/xhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c index e9b72a34e97f..2ad79646029a 100644 --- a/sys/dev/usb/controller/xhci.c +++ b/sys/dev/usb/controller/xhci.c @@ -492,7 +492,7 @@ xhci_start_controller(struct xhci_softc *sc) XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr); XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32)); - addr = (uint64_t)buf_res.physaddr; + addr = buf_res.physaddr; DPRINTF("ERSTBA(0)=0x%016llx\n", (unsigned long long)addr); @@ -1114,7 +1114,7 @@ xhci_interrupt_poll(struct xhci_softc *sc) * register. */ - addr = (uint32_t)buf_res.physaddr; + addr = buf_res.physaddr; addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[i]; /* try to clear busy bit */ From a2e77dc90674f19d7e1498d05671f3728a0c3d1a Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Feb 2015 23:04:30 +0000 Subject: [PATCH 60/75] Add the ability to print a vendor copyright in dmesg. --- sys/sys/copyright.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sys/sys/copyright.h b/sys/sys/copyright.h index 3e1b2b5687e8..6e47358ac14b 100644 --- a/sys/sys/copyright.h +++ b/sys/sys/copyright.h @@ -28,6 +28,10 @@ /* Copyrights macros */ +/* Add a FreeBSD vendor copyright here */ +#define COPYRIGHT_Vendor \ + "" + /* FreeBSD */ #define COPYRIGHT_FreeBSD \ "Copyright (c) 1992-2015 The FreeBSD Project.\n" @@ -48,5 +52,6 @@ #define COPYRIGHT_PC98 #endif -char copyright[] = COPYRIGHT_FreeBSD COPYRIGHT_PC98 COPYRIGHT_UCB; +char copyright[] = COPYRIGHT_Vendor COPYRIGHT_FreeBSD COPYRIGHT_PC98 \ + COPYRIGHT_UCB; char trademark[] = TRADEMARK_Foundation; From 842ab62b05137920c4d3e076f61cf65c3877f0ec Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Feb 2015 23:13:50 +0000 Subject: [PATCH 61/75] Notify devd(8) when a process crashed. This change implements a notification (via devctl) to userland when the kernel produces coredumps after a process has crashed. devd can then run a specific command to produce a human readable crash report. The command is most usually a helper that runs gdb/lldb commands on the file/coredump pair. It's possible to use this functionality for implementing automatic generation of crash reports. devd(8) will be notified of the full path of the binary that crashed and the full path of the coredump file. --- etc/devd.conf | 12 ++++++++++++ sys/kern/kern_sig.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/etc/devd.conf b/etc/devd.conf index 4120c637c19f..7a033a71dc48 100644 --- a/etc/devd.conf +++ b/etc/devd.conf @@ -325,4 +325,16 @@ notify 100 { action "/usr/sbin/automount -c"; }; +# Handle userland coredumps. +# This commented out handler makes it possible to run an +# automated debugging session after the core dump is generated. +# Replace action with a proper coredump handler, but be aware that +# it will run with elevated privileges. +notify 10 { + match "system" "kernel"; + match "subsystem" "signal"; + match "type" "coredump"; + action "logger $comm $core"; +}; + */ diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 45cb4b95630c..f25fc16fa6f3 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -3237,6 +3238,9 @@ coredump(struct thread *td) void *rl_cookie; off_t limit; int compress; + char *data = NULL; + size_t len; + char *fullpath, *freepath = NULL; #ifdef COMPRESS_USER_CORES compress = compress_user_cores; @@ -3322,9 +3326,36 @@ coredump(struct thread *td) error1 = vn_close(vp, FWRITE, cred, td); if (error == 0) error = error1; + else + goto out; + /* + * Notify the userland helper that a process triggered a core dump. + * This allows the helper to run an automated debugging session. + */ + len = MAXPATHLEN * 2 + 5 /* comm= */ + 5 /* core= */ + 1; + data = malloc(len, M_TEMP, M_NOWAIT); + if (data == NULL) + goto out; + if (vn_fullpath_global(td, p->p_textvp, &fullpath, &freepath) != 0) + goto out; + snprintf(data, len, "comm=%s", fullpath); + if (freepath != NULL) { + free(freepath, M_TEMP); + freepath = NULL; + } + if (vn_fullpath_global(td, vp, &fullpath, &freepath) != 0) + goto out; + snprintf(data, len, "%s core=%s", data, fullpath); + devctl_notify("kernel", "signal", "coredump", data); + free(name, M_TEMP); +out: #ifdef AUDIT audit_proc_coredump(td, name, error); #endif + if (freepath != NULL) + free(freepath, M_TEMP); + if (data != NULL) + free(data, M_TEMP); free(name, M_TEMP); return (error); } From 0639437b99fa9e1a31aff0af83fbe8a588ec216a Mon Sep 17 00:00:00 2001 From: Jamie Gritton Date: Tue, 10 Feb 2015 00:48:51 +0000 Subject: [PATCH 62/75] Un-revert the r278323 again - whatever Jenkins/kyua is up it, it has nothing to do with this. --- etc/rc.d/jail | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/etc/rc.d/jail b/etc/rc.d/jail index 393e35526574..ea62f4839db4 100755 --- a/etc/rc.d/jail +++ b/etc/rc.d/jail @@ -233,8 +233,7 @@ parse_options() fi eval : \${jail_${_j}_procfs_enable:=${jail_procfs_enable:-NO}} if checkyesno jail_${_j}_procfs_enable; then - echo " mount += " \ - "\"procfs ${_rootdir%/}/proc procfs rw 0 0\";" + echo " mount.procfs;" fi eval : \${jail_${_j}_mount_enable:=${jail_mount_enable:-NO}} From 9ddcd32269d13c7c4a29f76f7785198a6d49a185 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Tue, 10 Feb 2015 00:55:42 +0000 Subject: [PATCH 63/75] Set thread priorities on multithreaded CPUs so that threads holding a spinlock are high-priority and threads waiting for a spinlock are set to low priority. --- sys/powerpc/aim/machdep.c | 5 ++++- sys/powerpc/include/cpu.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index 2980b0997783..92a06d2131b7 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -750,6 +750,7 @@ spinlock_enter(void) td = curthread; if (td->td_md.md_spinlock_count == 0) { + __asm __volatile("or 2,2,2"); /* Set high thread priority */ msr = intr_disable(); td->td_md.md_spinlock_count = 1; td->td_md.md_saved_msr = msr; @@ -768,8 +769,10 @@ spinlock_exit(void) critical_exit(); msr = td->td_md.md_saved_msr; td->td_md.md_spinlock_count--; - if (td->td_md.md_spinlock_count == 0) + if (td->td_md.md_spinlock_count == 0) { intr_restore(msr); + __asm __volatile("or 6,6,6"); /* Set normal thread priority */ + } } int db_trap_glue(struct trapframe *); /* Called from trap_subr.S */ diff --git a/sys/powerpc/include/cpu.h b/sys/powerpc/include/cpu.h index 6ef9882e3b96..65358a6909f5 100644 --- a/sys/powerpc/include/cpu.h +++ b/sys/powerpc/include/cpu.h @@ -88,7 +88,7 @@ get_cyclecount(void) } #define cpu_getstack(td) ((td)->td_frame->fixreg[1]) -#define cpu_spinwait() /* nothing */ +#define cpu_spinwait() __asm __volatile("or 27,27,27") /* yield */ extern char btext[]; extern char etext[]; From a4c6f6e512eddd9be627e9e8d1009efacd3408b9 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Tue, 10 Feb 2015 00:57:26 +0000 Subject: [PATCH 64/75] Add error reporting to interrupt CPU binding. --- sys/powerpc/pseries/xics.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sys/powerpc/pseries/xics.c b/sys/powerpc/pseries/xics.c index f1a3c8b38c9a..2d012c5faa7b 100644 --- a/sys/powerpc/pseries/xics.c +++ b/sys/powerpc/pseries/xics.c @@ -197,12 +197,13 @@ xicp_bind(device_t dev, u_int irq, cpuset_t cpumask) { struct xicp_softc *sc = device_get_softc(dev); cell_t status, cpu; - int ncpus, i; + int ncpus, i, error; /* * This doesn't appear to actually support affinity groups, so pick a * random CPU. */ + ncpus = 0; CPU_FOREACH(cpu) if (CPU_ISSET(cpu, &cpumask)) ncpus++; @@ -217,8 +218,10 @@ xicp_bind(device_t dev, u_int irq, cpuset_t cpumask) } - rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, XICP_PRIORITY, - &status); + error = rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, + XICP_PRIORITY, &status); + if (error < 0) + panic("Cannot bind interrupt %d to CPU %d", irq, cpu); } static void From ec273ebf3b6aed5fba8c56b6ece5ad8693a48ea7 Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Tue, 10 Feb 2015 01:02:02 +0000 Subject: [PATCH 65/75] Comments. MFC after: 3 days --- usr.sbin/bsdconfig/networking/share/device.subr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.sbin/bsdconfig/networking/share/device.subr b/usr.sbin/bsdconfig/networking/share/device.subr index bb41be300a0c..6ee08ce8f5ac 100644 --- a/usr.sbin/bsdconfig/networking/share/device.subr +++ b/usr.sbin/bsdconfig/networking/share/device.subr @@ -207,7 +207,7 @@ f_dialog_menu_netdev_edit() '3 $msg_ipaddr4' '$ipaddr' '4 $msg_netmask' '$netmask' '5 $msg_options' '$options' - " + " # END-QUOTE eval f_dialog_menu_size height width rows \ \"\$DIALOG_TITLE\" \ \"\$DIALOG_BACKTITLE\" \ From d5d9fbbae2476b968b4b542e3a80ad2530e782f3 Mon Sep 17 00:00:00 2001 From: Navdeep Parhar Date: Tue, 10 Feb 2015 01:16:43 +0000 Subject: [PATCH 66/75] cxgbe(4): allow the SET_FILTER_MODE ioctl to change the mode when it's safe to do so. MFC after: 1 month --- sys/dev/cxgbe/common/t4_hw.c | 52 +++++++++++++++++++----------------- sys/dev/cxgbe/t4_main.c | 10 +------ 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c index 2d5d79d752f0..e2efb782e703 100644 --- a/sys/dev/cxgbe/common/t4_hw.c +++ b/sys/dev/cxgbe/common/t4_hw.c @@ -3111,6 +3111,31 @@ void t4_write_rss_pf_mask(struct adapter *adapter, u32 pfmask) &pfmask, 1, A_TP_RSS_PF_MSK); } +static void refresh_vlan_pri_map(struct adapter *adap) +{ + + t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, + &adap->params.tp.vlan_pri_map, 1, + A_TP_VLAN_PRI_MAP); + + /* + * Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field + * shift positions of several elements of the Compressed Filter Tuple + * for this adapter which we need frequently ... + */ + adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN); + adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID); + adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT); + adap->params.tp.protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL); + + /* + * If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID + * represents the presense of an Outer VLAN instead of a VNIC ID. + */ + if ((adap->params.tp.ingress_config & F_VNIC) == 0) + adap->params.tp.vnic_shift = -1; +} + /** * t4_set_filter_mode - configure the optional components of filter tuples * @adap: the adapter @@ -3134,6 +3159,8 @@ int t4_set_filter_mode(struct adapter *adap, unsigned int mode_map) return -EINVAL; t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &mode_map, 1, A_TP_VLAN_PRI_MAP); + refresh_vlan_pri_map(adap); + return 0; } @@ -5618,33 +5645,10 @@ int __devinit t4_init_tp_params(struct adapter *adap) for (chan = 0; chan < NCHAN; chan++) adap->params.tp.tx_modq[chan] = chan; - /* - * Cache the adapter's Compressed Filter Mode and global Incress - * Configuration. - */ - t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, - &adap->params.tp.vlan_pri_map, 1, - A_TP_VLAN_PRI_MAP); t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &adap->params.tp.ingress_config, 1, A_TP_INGRESS_CONFIG); - - /* - * Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field - * shift positions of several elements of the Compressed Filter Tuple - * for this adapter which we need frequently ... - */ - adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN); - adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID); - adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT); - adap->params.tp.protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL); - - /* - * If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID - * represents the presense of an Outer VLAN instead of a VNIC ID. - */ - if ((adap->params.tp.ingress_config & F_VNIC) == 0) - adap->params.tp.vnic_shift = -1; + refresh_vlan_pri_map(adap); return 0; } diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index dc20855eed80..94e7ed1fe492 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -7116,10 +7116,9 @@ get_filter_mode(struct adapter *sc, uint32_t *mode) log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", device_get_nameunit(sc->dev), sc->params.tp.vlan_pri_map, fconf); - sc->params.tp.vlan_pri_map = fconf; } - *mode = fconf_to_mode(sc->params.tp.vlan_pri_map); + *mode = fconf_to_mode(fconf); end_synchronized_op(sc, LOCK_HELD); return (0); @@ -7150,14 +7149,7 @@ set_filter_mode(struct adapter *sc, uint32_t mode) } #endif -#ifdef notyet rc = -t4_set_filter_mode(sc, fconf); - if (rc == 0) - sc->filter_mode = fconf; -#else - rc = ENOTSUP; -#endif - done: end_synchronized_op(sc, LOCK_HELD); return (rc); From cf4b80d882b1aad0bb55c2cf2902cfe4b93fac15 Mon Sep 17 00:00:00 2001 From: Glen Barber Date: Tue, 10 Feb 2015 01:35:26 +0000 Subject: [PATCH 67/75] Exclude 'tests' from DEBUG_DISTRIBUTIONS. Sponsored by: The FreeBSD Foundation --- Makefile.inc1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.inc1 b/Makefile.inc1 index e4eed287f9c6..f0fa94961708 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -823,7 +823,7 @@ EXTRA_DISTRIBUTIONS+= tests DEBUG_DISTRIBUTIONS= .if ${MK_DEBUG_FILES} != "no" -DEBUG_DISTRIBUTIONS+= base ${EXTRA_DISTRIBUTIONS:S,doc,,} +DEBUG_DISTRIBUTIONS+= base ${EXTRA_DISTRIBUTIONS:S,doc,,:S,tests,,} .endif MTREE_MAGIC?= mtree 2.0 From ad8d629a0c3d90072e5ccb38f700b4325cce7070 Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Tue, 10 Feb 2015 02:53:26 +0000 Subject: [PATCH 68/75] Whitespace. MFC after: 3 days --- usr.sbin/bsdconfig/usermgmt/share/user.subr | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/usr.sbin/bsdconfig/usermgmt/share/user.subr b/usr.sbin/bsdconfig/usermgmt/share/user.subr index 5fd65fbe088b..e6beb54a6065 100644 --- a/usr.sbin/bsdconfig/usermgmt/share/user.subr +++ b/usr.sbin/bsdconfig/usermgmt/share/user.subr @@ -830,8 +830,7 @@ f_user_delete() f_eval_catch $funcname \ pw '%s -H 0' "$cmd" else - f_eval_catch $funcname \ - pw '%s -h -' "$cmd" + f_eval_catch $funcname pw '%s -h -' "$cmd" fi fi fi From fb1f1bee0d46c9c2ed82879f63074f125c4b2e12 Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Tue, 10 Feb 2015 02:55:10 +0000 Subject: [PATCH 69/75] Eliminate sub-shells where possible for performance. MFC after: 7 days --- .../bsdconfig/timezone/share/continents.subr | 45 ++++++++++++++----- .../bsdconfig/timezone/share/countries.subr | 43 ++++++++++++++---- usr.sbin/bsdconfig/timezone/timezone | 42 ++++++++--------- 3 files changed, 89 insertions(+), 41 deletions(-) diff --git a/usr.sbin/bsdconfig/timezone/share/continents.subr b/usr.sbin/bsdconfig/timezone/share/continents.subr index 02c40717763e..764f33fc6c50 100644 --- a/usr.sbin/bsdconfig/timezone/share/continents.subr +++ b/usr.sbin/bsdconfig/timezone/share/continents.subr @@ -1,6 +1,6 @@ if [ ! "$_TIMEZONE_CONTINENTS_SUBR" ]; then _TIMEZONE_CONTINENTS_SUBR=1 # -# Copyright (c) 2011-2012 Devin Teske +# Copyright (c) 2011-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -87,7 +87,7 @@ export continent_utc_title ############################################################ FUNCTIONS -# f_continent $cont $property +# f_continent $cont $property [$var_to_set] # # Returns a single property of a given continent. Available properties are: # @@ -102,37 +102,60 @@ export continent_utc_title # (which appears after continent selection). # menu_list Menu-list of regions for this continent. # +# If $var_to_set is missing or NULL, the value of $var_to_get is printed to +# standard output for capturing in a sub-shell (which is less-recommended +# because of performance degredation; for example, when called in a loop). +# f_continent() { - local cont="$1" property="$2" - eval echo \"\${continent_${cont}_$property}\" + f_getvar "continent_${1}_$2" $3 } -# f_find_continent $title +# f_find_continent $title [$var_to_set] # # Returns continent identifier given continent title. # +# If $var_to_set is missing or NULL, the value of $var_to_get is printed to +# standard output for capturing in a sub-shell (which is less-recommended +# because of performance degredation; for example, when called in a loop). +# f_find_continent() { - local cont - for cont in $CONTINENTS; do - if [ "$1" = "$( f_continent $cont title )" ]; then - echo "$cont" + local __cont __title + for __cont in $CONTINENTS; do + f_continent $__cont title __title + if [ "$1" = "$__title" ]; then + if [ "$2" ]; then + setvar "$2" $__cont + else + echo "$__cont" + fi return $SUCCESS fi done return $FAILURE } -# f_OCEANP $cont +# f_OCEANP $cont [$var_to_set] # # Returns "1" if the first argument is an ocean, otherwise NULL. # +# If $var_to_set is missing or NULL, the value of $var_to_get is printed to +# standard output for capturing in a sub-shell (which is less-recommended +# because of performance degredation; for example, when called in a loop). +# f_OCEANP() { case "$1" in arctic|atlantic|indian|pacific) - echo 1 + if [ "$2" ]; then + setvar "$2" 1 + else + echo 1 + fi + ;; + *) + [ "$2" ] && setvar "$2" "" esac } diff --git a/usr.sbin/bsdconfig/timezone/share/countries.subr b/usr.sbin/bsdconfig/timezone/share/countries.subr index ff05766ba27a..8958e877c3d8 100644 --- a/usr.sbin/bsdconfig/timezone/share/countries.subr +++ b/usr.sbin/bsdconfig/timezone/share/countries.subr @@ -1,6 +1,6 @@ if [ ! "$_TIMEZONE_COUNTRIES_SUBR" ]; then _TIMEZONE_COUNTRIES_SUBR=1 # -# Copyright (c) 2011-2012 Devin Teske +# Copyright (c) 2011-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -25,8 +25,10 @@ if [ ! "$_TIMEZONE_COUNTRIES_SUBR" ]; then _TIMEZONE_COUNTRIES_SUBR=1 # SUCH DAMAGE. # # $FreeBSD$ +# +############################################################ FUNCTIONS -# f_country $code $property +# f_country $code $property [$var_to_set] # # Returns a single property of a given country. Available properties are: # @@ -44,10 +46,13 @@ if [ ! "$_TIMEZONE_COUNTRIES_SUBR" ]; then _TIMEZONE_COUNTRIES_SUBR=1 # descr_N Like name, but for the Nth zone when the country has # multiple zones (nzones > 0) # +# If $var_to_set is missing or NULL, the value of $var_to_get is printed to +# standard output for capturing in a sub-shell (which is less-recommended +# because of performance degredation; for example, when called in a loop). +# f_country() { - local code="$1" property="$2" - eval echo \"\${country_${code}_$property}\" + f_getvar "country_${1}_$2" $3 } # f_sort_countries @@ -59,22 +64,42 @@ f_country() # afterward is the sh(1) function which utilizes the below awk script. # f_sort_countries_awk=' +function _asorti(src, dest) { - split($0, array, /[[:space:]]+/) + k = nitems = 0 + for (i in src) dest[++nitems] = i + for (i = 1; i <= nitems; k = i++) { + idx = dest[i] + while ((k > 0) && (dest[k] > idx)) { + dest[k+1] = dest[k]; k-- + } + dest[k+1] = idx + } + return nitems +} +BEGIN { + split(ENVIRON["COUNTRIES"], array, /[[:space:]]+/) for (item in array) { tlc = array[item] - print ENVIRON["country_" tlc "_name"] " " tlc + name = ENVIRON["country_" tlc "_name"] + countries[name] = tlc } + n = _asorti(countries, sorted_countries) + for (i = 1; i <= n; i++) + print countries[sorted_countries[i]] + exit } ' f_sort_countries() { - COUNTRIES=$( echo "$COUNTRIES" | awk "$f_sort_countries_awk" | - sort | awk '{print $NF}' ) - export COUNTRIES + export COUNTRIES # for awk(1) ENVIRON[] visibility + COUNTRIES=$( awk "$f_sort_countries_awk" ) + export COUNTRIES # Pedantic } +############################################################ MAIN + f_dprintf "%s: Successfully loaded." timezone/countries.subr fi # ! $_TIMEZONE_COUNTRIES_SUBR diff --git a/usr.sbin/bsdconfig/timezone/timezone b/usr.sbin/bsdconfig/timezone/timezone index 66f2d7892286..a2914429846e 100755 --- a/usr.sbin/bsdconfig/timezone/timezone +++ b/usr.sbin/bsdconfig/timezone/timezone @@ -1,6 +1,6 @@ #!/bin/sh #- -# Copyright (c) 2011-2013 Devin Teske +# Copyright (c) 2011-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -280,8 +280,8 @@ f_make_menus # creates $continent_menu_list and $continent_*_menu_list # # Launch application main menu # -defaultctry="" -defaultzone="" +defaultctry= +defaultzone= NEED_CONTINENT=1 NEED_COUNTRY=1 while :; do @@ -299,10 +299,10 @@ while :; do continent=$( eval f_dialog_menutag2item \"\$mtag\" \ $continent_menu_list ) - cont=$( f_find_continent "$continent" ) - cont_title=$( f_continent $cont title ) - nitems=$( f_continent $cont nitems ) - isocean=$( f_OCEANP $cont ) + f_find_continent "$continent" cont + f_continent $cont title cont_title + f_continent $cont nitems nitems + f_OCEANP $cont isocean fi if [ "$NEED_COUNTRY" ]; then @@ -345,7 +345,7 @@ while :; do # # Calculate size of menu # - menu_list=$( f_continent $cont menu_list ) + f_continent $cont menu_list menu_list eval f_dialog_menu_size height width rows \ \"\$title\" \ \"\$btitle\" \ @@ -378,7 +378,7 @@ while :; do fi # Get the country code from the user's selection - tlc=$( f_continent $cont tlc_$tag ) + f_continent $cont tlc_$tag tlc NEED_COUNTRY= fi @@ -387,12 +387,12 @@ while :; do # If the selection has only one zone (nzones == -1), # just set it. # - nzones=$( f_country $tlc nzones ) + f_country $tlc nzones nzones if [ $nzones -lt 0 ]; then - real_cont=$( f_country $tlc cont ) - real_continent=$( f_continent $real_cont name ) - name=$( f_country $tlc name ) - filename=$( f_country $tlc filename ) + f_country $tlc cont real_cont + f_continent $real_cont name real_continent + f_country $tlc name name + f_country $tlc filename filename if ! f_confirm_zone "$real_continent/$filename"; then [ $nitems -eq 1 ] && NEED_CONTINENT=1 @@ -400,13 +400,13 @@ while :; do continue fi else - f_sprintf title "$msg_country_time_zones" \ - "$( f_country $tlc name )" + f_country $tlc name name + f_sprintf title "$msg_country_time_zones" "$name" f_dialog_title "$title" title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE" f_dialog_title_restore prompt="$msg_select_zone" - menu_list=$( f_country $tlc menu_list ) + f_country $tlc menu_list menu_list eval f_dialog_menu_size height width rows \ \"\$title\" \"\$btitle\" \"\$prompt\" \"\" $menu_list @@ -435,10 +435,10 @@ while :; do continue fi - real_cont=$( f_country $tlc cont_$n ) - real_continent=$( f_continent $real_cont name ) - name=$( f_country $tlc name ) - filename=$( f_country $tlc filename_$n ) + f_country $tlc cont_$n real_cont + f_continent $real_cont name real_continent + f_country $tlc name name + f_country $tlc filename_$n filename f_confirm_zone "$real_continent/$filename" || continue fi From 3c63cc68aede27b10861ec56db126766281b4642 Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Tue, 10 Feb 2015 03:12:11 +0000 Subject: [PATCH 70/75] Add bsdconfig api functions f_dialog_pause()/f_dialog_pause_no_cancel() --- usr.sbin/bsdconfig/share/dialog.subr | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/usr.sbin/bsdconfig/share/dialog.subr b/usr.sbin/bsdconfig/share/dialog.subr index db99a70d46c1..13d209cfead0 100644 --- a/usr.sbin/bsdconfig/share/dialog.subr +++ b/usr.sbin/bsdconfig/share/dialog.subr @@ -1580,6 +1580,56 @@ f_xdialog_info() -1 # timeout of -1 means abort when EOF on stdin } +############################################################ PAUSE FUNCTIONS + +# f_dialog_pause $msg_text $duration [$hline] +# +# Display a message in a widget with a progress bar that runs backward for +# $duration seconds. +# +f_dialog_pause() +{ + local pause_text="$1" duration="$2" hline="$3" height width + f_isinteger "$duration" || return $FAILURE + f_dialog_buttonbox_size height width \ + "$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$pause_text" "$hline" + if [ "$USE_XDIALOG" ]; then + $DIALOG \ + --title "$DIALOG_TITLE" \ + --backtitle "$DIALOG_BACKTITLE" \ + --ok-label "$msg_skip" \ + --cancel-label "$msg_cancel" \ + ${noCancel:+--no-cancel} \ + --timeout "$duration" \ + --yesno "$pause_text" \ + $height $width + else + [ $duration -gt 0 ] && duration=$(( $duration - 1 )) + [ $duration -gt 1 ] && duration=$(( $duration - 1 )) + height=$(( $height + 3 )) # Add height for progress bar + $DIALOG \ + --title "$DIALOG_TITLE" \ + --backtitle "$DIALOG_BACKTITLE" \ + --hline "$hline" \ + --ok-label "$msg_skip" \ + --cancel-label "$msg_cancel" \ + ${noCancel:+--no-cancel} \ + --pause "$pause_text" \ + $height $width "$duration" + fi +} + +# f_dialog_pause_no_cancel $msg_text $duration [$hline] +# +# Display a message in a widget with a progress bar that runs backward for +# $duration seconds. No cancel button is provided. Always returns success. +# +f_dialog_pause_no_cancel() +{ + noCancel=1 f_dialog_pause "$@" + return $SUCCESS +} + ############################################################ MSGBOX FUNCTIONS # f_dialog_msgbox $msg_text [$hline] From b39eff3362b60b3f3b9ccff0a7f3bb543128b7fb Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Tue, 10 Feb 2015 03:15:54 +0000 Subject: [PATCH 71/75] Add bsdconfig api function f_dialog_menutag2help() --- usr.sbin/bsdconfig/share/dialog.subr | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/usr.sbin/bsdconfig/share/dialog.subr b/usr.sbin/bsdconfig/share/dialog.subr index 13d209cfead0..c83c0c6ad487 100644 --- a/usr.sbin/bsdconfig/share/dialog.subr +++ b/usr.sbin/bsdconfig/share/dialog.subr @@ -2116,6 +2116,39 @@ f_dialog_menutag2index_with_help() return $FAILURE } +# f_dialog_menutag2help $tag_chosen $tag1 $item1 $help1 $tag2 $item2 $help2 ... +# +# To use the `--menu' option of dialog(1) with the `--item-help' option, you +# must pass an ordered list of tag/item/help triplets on the command-line. When +# the user selects a menu option the tag for that item is printed to stderr. +# +# This function allows you to dereference the tag chosen by the user back into +# the help associated with said tag (item is discarded/ignored). +# +# Pass the tag chosen by the user as the first argument, followed by the +# ordered list of tag/item/help triplets (HINT: use the same tag/item/help list +# as was passed to dialog(1) for consistency). +# +# If the tag cannot be found, NULL is returned. +# +f_dialog_menutag2help() +{ + local tag="$1" tagn help + shift 1 # tag + + while [ $# -gt 0 ]; do + tagn="$1" + help="$3" + shift 3 # tagn/item/help + + if [ "$tag" = "$tagn" ]; then + echo "$help" + return $SUCCESS + fi + done + return $FAILURE +} + ############################################################ INIT FUNCTIONS # f_dialog_init From 75855cb6c09a8ba100173ba7a124cfa5b83dce01 Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Tue, 10 Feb 2015 03:17:51 +0000 Subject: [PATCH 72/75] Add "vt_"* aliases to bsdconfig console entries. NB: "syscons_"* kept for backward compatibility --- usr.sbin/bsdconfig/console/INDEX | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/usr.sbin/bsdconfig/console/INDEX b/usr.sbin/bsdconfig/console/INDEX index 18763fdbfc14..b3bf975a518d 100644 --- a/usr.sbin/bsdconfig/console/INDEX +++ b/usr.sbin/bsdconfig/console/INDEX @@ -46,6 +46,13 @@ menu_help="Customize system console behavior" # can be i18n'ed but `command' is the name of a script. # menu_selection="console|console" +menu_selection="vt_font|font" +menu_selection="vt_keymap|keymap" +menu_selection="vt_repeat|repeat" +menu_selection="vt_saver|saver" +menu_selection="vt_screenmap|screenmap" +menu_selection="vt_ttys|ttys" +# For backward compatibility menu_selection="syscons_font|font" menu_selection="syscons_keymap|keymap" menu_selection="syscons_repeat|repeat" From 35994c42c3473d6b9b18d873aa442e4b54f5bb4f Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Tue, 10 Feb 2015 03:34:42 +0000 Subject: [PATCH 73/75] Update copyrights. --- usr.sbin/bsdconfig/console/INDEX | 2 +- usr.sbin/bsdconfig/includes/INDEX | 2 +- usr.sbin/bsdconfig/networking/share/device.subr | 2 +- usr.sbin/bsdconfig/share/dialog.subr | 2 +- usr.sbin/bsdconfig/share/keymap.subr | 2 +- usr.sbin/bsdconfig/usermgmt/share/user.subr | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/usr.sbin/bsdconfig/console/INDEX b/usr.sbin/bsdconfig/console/INDEX index b3bf975a518d..e298f340e63c 100644 --- a/usr.sbin/bsdconfig/console/INDEX +++ b/usr.sbin/bsdconfig/console/INDEX @@ -1,5 +1,5 @@ # Copyright (c) 2012 Ron McDowell -# Copyright (c) 2012 Devin Teske +# Copyright (c) 2012-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr.sbin/bsdconfig/includes/INDEX b/usr.sbin/bsdconfig/includes/INDEX index c32542de279e..a6a6c49212a4 100644 --- a/usr.sbin/bsdconfig/includes/INDEX +++ b/usr.sbin/bsdconfig/includes/INDEX @@ -1,4 +1,4 @@ -# Copyright (c) 2013 Devin Teske +# Copyright (c) 2013-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr.sbin/bsdconfig/networking/share/device.subr b/usr.sbin/bsdconfig/networking/share/device.subr index 6ee08ce8f5ac..14758e678ae9 100644 --- a/usr.sbin/bsdconfig/networking/share/device.subr +++ b/usr.sbin/bsdconfig/networking/share/device.subr @@ -1,6 +1,6 @@ if [ ! "$_NETWORKING_DEVICE_SUBR" ]; then _NETWORKING_DEVICE_SUBR=1 # -# Copyright (c) 2006-2013 Devin Teske +# Copyright (c) 2006-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr.sbin/bsdconfig/share/dialog.subr b/usr.sbin/bsdconfig/share/dialog.subr index c83c0c6ad487..d7c2d2c3dfba 100644 --- a/usr.sbin/bsdconfig/share/dialog.subr +++ b/usr.sbin/bsdconfig/share/dialog.subr @@ -1,6 +1,6 @@ if [ ! "$_DIALOG_SUBR" ]; then _DIALOG_SUBR=1 # -# Copyright (c) 2006-2014 Devin Teske +# Copyright (c) 2006-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr.sbin/bsdconfig/share/keymap.subr b/usr.sbin/bsdconfig/share/keymap.subr index 41f59cf7a3ef..7f2f87c91b38 100644 --- a/usr.sbin/bsdconfig/share/keymap.subr +++ b/usr.sbin/bsdconfig/share/keymap.subr @@ -1,6 +1,6 @@ if [ ! "$_KEYMAP_SUBR" ]; then _KEYMAP_SUBR=1 # -# Copyright (c) 2013 Devin Teske +# Copyright (c) 2013-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr.sbin/bsdconfig/usermgmt/share/user.subr b/usr.sbin/bsdconfig/usermgmt/share/user.subr index e6beb54a6065..d0e38878b348 100644 --- a/usr.sbin/bsdconfig/usermgmt/share/user.subr +++ b/usr.sbin/bsdconfig/usermgmt/share/user.subr @@ -1,7 +1,7 @@ if [ ! "$_USERMGMT_USER_SUBR" ]; then _USERMGMT_USER_SUBR=1 # # Copyright (c) 2012 Ron McDowell -# Copyright (c) 2012-2014 Devin Teske +# Copyright (c) 2012-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without From eb6368d4f8a065b52cfe6a13c780e940a09db0b7 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Tue, 10 Feb 2015 04:34:39 +0000 Subject: [PATCH 74/75] Sanitise the coredump file names sent to devd. While there, add a sysctl to turn this feature off as requested by kib@. --- sys/kern/kern_sig.c | 57 +++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index f25fc16fa6f3..655866d8cee2 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include "opt_core.h" #include +#include #include #include #include @@ -179,6 +180,10 @@ static int set_core_nodump_flag = 0; SYSCTL_INT(_kern, OID_AUTO, nodump_coredump, CTLFLAG_RW, &set_core_nodump_flag, 0, "Enable setting the NODUMP flag on coredump files"); +static int coredump_devctl = 1; +SYSCTL_INT(_kern, OID_AUTO, coredump_devctl, CTLFLAG_RW, &coredump_devctl, + 0, "Generate a devctl notification when processes coredump"); + /* * Signal properties and actions. * The array below categorizes the signals and their default actions @@ -3217,6 +3222,25 @@ corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td, return (0); } +static int +coredump_sanitise_path(const char *path) +{ + size_t len, i; + + /* + * Only send a subset of ASCII to devd(8) because it + * might pass these strings to sh -c. + */ + len = strlen(path); + for (i = 0; i < len; i++) + if (!(isalpha(path[i]) || isdigit(path[i])) && + path[i] != '/' && path[i] != '.' && + path[i] != '-') + return (0); + + return (1); +} + /* * Dump a process' core. The main routine does some * policy checking, and creates the name of the coredump; @@ -3238,9 +3262,9 @@ coredump(struct thread *td) void *rl_cookie; off_t limit; int compress; - char *data = NULL; - size_t len; + char data[MAXPATHLEN * 2 + 16]; /* space for devctl notification */ char *fullpath, *freepath = NULL; + size_t len; #ifdef COMPRESS_USER_CORES compress = compress_user_cores; @@ -3332,30 +3356,29 @@ coredump(struct thread *td) * Notify the userland helper that a process triggered a core dump. * This allows the helper to run an automated debugging session. */ - len = MAXPATHLEN * 2 + 5 /* comm= */ + 5 /* core= */ + 1; - data = malloc(len, M_TEMP, M_NOWAIT); - if (data == NULL) + if (coredump_devctl == 0) goto out; if (vn_fullpath_global(td, p->p_textvp, &fullpath, &freepath) != 0) goto out; - snprintf(data, len, "comm=%s", fullpath); - if (freepath != NULL) { - free(freepath, M_TEMP); - freepath = NULL; - } - if (vn_fullpath_global(td, vp, &fullpath, &freepath) != 0) + if (!coredump_sanitise_path(fullpath)) goto out; - snprintf(data, len, "%s core=%s", data, fullpath); + snprintf(data, sizeof(data), "comm=%s ", fullpath); + free(freepath, M_TEMP); + freepath = NULL; + if (vn_fullpath_global(td, vp, &fullpath, &freepath) != 0) { + printf("could not find coredump\n"); + goto out; + } + if (!coredump_sanitise_path(fullpath)) + goto out; + strlcat(data, "core=", sizeof(data)); + len = strlcat(data, fullpath, sizeof(data)); devctl_notify("kernel", "signal", "coredump", data); - free(name, M_TEMP); out: #ifdef AUDIT audit_proc_coredump(td, name, error); #endif - if (freepath != NULL) - free(freepath, M_TEMP); - if (data != NULL) - free(data, M_TEMP); + free(freepath, M_TEMP); free(name, M_TEMP); return (error); } From 29d0137a8d2b31771eee2172f4f73e7d4fe48373 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Tue, 10 Feb 2015 06:35:16 +0000 Subject: [PATCH 75/75] Remove FreeBSD/wii. This port failed to gain traction and probably only a couple Wii consoles ran FreeBSD all the way to single user mode with an md(4). IPC support was never implemented, so it was impossible to use any peripheral Any further development, if any, will happen at https://github.com/rpaulo/wii. Discussed with: nathanw (a long time ago), jhibbits --- sys/conf/files.powerpc | 6 - sys/conf/options.powerpc | 1 - sys/powerpc/aim/locore32.S | 4 +- sys/powerpc/aim/machdep.c | 35 +- sys/powerpc/aim/mmu_oea.c | 47 +- sys/powerpc/conf/NOTES | 1 - sys/powerpc/conf/WII | 110 ---- sys/powerpc/ofw/ofw_syscons.c | 12 +- sys/powerpc/wii/ios_if.m | 64 --- sys/powerpc/wii/locore.S | 131 ----- sys/powerpc/wii/platform_wii.c | 161 ------ sys/powerpc/wii/wii_bus.c | 340 ------------- sys/powerpc/wii/wii_exireg.h | 35 -- sys/powerpc/wii/wii_fb.c | 885 --------------------------------- sys/powerpc/wii/wii_fbreg.h | 40 -- sys/powerpc/wii/wii_fbvar.h | 857 ------------------------------- sys/powerpc/wii/wii_gpio.c | 353 ------------- sys/powerpc/wii/wii_gpioreg.h | 38 -- sys/powerpc/wii/wii_ipc.c | 102 ---- sys/powerpc/wii/wii_ipcreg.h | 102 ---- sys/powerpc/wii/wii_pic.c | 244 --------- sys/powerpc/wii/wii_picreg.h | 42 -- 22 files changed, 31 insertions(+), 3579 deletions(-) delete mode 100644 sys/powerpc/conf/WII delete mode 100644 sys/powerpc/wii/ios_if.m delete mode 100644 sys/powerpc/wii/locore.S delete mode 100644 sys/powerpc/wii/platform_wii.c delete mode 100644 sys/powerpc/wii/wii_bus.c delete mode 100644 sys/powerpc/wii/wii_exireg.h delete mode 100644 sys/powerpc/wii/wii_fb.c delete mode 100644 sys/powerpc/wii/wii_fbreg.h delete mode 100644 sys/powerpc/wii/wii_fbvar.h delete mode 100644 sys/powerpc/wii/wii_gpio.c delete mode 100644 sys/powerpc/wii/wii_gpioreg.h delete mode 100644 sys/powerpc/wii/wii_ipc.c delete mode 100644 sys/powerpc/wii/wii_ipcreg.h delete mode 100644 sys/powerpc/wii/wii_pic.c delete mode 100644 sys/powerpc/wii/wii_picreg.h diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index e20e5649f046..73d3979d0d7b 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -242,9 +242,3 @@ powerpc/psim/iobus.c optional psim powerpc/psim/ata_iobus.c optional ata psim powerpc/psim/openpic_iobus.c optional psim powerpc/psim/uart_iobus.c optional uart psim -powerpc/wii/platform_wii.c optional wii -powerpc/wii/wii_bus.c optional wii -powerpc/wii/wii_pic.c optional wii -powerpc/wii/wii_fb.c optional wii -powerpc/wii/wii_gpio.c optional wii wiigpio -powerpc/wii/wii_ipc.c optional wii diff --git a/sys/conf/options.powerpc b/sys/conf/options.powerpc index d1b8b40d3637..e3f024dd6a65 100644 --- a/sys/conf/options.powerpc +++ b/sys/conf/options.powerpc @@ -24,7 +24,6 @@ PS3 opt_platform.h MAMBO PSERIES PSIM -WII opt_platform.h SC_OFWFB opt_ofwfb.h diff --git a/sys/powerpc/aim/locore32.S b/sys/powerpc/aim/locore32.S index 6e462a05d33b..a2cb1028701a 100644 --- a/sys/powerpc/aim/locore32.S +++ b/sys/powerpc/aim/locore32.S @@ -118,9 +118,7 @@ __start: bdnz 1b sync isync -#ifdef WII -#include -#endif + /* Zero bss, in case we were started by something unhelpful */ li 0,0 lis 8,_edata@ha diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index 92a06d2131b7..5d7c784ed60b 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -260,9 +260,6 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) void *kmdp; char *env; register_t msr, scratch; -#ifdef WII - register_t vers; -#endif uint8_t *cache_check; int cacheline_warn; #ifndef __powerpc64__ @@ -281,16 +278,6 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) startkernel = __startkernel; endkernel = __endkernel; -#ifdef WII - /* - * The Wii loader doesn't pass us any environment so, mdp - * points to garbage at this point. The Wii CPU is a 750CL. - */ - vers = mfpvr(); - if ((vers & 0xfffff0e0) == (MPC750 << 16 | MPC750CL)) - mdp = NULL; -#endif - /* Check for ePAPR loader, which puts a magic value into r6 */ if (mdp == (void *)0x65504150) mdp = NULL; @@ -513,13 +500,13 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) */ trap_offset += (size_t)&restorebridgesize; - bcopy(&restorebridge, (void *)EXC_RST, trap_offset); - bcopy(&restorebridge, (void *)EXC_DSI, trap_offset); - bcopy(&restorebridge, (void *)EXC_ALI, trap_offset); - bcopy(&restorebridge, (void *)EXC_PGM, trap_offset); - bcopy(&restorebridge, (void *)EXC_MCHK, trap_offset); - bcopy(&restorebridge, (void *)EXC_TRC, trap_offset); - bcopy(&restorebridge, (void *)EXC_BPT, trap_offset); + bcopy(&restorebridge, (void *)EXC_RST, trap_offset); + bcopy(&restorebridge, (void *)EXC_DSI, trap_offset); + bcopy(&restorebridge, (void *)EXC_ALI, trap_offset); + bcopy(&restorebridge, (void *)EXC_PGM, trap_offset); + bcopy(&restorebridge, (void *)EXC_MCHK, trap_offset); + bcopy(&restorebridge, (void *)EXC_TRC, trap_offset); + bcopy(&restorebridge, (void *)EXC_BPT, trap_offset); } #endif @@ -560,7 +547,7 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) * Restore MSR */ mtmsr(msr); - + /* Warn if cachline size was not determined */ if (cacheline_warn == 1) { printf("WARNING: cacheline size undetermined, setting to 32\n"); @@ -569,7 +556,7 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) /* * Choose a platform module so we can get the physical memory map. */ - + platform_probe_and_attach(); /* @@ -698,7 +685,7 @@ int ptrace_single_step(struct thread *td) { struct trapframe *tf; - + tf = td->td_frame; tf->srr1 |= PSL_SE; @@ -789,7 +776,7 @@ db_trap_glue(struct trapframe *frame) int type = frame->exc; /* Ignore DTrace traps. */ - if (*(uint32_t *)frame->srr0 == EXC_DTRACE) + if (*(uint32_t *)frame->srr0 == EXC_DTRACE) return (0); if (type == EXC_PGM && (frame->srr1 & 0x20000)) { type = T_BREAKPOINT; diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 96628f71ae5b..12d108b8953d 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -420,7 +420,7 @@ static void tlbia(void) { vm_offset_t va; - + for (va = 0; va < 0x00040000; va += 0x00001000) { __asm __volatile("tlbie %0" :: "r"(va)); powerpc_sync(); @@ -623,17 +623,8 @@ moea_cpu_bootstrap(mmu_t mmup, int ap) isync(); } -#ifdef WII - /* - * Special case for the Wii: don't install the PCI BAT. - */ - if (strcmp(installed_platform(), "wii") != 0) { -#endif - __asm __volatile("mtdbatu 1,%0" :: "r"(battable[8].batu)); - __asm __volatile("mtdbatl 1,%0" :: "r"(battable[8].batl)); -#ifdef WII - } -#endif + __asm __volatile("mtdbatu 1,%0" :: "r"(battable[8].batu)); + __asm __volatile("mtdbatl 1,%0" :: "r"(battable[8].batl)); isync(); __asm __volatile("mtibatu 1,%0" :: "r"(0)); @@ -706,15 +697,9 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) :: "r"(battable[0].batu), "r"(battable[0].batl)); mtmsr(msr); -#ifdef WII - if (strcmp(installed_platform(), "wii") != 0) { -#endif - /* map pci space */ - __asm __volatile("mtdbatu 1,%0" :: "r"(battable[8].batu)); - __asm __volatile("mtdbatl 1,%0" :: "r"(battable[8].batl)); -#ifdef WII - } -#endif + /* map pci space */ + __asm __volatile("mtdbatu 1,%0" :: "r"(battable[8].batu)); + __asm __volatile("mtdbatl 1,%0" :: "r"(battable[8].batl)); isync(); /* set global direct map flag */ @@ -885,7 +870,7 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) */ chosen = OF_finddevice("/chosen"); if (chosen != -1 && OF_getprop(chosen, "mmu", &mmui, 4) != -1 && - (mmu = OF_instance_to_package(mmui)) != -1 && + (mmu = OF_instance_to_package(mmui)) != -1 && (sz = OF_getproplen(mmu, "translations")) != -1) { translations = NULL; for (i = 0; phys_avail[i] != 0; i += 2) { @@ -917,7 +902,7 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) /* Enter the pages */ for (off = 0; off < translations[i].om_len; off += PAGE_SIZE) - moea_kenter(mmup, translations[i].om_va + off, + moea_kenter(mmup, translations[i].om_va + off, translations[i].om_pa + off); } } @@ -1488,7 +1473,7 @@ void moea_kenter_attr(mmu_t mmu, vm_offset_t va, vm_offset_t pa, vm_memattr_t ma) { u_int pte_lo; - int error; + int error; #if 0 if (va < VM_MIN_KERNEL_ADDRESS) @@ -1637,7 +1622,7 @@ moea_pinit(mmu_t mmu, pmap_t pmap) == NULL) { pmap->pmap_phys = pmap; } - + mtx_lock(&moea_vsid_mutex); /* @@ -1782,7 +1767,7 @@ void moea_release(mmu_t mmu, pmap_t pmap) { int idx, mask; - + /* * Free segment register's VSID */ @@ -1957,7 +1942,7 @@ moea_pvo_enter(pmap_t pm, uma_zone_t zone, struct pvo_head *pvo_head, } else { if (moea_bpvo_pool_index >= BPVO_POOL_SIZE) { panic("moea_enter: bpvo pool exhausted, %d, %d, %d", - moea_bpvo_pool_index, BPVO_POOL_SIZE, + moea_bpvo_pool_index, BPVO_POOL_SIZE, BPVO_POOL_SIZE * sizeof(struct pvo_entry)); } pvo = &moea_bpvo_pool[moea_bpvo_pool_index]; @@ -2307,7 +2292,7 @@ moea_pte_spillable_ident(u_int ptegidx) if (!(pt->pte_lo & PTE_REF)) return (pvo_walk); } - + return (pvo); } @@ -2504,7 +2489,7 @@ moea_bat_mapped(int idx, vm_offset_t pa, vm_size_t size) */ prot = battable[idx].batl & (BAT_I|BAT_G|BAT_PP_RW); if (prot != (BAT_I|BAT_G|BAT_PP_RW)) - return (EPERM); + return (EPERM); /* * The address should be within the BAT range. Assume that the @@ -2527,7 +2512,7 @@ moea_dev_direct_mapped(mmu_t mmu, vm_paddr_t pa, vm_size_t size) int i; /* - * This currently does not work for entries that + * This currently does not work for entries that * overlap 256M BAT segments. */ @@ -2560,7 +2545,7 @@ moea_mapdev_attr(mmu_t mmu, vm_offset_t pa, vm_size_t size, vm_memattr_t ma) ppa = trunc_page(pa); offset = pa & PAGE_MASK; size = roundup(offset + size, PAGE_SIZE); - + /* * If the physical address lies within a valid BAT table entry, * return the 1:1 mapping. This currently doesn't work diff --git a/sys/powerpc/conf/NOTES b/sys/powerpc/conf/NOTES index ebfd299c484b..974c91ba00cd 100644 --- a/sys/powerpc/conf/NOTES +++ b/sys/powerpc/conf/NOTES @@ -24,7 +24,6 @@ options POWERMAC #NewWorld Apple PowerMacs #options PS3 #Sony Playstation 3 options PSIM #GDB PSIM ppc simulator options MAMBO #IBM Mambo Full System Simulator -#options WII #Nintendo Wii options SC_OFWFB # OFW frame buffer diff --git a/sys/powerpc/conf/WII b/sys/powerpc/conf/WII deleted file mode 100644 index ebfaffc74300..000000000000 --- a/sys/powerpc/conf/WII +++ /dev/null @@ -1,110 +0,0 @@ -# -# Custom kernel for the Nintendo Wii. -# -# $FreeBSD$ - -cpu AIM -ident WII -machine powerpc powerpc - -makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols - -options WII - -options SCHED_ULE #ULE scheduler -options PREEMPTION #Enable kernel thread preemption -options INET #InterNETworking -options INET6 #IPv6 communications protocols -options SCTP #Stream Control Transmission Protocol -options FFS #Berkeley Fast Filesystem -options SOFTUPDATES #Enable FFS soft updates support -options UFS_ACL #Support for access control lists -options UFS_DIRHASH #Improve performance on big directories -options UFS_GJOURNAL #Enable gjournal-based UFS journaling -options MD_ROOT #MD is a potential root device -options NFSCL #Network Filesystem Client -options NFSD #Network Filesystem Server -options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as root device -options MSDOSFS #MSDOS Filesystem -options CD9660 #ISO 9660 Filesystem -options PROCFS #Process filesystem (requires PSEUDOFS) -options PSEUDOFS #Pseudo-filesystem framework -options GEOM_PART_GPT #GUID Partition Tables. -options GEOM_LABEL #Provides labelization -options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI -options KTRACE #ktrace(1) syscall trace support -options STACK #stack(9) support -options SYSVSHM #SYSV-style shared memory -options SYSVMSG #SYSV-style message queues -options SYSVSEM #SYSV-style semaphores -options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions -#options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) -options AUDIT # Security event auditing -options CAPABILITY_MODE # Capsicum capability mode -options CAPABILITIES # Capsicum capabilities -options MAC # TrustedBSD MAC Framework -options INCLUDE_CONFIG_FILE # Include this file in kernel - -# Debugging support. Always need this: -options KDB # Enable kernel debugger support. -# For minimum debugger support (stable branch) use: -options KDB_TRACE # Print a stack trace for a panic. -# For full debugger support use this instead: -options DDB #Support DDB -#options DEADLKRES #Enable the deadlock resolver -options INVARIANTS #Enable calls of extra sanity checking -options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS -options WITNESS #Enable checks to detect deadlocks and cycles -options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed -options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones - -# ATA/SCSI peripherals -device scbus # SCSI bus (required for ATA/SCSI) -device da # Direct Access (disks) - -# syscons is the default console driver, resembling an SCO console -device sc -device kbdmux -options SC_DFLT_FONT # compile font in -makeoptions SC_DFLT_FONT=cp437 - -# Pseudo devices. -device loop # Network loopback -device random # Entropy device -device ether # Ethernet support -device vlan # 802.1Q VLAN support -device tun # Packet tunnel. -device md # Memory "disks" -device gif # IPv6 and IPv4 tunneling -device firmware # firmware assist module - - -# The `bpf' device enables the Berkeley Packet Filter. -# Be aware of the administrative consequences of enabling this! -# Note that 'bpf' is required for DHCP. -device bpf #Berkeley packet filter - -# USB support -options USB_DEBUG # enable debug msgs -device uhci # UHCI PCI->USB interface -device ohci # OHCI PCI->USB interface -device ehci # EHCI PCI->USB interface -device usb # USB Bus (required) -device uhid # "Human Interface Devices" -device ukbd # Keyboard -options KBD_INSTALL_CDEV # install a CDEV entry in /dev -device ulpt # Printer -device umass # Disks/Mass storage - Requires scbus and da0 -device ums # Mouse -# USB Ethernet -device miibus # MII bus support -device aue # ADMtek USB Ethernet -device axe # ASIX Electronics USB Ethernet -device cdce # Generic USB over Ethernet -device cue # CATC USB Ethernet -device kue # Kawasaki LSI USB Ethernet - -# GPIO -device gpio -device wiigpio diff --git a/sys/powerpc/ofw/ofw_syscons.c b/sys/powerpc/ofw/ofw_syscons.c index a8797c2c16e7..7dc51f9888c8 100644 --- a/sys/powerpc/ofw/ofw_syscons.c +++ b/sys/powerpc/ofw/ofw_syscons.c @@ -412,7 +412,7 @@ ofwfb_init(int unit, video_adapter_t *adp, int flags) adp->va_window = (vm_offset_t) ofwfb_static_window; /* - * Enable future font-loading and flag color support, as well as + * Enable future font-loading and flag color support, as well as * adding V_ADP_MODECHANGE so that we ofwfb_set_mode() gets called * when the X server shuts down. This enables us to get the console * back when X disappears. @@ -874,7 +874,7 @@ ofwfb_putc32(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) addr = (uint32_t *)sc->sc_addr + (row + sc->sc_ymargin)*(sc->sc_stride/4) + col + sc->sc_xmargin; - + fg = ofwfb_pix32(sc, ofwfb_foreground(a)); bg = ofwfb_pix32(sc, ofwfb_background(a)); @@ -999,12 +999,6 @@ ofwfb_scidentify(driver_t *driver, device_t parent) { device_t child; - /* - * The Nintendo Wii doesn't have open firmware, so don't probe ofwfb - * because otherwise we will crash. - */ - if (strcmp(installed_platform(), "wii") == 0) - return; /* * Add with a priority guaranteed to make it last on * the device list @@ -1019,7 +1013,7 @@ ofwfb_scprobe(device_t dev) device_set_desc(dev, "System console"); - error = sc_probe_unit(device_get_unit(dev), + error = sc_probe_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD); if (error != 0) return (error); diff --git a/sys/powerpc/wii/ios_if.m b/sys/powerpc/wii/ios_if.m deleted file mode 100644 index f5c6a17b9ab1..000000000000 --- a/sys/powerpc/wii/ios_if.m +++ /dev/null @@ -1,64 +0,0 @@ -#- -# Copyright (c) 2013 Rui Paulo -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# $FreeBSD$ -# - -#include -#include - -INTERFACE ios; - -METHOD int open { - device_t dev; - const char *path; - int mode; -}; - -METHOD int close { - device_t dev; - int fd; -}; - -METHOD int ioctl { - device_t dev; - int fd; - unsigned int request; - void *ibuf; - size_t ilen; - void *obuf; - size_t olen; -}; - -METHOD int ioctlv { - device_t dev; - int fd; - unsigned int request; - struct iovec *in; - size_t ilen; - struct iovec *out; - size_t olen; -}; - diff --git a/sys/powerpc/wii/locore.S b/sys/powerpc/wii/locore.S deleted file mode 100644 index 7254bec4a7ea..000000000000 --- a/sys/powerpc/wii/locore.S +++ /dev/null @@ -1,131 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -/* - * When we are invoked from Wii loaders, the state of the MMU and the BAT - * mappings can vary. In this file we try to reset the MMU to a state - * that lets us boot FreeBSD. - * - * N.B.: keep the BAT0 in sync with mmu_oea.c and never touch BAT1 later. - * - * This file is being included from aim/locore32.S. - */ - -#define MMU_REALMODE() \ - mfmsr %r12; \ - rlwinm %r12, %r12, 0, ~(PSL_DR|PSL_IR);\ - sync; \ - bl 1f; \ -1: \ - mflr %r11; \ - clrlwi %r11, %r11, 3; /* XXX why? */ \ - addi %r11, %r11, 2f - 1b; \ - mtsrr0 %r11; \ - mtsrr1 %r12; /* Disables the MMU */ \ - isync; \ - rfi; \ -2: - -#define MMU_VIRTUALMODE() \ - bl 3f; \ -3: \ - mflr %r11; \ - addi %r11, %r11, 4f - 3b; \ - mfmsr %r12; \ - ori %r12, %r12, PSL_DR|PSL_IR; \ - mtsrr0 %r11; \ - mtsrr1 %r12; /* Enables the MMU */ \ - isync; \ - rfi; \ -4: - - MMU_REALMODE() - - /* Reset standard BATs */ - li %r11, 0 - mtibatu 0, %r11 - mtibatl 0, %r11 - mtdbatu 0, %r11 - mtdbatl 0, %r11 - mtibatu 1, %r11 - mtibatl 1, %r11 - mtdbatu 1, %r11 - mtdbatl 1, %r11 - mtibatu 2, %r11 - mtibatl 2, %r11 - mtdbatu 2, %r11 - mtdbatl 2, %r11 - mtibatu 3, %r11 - mtibatl 3, %r11 - mtdbatu 3, %r11 - mtdbatl 3, %r11 - - /* Reset high BATs. IBAT[4-7][UL] + DBAT[4-7][UL] */ - mtspr 560, %r11 - mtspr 561, %r11 - mtspr 562, %r11 - mtspr 563, %r11 - mtspr 564, %r11 - mtspr 565, %r11 - mtspr 566, %r11 - mtspr 567, %r11 - mtspr 568, %r11 - mtspr 569, %r11 - mtspr 570, %r11 - mtspr 571, %r11 - mtspr 572, %r11 - mtspr 573, %r11 - mtspr 574, %r11 - mtspr 575, %r11 - - /* - * We need to setup BAT0 as in mmu_oea.c. - */ - li %r11, BATU(0x00000000, BAT_BL_256M, BAT_Vs) - li %r12, BATL(0x00000000, BAT_M, BAT_PP_RW) - mtdbatu 0, %r11 - mtdbatl 0, %r12 - mtibatu 0, %r11 - mtibatl 0, %r12 - isync - - /* - * We use BAT1 to be able to write I/O memory, including the - * framebuffer registers. - */ - /* BATU(0x0c000000, BAT_BL_32M, BAT_Vs) */ - lis %r11, 0x0c00 - ori %r11, %r11, BAT_BL_32M|BAT_Vs - /* BATL(0x0c000000, BAT_I|BAT_G, BAT_PP_RW) */ - lis %r12, 0x0c00 - ori %r12, %r12, BAT_I|BAT_G|BAT_PP_RW - mtdbatu 1, %r11 - mtdbatl 1, %r12 - isync - - MMU_VIRTUALMODE() diff --git a/sys/powerpc/wii/platform_wii.c b/sys/powerpc/wii/platform_wii.c deleted file mode 100644 index c5709f4c8a5f..000000000000 --- a/sys/powerpc/wii/platform_wii.c +++ /dev/null @@ -1,161 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "platform_if.h" - -static int wii_probe(platform_t); -static int wii_attach(platform_t); -static void wii_mem_regions(platform_t, struct mem_region *, - int *, struct mem_region *, int *); -static unsigned long wii_timebase_freq(platform_t, struct cpuref *); -static void wii_reset(platform_t); -static void wii_cpu_idle(sbintime_t); - -extern void wiibus_reset_system(void); - -static platform_method_t wii_methods[] = { - PLATFORMMETHOD(platform_probe, wii_probe), - PLATFORMMETHOD(platform_attach, wii_attach), - PLATFORMMETHOD(platform_mem_regions, wii_mem_regions), - PLATFORMMETHOD(platform_timebase_freq, wii_timebase_freq), - PLATFORMMETHOD(platform_reset, wii_reset), - - PLATFORMMETHOD_END -}; - -static platform_def_t wii_platform = { - "wii", - wii_methods, - 0 -}; - -PLATFORM_DEF(wii_platform); - -static int -wii_probe(platform_t plat) -{ - register_t vers = mfpvr(); - - /* - * The Wii includes a PowerPC 750CL with custom modifications - * ("Broadway"). - * For now, we just assume that if we are running on a - * PowerPC 750CL, then this platform is a Nintendo Wii. - */ - if ((vers & 0xfffff0e0) == (MPC750 << 16 | MPC750CL)) - return (BUS_PROBE_SPECIFIC); - - return (ENXIO); -} - -static int -wii_attach(platform_t plat) -{ - cpu_idle_hook = wii_cpu_idle; - - return (0); -} - -static void -wii_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, - struct mem_region *avail_regions, int *availsz) -{ - /* 24MB 1T-SRAM */ - avail_regions[0].mr_start = 0x00000000; - avail_regions[0].mr_size = 0x01800000; - - /* - * Reserve space for the framebuffer which is located - * at the end of this 24MB memory region. See wii_fbreg.h. - */ - avail_regions[0].mr_size -= WIIFB_FB_LEN; - - /* 64MB GDDR3 SDRAM */ - avail_regions[1].mr_start = 0x10000000; - avail_regions[1].mr_size = 0x04000000; - - /* - * Reserve space for the DSP. - */ - avail_regions[1].mr_start += 0x4000; - avail_regions[1].mr_size -= 0x4000; - - /* - * Reserve space for the IOS I/O memory. - */ - avail_regions[1].mr_size -= WIIIPC_IOH_LEN + 1; - - memcpy(phys, avail_regions, 2*sizeof(*avail_regions)); - *physsz = *availsz = 2; -} - -static u_long -wii_timebase_freq(platform_t plat, struct cpuref *cpuref) -{ - - /* Bus Frequency (243MHz) / 4 */ - return (60750000); -} - -static void -wii_reset(platform_t plat __unused) -{ - - wiibus_reset_system(); -} - -static void -wii_cpu_idle(sbintime_t sbt) -{ -} diff --git a/sys/powerpc/wii/wii_bus.c b/sys/powerpc/wii/wii_bus.c deleted file mode 100644 index e836529176c5..000000000000 --- a/sys/powerpc/wii/wii_bus.c +++ /dev/null @@ -1,340 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define WIIBUS_CSR_ADDR 0x0d800100 -#define WIIBUS_CSR_LEN 0x300 -#define WIIBUS_CSR_RESET 0x94 - -struct wiibus_softc { - device_t sc_dev; - struct rman sc_rman; - bus_space_tag_t sc_tag; - bus_space_handle_t sc_handle; -}; - -static struct wiibus_softc *wiibus_sc = NULL; - -static uint32_t wiibus_csr_read(struct wiibus_softc *, uint16_t); -static void wiibus_csr_write(struct wiibus_softc *, uint16_t, uint32_t); -static void wiibus_identify(driver_t *, device_t); -static int wiibus_probe(device_t); -static int wiibus_attach(device_t); -static int wiibus_print_child(device_t, device_t); -static struct resource * - wiibus_alloc_resource(device_t, device_t, int, int *, - unsigned long, unsigned long, unsigned long, - unsigned int); -static int wiibus_activate_resource(device_t, device_t, int, int, - struct resource *); - void wiibus_reset_system(void); - -static device_method_t wiibus_methods[] = { - /* Device interface */ - DEVMETHOD(device_identify, wiibus_identify), - DEVMETHOD(device_probe, wiibus_probe), - DEVMETHOD(device_attach, wiibus_attach), - - /* Bus interface */ - DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_print_child, wiibus_print_child), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - DEVMETHOD(bus_alloc_resource, wiibus_alloc_resource), - DEVMETHOD(bus_activate_resource,wiibus_activate_resource), - - DEVMETHOD_END -}; - -static MALLOC_DEFINE(M_WIIBUS, "wiibus", "Nintendo Wii system bus"); - -struct wiibus_devinfo { - struct resource_list di_resources; - uint8_t di_init; -}; - -static driver_t wiibus_driver = { - "wiibus", - wiibus_methods, - sizeof(struct wiibus_softc) -}; - -static devclass_t wiibus_devclass; - -DRIVER_MODULE(wiibus, nexus, wiibus_driver, wiibus_devclass, 0, 0); - -static uint32_t -wiibus_csr_read(struct wiibus_softc *sc, uint16_t reg) -{ - - return (bus_space_read_4(sc->sc_tag, sc->sc_handle, reg)); -} - -static void -wiibus_csr_write(struct wiibus_softc *sc, uint16_t reg, - uint32_t val) -{ - - bus_space_write_4(sc->sc_tag, sc->sc_handle, reg, val); -} - -static void -wiibus_identify(driver_t *driver, device_t parent) -{ - - if (strcmp(installed_platform(), "wii") != 0) - return; - - if (device_find_child(parent, "wiibus", -1) == NULL) - BUS_ADD_CHILD(parent, 0, "wiibus", 0); -} - - -static int -wiibus_probe(device_t dev) -{ - - device_set_desc(dev, "Nintendo Wii System Bus"); - - return (BUS_PROBE_NOWILDCARD); -} - -static void -wiibus_init_device_resources(struct rman *rm, struct wiibus_devinfo *dinfo, - unsigned int rid, uintptr_t addr, size_t len, unsigned int irq) - -{ - - if (!dinfo->di_init) { - resource_list_init(&dinfo->di_resources); - dinfo->di_init++; - } - if (addr) { - rman_manage_region(rm, addr, addr + len - 1); - resource_list_add(&dinfo->di_resources, SYS_RES_MEMORY, rid, - addr, addr + len, len); - } - if (irq) - resource_list_add(&dinfo->di_resources, SYS_RES_IRQ, rid, - irq, irq, 1); -} - -static int -wiibus_attach(device_t self) -{ - struct wiibus_softc *sc; - struct wiibus_devinfo *dinfo; - device_t cdev; - - sc = device_get_softc(self); - sc->sc_rman.rm_type = RMAN_ARRAY; - sc->sc_rman.rm_descr = "Wii Bus Memory Mapped I/O"; - rman_init(&sc->sc_rman); - KASSERT(wiibus_sc == NULL, ("wiibus_sc already initialised")); - wiibus_sc = sc; - - /* Nintendo PIC */ - dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); - wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIPIC_REG_ADDR, - WIIPIC_REG_LEN, 1); - cdev = BUS_ADD_CHILD(self, 0, "wiipic", 0); - device_set_ivars(cdev, dinfo); - - /* Framebuffer */ - dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); - wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIFB_REG_ADDR, - WIIFB_REG_LEN, 8); - wiibus_init_device_resources(&sc->sc_rman, dinfo, 1, WIIFB_FB_ADDR, - WIIFB_FB_LEN, 0); - cdev = BUS_ADD_CHILD(self, 0, "wiifb", 0); - device_set_ivars(cdev, dinfo); - - /* External Interface Bus */ - dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); - wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIEXI_REG_ADDR, - WIIEXI_REG_LEN, 4); - cdev = BUS_ADD_CHILD(self, 0, "wiiexi", 0); - device_set_ivars(cdev, dinfo); - - /* Nintendo IOS IPC */ - dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); - wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIIPC_REG_ADDR, - WIIIPC_REG_LEN, 14); - wiibus_init_device_resources(&sc->sc_rman, dinfo, 1, WIIIPC_IOH_ADDR, - WIIIPC_IOH_LEN, 0); - cdev = BUS_ADD_CHILD(self, 0, "wiiipc", 0); - device_set_ivars(cdev, dinfo); - - /* GPIO */ - dinfo = malloc(sizeof(*dinfo), M_WIIBUS, M_WAITOK | M_ZERO); - wiibus_init_device_resources(&sc->sc_rman, dinfo, 0, WIIGPIO_REG_ADDR, - WIIGPIO_REG_LEN, 0); - cdev = BUS_ADD_CHILD(self, 0, "wiigpio", 0); - device_set_ivars(cdev, dinfo); - - /* The control registers */ - sc->sc_tag = &bs_be_tag; - sc->sc_handle = (bus_space_handle_t)pmap_mapdev(WIIBUS_CSR_ADDR, - WIIBUS_CSR_LEN); - - return (bus_generic_attach(self)); -} - -static int -wiibus_print_child(device_t dev, device_t child) -{ - struct wiibus_devinfo *dinfo = device_get_ivars(child); - int retval = 0; - - retval += bus_print_child_header(dev, child); - retval += resource_list_print_type(&dinfo->di_resources, "mem", - SYS_RES_MEMORY, "%#lx"); - retval += resource_list_print_type(&dinfo->di_resources, "irq", - SYS_RES_IRQ, "%ld"); - retval += bus_print_child_footer(dev, child); - - return (retval); -} - -static struct resource * -wiibus_alloc_resource(device_t bus, device_t child, int type, - int *rid, unsigned long start, unsigned long end, - unsigned long count, unsigned int flags) -{ - struct wiibus_softc *sc; - struct wiibus_devinfo *dinfo; - struct resource_list_entry *rle; - struct resource *rv; - int needactivate; - - sc = device_get_softc(bus); - dinfo = device_get_ivars(child); - needactivate = flags & RF_ACTIVE; - flags &= ~RF_ACTIVE; - - switch (type) { - case SYS_RES_MEMORY: - rle = resource_list_find(&dinfo->di_resources, SYS_RES_MEMORY, - *rid); - if (rle == NULL) { - device_printf(bus, "no res entry for %s memory 0x%x\n", - device_get_nameunit(child), *rid); - return (NULL); - } - rv = rman_reserve_resource(&sc->sc_rman, rle->start, rle->end, - rle->count, flags, child); - if (rv == NULL) { - device_printf(bus, - "failed to reserve resource for %s\n", - device_get_nameunit(child)); - return (NULL); - } - rman_set_rid(rv, *rid); - break; - case SYS_RES_IRQ: - return (resource_list_alloc(&dinfo->di_resources, bus, child, - type, rid, start, end, count, flags)); - default: - device_printf(bus, "unknown resource request from %s\n", - device_get_nameunit(child)); - return (NULL); - } - - if (needactivate) { - if (bus_activate_resource(child, type, *rid, rv) != 0) { - device_printf(bus, - "failed to activate resource for %s\n", - device_get_nameunit(child)); - return (NULL); - } - } - - return (rv); -} - -static int -wiibus_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *res) -{ - void *p; - - switch (type) { - case SYS_RES_MEMORY: - p = pmap_mapdev(rman_get_start(res), rman_get_size(res)); - if (p == NULL) - return (ENOMEM); - rman_set_virtual(res, p); - rman_set_bustag(res, &bs_be_tag); - rman_set_bushandle(res, (unsigned long)p); - break; - case SYS_RES_IRQ: - return (bus_activate_resource(bus, type, rid, res)); - default: - device_printf(bus, - "unknown activate resource request from %s\n", - device_get_nameunit(child)); - return (ENXIO); - } - - return (rman_activate_resource(res)); -} - -void -wiibus_reset_system(void) -{ - uint32_t r; - - r = wiibus_csr_read(wiibus_sc, WIIBUS_CSR_RESET); - r &= ~1; - wiibus_csr_write(wiibus_sc, WIIBUS_CSR_RESET, r); -} diff --git a/sys/powerpc/wii/wii_exireg.h b/sys/powerpc/wii/wii_exireg.h deleted file mode 100644 index 34a6bf61a883..000000000000 --- a/sys/powerpc/wii/wii_exireg.h +++ /dev/null @@ -1,35 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _POWERPC_WII_WII_EXIREG_H -#define _POWERPC_WII_WII_EXIREG_H - -#define WIIEXI_REG_ADDR 0x0d006800 -#define WIIEXI_REG_LEN 0x40 - -#endif /* _POWERPC_WII_WII_IPCREG_H */ diff --git a/sys/powerpc/wii/wii_fb.c b/sys/powerpc/wii/wii_fb.c deleted file mode 100644 index c32ab769eff6..000000000000 --- a/sys/powerpc/wii/wii_fb.c +++ /dev/null @@ -1,885 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * Copyright (c) 2003 Peter Grehan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include - -/* - * Driver for the Nintendo Wii's framebuffer. Based on Linux's gcnfb.c. - */ - -/* - * Syscons glue. - */ -static int wiifb_scprobe(device_t); -static int wiifb_scattach(device_t); - -static device_method_t wiifb_sc_methods[] = { - DEVMETHOD(device_probe, wiifb_scprobe), - DEVMETHOD(device_attach, wiifb_scattach), - - DEVMETHOD_END -}; - -static driver_t wiifb_sc_driver = { - "wiifb", - wiifb_sc_methods, - sizeof(sc_softc_t), -}; - -static devclass_t sc_devclass; - -DRIVER_MODULE(sc, wiibus, wiifb_sc_driver, sc_devclass, 0, 0); - -static int -wiifb_scprobe(device_t dev) -{ - int error; - - device_set_desc(dev, "Nintendo Wii frambuffer"); - - error = sc_probe_unit(device_get_unit(dev), - device_get_flags(dev) | SC_AUTODETECT_KBD); - if (error != 0) - return (error); - - /* This is a fake device, so make sure we added it ourselves */ - return (BUS_PROBE_NOWILDCARD); -} - -static int -wiifb_scattach(device_t dev) -{ - - return (sc_attach_unit(device_get_unit(dev), - device_get_flags(dev) | SC_AUTODETECT_KBD)); -} - -/* - * Video driver routines and glue. - */ -static void wiifb_reset_video(struct wiifb_softc *); -static void wiifb_enable_interrupts(struct wiifb_softc *); -static void wiifb_configure_tv_mode(struct wiifb_softc *); -static void wiifb_setup_framebuffer(struct wiifb_softc *); -static int wiifb_configure(int); -static vi_probe_t wiifb_probe; -static vi_init_t wiifb_init; -static vi_get_info_t wiifb_get_info; -static vi_query_mode_t wiifb_query_mode; -static vi_set_mode_t wiifb_set_mode; -static vi_save_font_t wiifb_save_font; -static vi_load_font_t wiifb_load_font; -static vi_show_font_t wiifb_show_font; -static vi_save_palette_t wiifb_save_palette; -static vi_load_palette_t wiifb_load_palette; -static vi_set_border_t wiifb_set_border; -static vi_save_state_t wiifb_save_state; -static vi_load_state_t wiifb_load_state; -static vi_set_win_org_t wiifb_set_win_org; -static vi_read_hw_cursor_t wiifb_read_hw_cursor; -static vi_set_hw_cursor_t wiifb_set_hw_cursor; -static vi_set_hw_cursor_shape_t wiifb_set_hw_cursor_shape; -static vi_blank_display_t wiifb_blank_display; -static vi_mmap_t wiifb_mmap; -static vi_ioctl_t wiifb_ioctl; -static vi_clear_t wiifb_clear; -static vi_fill_rect_t wiifb_fill_rect; -static vi_bitblt_t wiifb_bitblt; -static vi_diag_t wiifb_diag; -static vi_save_cursor_palette_t wiifb_save_cursor_palette; -static vi_load_cursor_palette_t wiifb_load_cursor_palette; -static vi_copy_t wiifb_copy; -static vi_putp_t wiifb_putp; -static vi_putc_t wiifb_putc; -static vi_puts_t wiifb_puts; -static vi_putm_t wiifb_putm; - -static video_switch_t wiifbvidsw = { - .probe = wiifb_probe, - .init = wiifb_init, - .get_info = wiifb_get_info, - .query_mode = wiifb_query_mode, - .set_mode = wiifb_set_mode, - .save_font = wiifb_save_font, - .load_font = wiifb_load_font, - .show_font = wiifb_show_font, - .save_palette = wiifb_save_palette, - .load_palette = wiifb_load_palette, - .set_border = wiifb_set_border, - .save_state = wiifb_save_state, - .load_state = wiifb_load_state, - .set_win_org = wiifb_set_win_org, - .read_hw_cursor = wiifb_read_hw_cursor, - .set_hw_cursor = wiifb_set_hw_cursor, - .set_hw_cursor_shape = wiifb_set_hw_cursor_shape, - .blank_display = wiifb_blank_display, - .mmap = wiifb_mmap, - .ioctl = wiifb_ioctl, - .clear = wiifb_clear, - .fill_rect = wiifb_fill_rect, - .bitblt = wiifb_bitblt, - .diag = wiifb_diag, - .save_cursor_palette = wiifb_save_cursor_palette, - .load_cursor_palette = wiifb_load_cursor_palette, - .copy = wiifb_copy, - .putp = wiifb_putp, - .putc = wiifb_putc, - .puts = wiifb_puts, - .putm = wiifb_putm, -}; - -VIDEO_DRIVER(wiifb, wiifbvidsw, wiifb_configure); - -extern sc_rndr_sw_t txtrndrsw; -RENDERER(wiifb, 0, txtrndrsw, gfb_set); -RENDERER_MODULE(wiifb, gfb_set); - -static struct wiifb_softc wiifb_softc; -static uint16_t wiifb_static_window[ROW*COL]; -extern u_char dflt_font_8[]; - -/* - * Map the syscons colors to YUY2 (Y'UV422). - * Some colours are an approximation. - * - * The Wii has a 16 bit pixel, so each 32 bit DWORD encodes - * two pixels. The upper 16 bits is for pixel 0 (left hand pixel - * in a pair), the lower 16 bits is for pixel 1. - * - * For now, we're going to ignore that entirely and just use the - * lower 16 bits for each pixel. We'll take the upper value into - * account later. - */ -static uint32_t wiifb_cmap[16] = { - 0x00800080, /* Black */ - 0x1dff1d6b, /* Blue */ - 0x4b554b4a, /* Green */ - 0x80808080, /* Cyan */ - 0x4c544cff, /* Red */ - 0x3aaa34b5, /* Magenta */ - 0x7140718a, /* Brown */ - 0xff80ff80, /* White */ - 0x80808080, /* Gray */ - 0xc399c36a, /* Bright Blue */ - 0xd076d074, /* Bright Green */ - 0x80808080, /* Bright Cyan */ - 0x4c544cff, /* Bright Red */ - 0x3aaa34b5, /* Bright Magenta */ - 0xe100e194, /* Bright Yellow */ - 0xff80ff80 /* Bright White */ -}; - -static struct wiifb_mode_desc wiifb_modes[] = { - [WIIFB_MODE_NTSC_480i] = { - "NTSC 480i", - 640, 480, - 525, - WIIFB_MODE_FLAG_INTERLACED, - }, - [WIIFB_MODE_NTSC_480p] = { - "NTSC 480p", - 640, 480, - 525, - WIIFB_MODE_FLAG_PROGRESSIVE, - }, - [WIIFB_MODE_PAL_576i] = { - "PAL 576i (50Hz)", - 640, 574, - 625, - WIIFB_MODE_FLAG_INTERLACED, - }, - [WIIFB_MODE_PAL_480i] = { - "PAL 480i (60Hz)", - 640, 480, - 525, - WIIFB_MODE_FLAG_INTERLACED, - }, - [WIIFB_MODE_PAL_480p] = { - "PAL 480p", - 640, 480, - 525, - WIIFB_MODE_FLAG_PROGRESSIVE, - }, -}; - -static const uint32_t wiifb_filter_coeft[] = { - 0x1ae771f0, 0x0db4a574, 0x00c1188e, 0xc4c0cbe2, 0xfcecdecf, - 0x13130f08, 0x00080c0f -}; - -static __inline int -wiifb_background(uint8_t attr) -{ - - return (attr >> 4); -} - -static __inline int -wiifb_foreground(uint8_t attr) -{ - - return (attr & 0x0f); -} - -static void -wiifb_reset_video(struct wiifb_softc *sc) -{ - struct wiifb_dispcfg dc; - - wiifb_dispcfg_read(sc, &dc); - dc.dc_reset = 1; - wiifb_dispcfg_write(sc, &dc); - dc.dc_reset = 0; - wiifb_dispcfg_write(sc, &dc); -} - -static void -wiifb_enable_interrupts(struct wiifb_softc *sc) -{ - struct wiifb_dispint di; - -#ifdef notyet - /* - * Display Interrupt 0 - */ - di.di_htiming = 1; - di.di_vtiming = 1; - di.di_enable = 1; - di.di_irq = 1; - wiifb_dispint_write(sc, 0, &di); - - /* - * Display Interrupt 1 - */ - di.di_htiming = sc->sc_format == WIIFB_FORMAT_PAL ? 433 : 430; - di.di_vtiming = sc->sc_mode->fd_lines; - di.di_enable = 1; - di.di_irq = 1; - if (sc->sc_mode->fd_flags & WIIFB_MODE_FLAG_INTERLACED) - di.di_vtiming /= 2; - wiifb_dispint_write(sc, 1, &di); - - /* - * Display Interrupts 2 and 3 are not used. - */ - memset(&di, 0, sizeof(di)); - wiifb_dispint_write(sc, 2, &di); - wiifb_dispint_write(sc, 3, &di); -#else - memset(&di, 0, sizeof(di)); - wiifb_dispint_write(sc, 0, &di); - wiifb_dispint_write(sc, 1, &di); - wiifb_dispint_write(sc, 2, &di); - wiifb_dispint_write(sc, 3, &di); -#endif -} - -/* - * Reference gcnfb.c for an in depth explanation. - * XXX only works with NTSC. - */ -static void -wiifb_configure_tv_mode(struct wiifb_softc *sc) -{ - struct wiifb_vtiming vt; - struct wiifb_hscaling hs; - struct wiifb_htiming0 ht0; - struct wiifb_htiming1 ht1; - struct wiifb_vtimingodd vto; - struct wiifb_vtimingeven vte; - struct wiifb_burstblankodd bbo; - struct wiifb_burstblankeven bbe; - struct wiifb_picconf pc; - struct wiifb_mode_desc *mode = sc->sc_mode; - unsigned int height = mode->fd_height; - unsigned int width = mode->fd_width; - unsigned int eqpulse, interlacebias, shift; - const unsigned int maxwidth = 714; - unsigned int hblanking = maxwidth - width; - unsigned int hmargin = hblanking / 2; - unsigned int A = 20 + hmargin, C = 60 + hblanking - hmargin; - unsigned int maxheight = 484; - unsigned int P = 2 * (20 - 10 + 1); - unsigned int Q = 1; - unsigned int vblanking = maxheight - height; - unsigned int vmargin = vblanking / 2; - unsigned int prb = vmargin; - unsigned int psb = vblanking - vmargin; - int i; - - /* - * Vertical timing. - */ - if (mode->fd_flags & WIIFB_MODE_FLAG_INTERLACED) { - vt.vt_actvideo = height / 2; - interlacebias = 1; - shift = 0; - } else { - vt.vt_actvideo = height; - interlacebias = 0; - shift = 1; - } - /* Lines of equalization */ - if (mode->fd_lines == 625) - eqpulse = 2 * 2.5; - else - eqpulse = 2 * 3; - vt.vt_eqpulse = eqpulse << shift; - wiifb_vtiming_write(sc, &vt); - - /* - * Horizontal timings. - */ - ht0.ht0_hlinew = 858 / 2; - ht1.ht1_hsyncw = 64; - ht0.ht0_hcolourstart = 71; - ht0.ht0_hcolourend = 71 + 34; - ht1.ht1_hblankstart = (858 / 2) - A; - ht1.ht1_hblankend = 64 + C; - wiifb_htiming0_write(sc, &ht0); - wiifb_htiming1_write(sc, &ht1); - - /* - * Vertical timing odd/even. - */ - if (vmargin & 1) { - vto.vto_preb = (P + interlacebias + prb) << shift; - vto.vto_postb = (Q - interlacebias + psb) << shift; - vte.vte_preb = (P + prb) << shift; - vte.vte_postb = (Q - psb) << shift; - } else { - /* XXX if this isn't 0, it doesn't work? */ - prb = 0; - psb = 0; - vte.vte_preb = (P + interlacebias + prb) << shift; - vte.vte_postb = (Q - interlacebias + psb) << shift; - vto.vto_preb = (P + prb) << shift; - vto.vto_postb = (Q - psb) << shift; - } - wiifb_vtimingodd_write(sc, &vto); - wiifb_vtimingeven_write(sc, &vte); - - /* - * Burst blanking odd/even interval. - */ - bbo.bbo_bs1 = 2 * (18 - 7 + 1); - bbe.bbe_bs2 = bbo.bbo_bs3 = bbe.bbe_bs4 = bbo.bbo_bs1; - bbo.bbo_be1 = 2 * (525 - 7 + 1); - bbe.bbe_be2 = bbo.bbo_be3 = bbe.bbe_be4 = bbo.bbo_be1; - wiifb_burstblankodd_write(sc, &bbo); - wiifb_burstblankeven_write(sc, &bbe); - - /* - * Picture configuration. - */ - pc.pc_strides = (mode->fd_width * 2) / 32; - if (mode->fd_flags & WIIFB_MODE_FLAG_INTERLACED) - pc.pc_strides *= 2; - pc.pc_reads = (mode->fd_width * 2) / 32; - wiifb_picconf_write(sc, &pc); - - /* - * Horizontal scaling disabled. - */ - hs.hs_enable = 0; - hs.hs_step = 256; - wiifb_hscaling_write(sc, &hs); - - /* - * Filter coeficient table. - */ - for (i = 0; i < 7; i++) - wiifb_filtcoeft_write(sc, i, wiifb_filter_coeft[i]); - - /* - * Anti alias. - */ - wiifb_antialias_write(sc, 0x00ff0000); - - /* - * Video clock. - */ - wiifb_videoclk_write(sc, - mode->fd_flags & WIIFB_MODE_FLAG_INTERLACED ? 0 : 1); - - /* - * Disable horizontal scaling width. - */ - wiifb_hscalingw_write(sc, mode->fd_width); - - /* - * DEBUG mode borders. Not used. - */ - wiifb_hborderend_write(sc, 0); - wiifb_hborderstart_write(sc, 0); - - /* - * XXX unknown registers. - */ - wiifb_unknown1_write(sc, 0x00ff); - wiifb_unknown2_write(sc, 0x00ff00ff); - wiifb_unknown3_write(sc, 0x00ff00ff); -} - -static void -wiifb_setup_framebuffer(struct wiifb_softc *sc) -{ - intptr_t addr = sc->sc_fb_addr; - struct wiifb_topfieldbasel tfbl; - struct wiifb_bottomfieldbasel bfbl; - struct wiifb_topfieldbaser tfbr; - struct wiifb_bottomfieldbaser bfbr; - - tfbl.tfbl_fbaddr = addr >> 5; - tfbl.tfbl_xoffset = (addr / 2) & 0xf; - tfbl.tfbl_pageoffbit = 1; - wiifb_topfieldbasel_write(sc, &tfbl); - - if (sc->sc_mode->fd_flags & WIIFB_MODE_FLAG_INTERLACED) - addr += sc->sc_mode->fd_width * 2; - bfbl.bfbl_fbaddr = addr >> 5; - bfbl.bfbl_xoffset = (addr / 2) & 0xf; - bfbl.bfbl_pageoffbit = 1; - wiifb_bottomfieldbasel_write(sc, &bfbl); - - /* - * Only used used for 3D. - */ - memset(&tfbr, 0, sizeof(tfbr)); - memset(&bfbr, 0, sizeof(bfbr)); - wiifb_topfieldbaser_write(sc, &tfbr); - wiifb_bottomfieldbaser_write(sc, &bfbr); -} - -static int -wiifb_configure(int flags) -{ - struct wiifb_softc *sc; - struct wiifb_dispcfg dc; - int progressive; - - sc = &wiifb_softc; - if (sc->sc_initialized) { - /* XXX We should instead use bus_space */ - sc->sc_fb_addr = (intptr_t)pmap_mapdev(WIIFB_FB_ADDR, WIIFB_FB_LEN); - sc->sc_reg_addr = (intptr_t)pmap_mapdev(WIIFB_REG_ADDR, WIIFB_REG_LEN); - return 0; - } - - sc->sc_console = 1; - - sc->sc_fb_addr = WIIFB_FB_ADDR; - sc->sc_fb_size = WIIFB_FB_LEN; - - sc->sc_reg_addr = WIIFB_REG_ADDR; - sc->sc_reg_size = WIIFB_REG_LEN; - - wiifb_reset_video(sc); - wiifb_dispcfg_read(sc, &dc); - sc->sc_format = dc.dc_format; - sc->sc_component = wiifb_component_enabled(sc); - progressive = dc.dc_noninterlaced; - switch (sc->sc_format) { - case WIIFB_FORMAT_MPAL: - case WIIFB_FORMAT_DEBUG: - case WIIFB_FORMAT_NTSC: - sc->sc_mode = progressive ? - &wiifb_modes[WIIFB_MODE_NTSC_480p] : - &wiifb_modes[WIIFB_MODE_NTSC_480i]; - break; - case WIIFB_FORMAT_PAL: - sc->sc_mode = progressive ? - &wiifb_modes[WIIFB_MODE_PAL_480p] : - &wiifb_modes[WIIFB_MODE_PAL_480i]; - break; - } - sc->sc_height = sc->sc_mode->fd_height; - sc->sc_width = sc->sc_mode->fd_width; - /* Usually we multiply by 4, but I think this looks better. */ - sc->sc_stride = sc->sc_width * 2; - - wiifb_init(0, &sc->sc_va, 0); - - sc->sc_initialized = 1; - - return (0); -} - -static int -wiifb_probe(int unit, video_adapter_t **adp, void *arg, int flags) -{ - - return (0); -} - -static int -wiifb_init(int unit, video_adapter_t *adp, int flags) -{ - struct wiifb_softc *sc; - video_info_t *vi; - - sc = (struct wiifb_softc *)adp; - vi = &adp->va_info; - - vid_init_struct(adp, "wiifb", -1, unit); - - sc->sc_font = dflt_font_8; - vi->vi_cheight = WIIFB_FONT_HEIGHT; - vi->vi_width = sc->sc_width/8; - vi->vi_height = sc->sc_height/vi->vi_cheight; - vi->vi_cwidth = 8; - - /* - * Clamp width/height to syscons maximums - */ - if (vi->vi_width > COL) - vi->vi_width = COL; - if (vi->vi_height > ROW) - vi->vi_height = ROW; - - sc->sc_xmargin = (sc->sc_width - (vi->vi_width * vi->vi_cwidth)) / 2; - sc->sc_ymargin = (sc->sc_height - (vi->vi_height * vi->vi_cheight))/2; - - adp->va_window = (vm_offset_t) wiifb_static_window; - /* XXX no colour support */ - adp->va_flags |= V_ADP_FONT | /*V_ADP_COLOR |*/ V_ADP_MODECHANGE; - - vid_register(&sc->sc_va); - - wiifb_configure_tv_mode(sc); - wiifb_setup_framebuffer(sc); - wiifb_enable_interrupts(sc); - wiifb_clear(adp); - - return (0); -} - -static int -wiifb_get_info(video_adapter_t *adp, int mode, video_info_t *info) -{ - - bcopy(&adp->va_info, info, sizeof(*info)); - return (0); -} - -static int -wiifb_query_mode(video_adapter_t *adp, video_info_t *info) -{ - - return (0); -} - -static int -wiifb_set_mode(video_adapter_t *adp, int mode) -{ - - return (0); -} - -static int -wiifb_save_font(video_adapter_t *adp, int page, int size, int width, - u_char *data, int c, int count) -{ - - return (0); -} - -static int -wiifb_load_font(video_adapter_t *adp, int page, int size, int width, - u_char *data, int c, int count) -{ - struct wiifb_softc *sc = (struct wiifb_softc *)adp; - - sc->sc_font = data; - - return (0); -} - -static int -wiifb_show_font(video_adapter_t *adp, int page) -{ - - return (0); -} - -static int -wiifb_save_palette(video_adapter_t *adp, u_char *palette) -{ - - return (0); -} - -static int -wiifb_load_palette(video_adapter_t *adp, u_char *palette) -{ - - return (0); -} - -static int -wiifb_set_border(video_adapter_t *adp, int border) -{ - - return (wiifb_blank_display(adp, border)); -} - -static int -wiifb_save_state(video_adapter_t *adp, void *p, size_t size) -{ - - return (0); -} - -static int -wiifb_load_state(video_adapter_t *adp, void *p) -{ - - return (0); -} - -static int -wiifb_set_win_org(video_adapter_t *adp, off_t offset) -{ - - return (0); -} - -static int -wiifb_read_hw_cursor(video_adapter_t *adp, int *col, int *row) -{ - - *col = *row = 0; - - return (0); -} - -static int -wiifb_set_hw_cursor(video_adapter_t *adp, int col, int row) -{ - - return (0); -} - -static int -wiifb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, - int celsize, int blink) -{ - - return (0); -} - -static int -wiifb_blank_display(video_adapter_t *adp, int mode) -{ - struct wiifb_softc *sc = (struct wiifb_softc *)adp; - uint32_t *p; - - for (p = (uint32_t *)sc->sc_fb_addr; - p < (uint32_t *)(sc->sc_fb_addr + sc->sc_fb_size); - p++) - *p = wiifb_cmap[wiifb_background(SC_NORM_ATTR)]; - - return (0); -} - -static int -wiifb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, - int prot, vm_memattr_t *memattr) -{ - struct wiifb_softc *sc; - - sc = (struct wiifb_softc *)adp; - - /* - * This might be a legacy VGA mem request: if so, just point it at the - * framebuffer, since it shouldn't be touched - */ - if (offset < sc->sc_stride*sc->sc_height) { - *paddr = sc->sc_fb_addr + offset; - return (0); - } - - return (EINVAL); -} - -static int -wiifb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data) -{ - - return (0); -} - -static int -wiifb_clear(video_adapter_t *adp) -{ - - return (wiifb_blank_display(adp, 0)); -} - -static int -wiifb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) -{ - - return (0); -} - -static int -wiifb_bitblt(video_adapter_t *adp, ...) -{ - - return (0); -} - -static int -wiifb_diag(video_adapter_t *adp, int level) -{ - - return (0); -} - -static int -wiifb_save_cursor_palette(video_adapter_t *adp, u_char *palette) -{ - - return (0); -} - -static int -wiifb_load_cursor_palette(video_adapter_t *adp, u_char *palette) -{ - - return (0); -} - -static int -wiifb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n) -{ - - return (0); -} - -static int -wiifb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a, - int size, int bpp, int bit_ltor, int byte_ltor) -{ - - return (0); -} - -static int -wiifb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) -{ - struct wiifb_softc *sc; - int row; - int col; - int i, j, k; - uint32_t *addr; - u_char *p; - uint32_t fg, bg; - unsigned long pixel[2]; - - sc = (struct wiifb_softc *)adp; - row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight; - col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth / 2; - p = sc->sc_font + c*WIIFB_FONT_HEIGHT; - addr = (uint32_t *)sc->sc_fb_addr - + (row + sc->sc_ymargin)*(sc->sc_stride/4) - + col + sc->sc_xmargin; - - bg = wiifb_cmap[wiifb_background(a)]; - fg = wiifb_cmap[wiifb_foreground(a)]; - - for (i = 0; i < WIIFB_FONT_HEIGHT; i++) { - for (j = 0, k = 7; j < 4; j++, k--) { - if ((p[i] & (1 << k)) == 0) - pixel[0] = bg; - else - pixel[0] = fg; - k--; - if ((p[i] & (1 << k)) == 0) - pixel[1] = bg; - else - pixel[1] = fg; - - addr[j] = (pixel[0] & 0xffff00ff) | - (pixel[1] & 0x0000ff00); - } - addr += (sc->sc_stride/4); - } - - return (0); -} - -static int -wiifb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len) -{ - int i; - - for (i = 0; i < len; i++) - wiifb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8); - - return (0); -} - -static int -wiifb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, - uint32_t pixel_mask, int size, int width) -{ - - return (0); -} diff --git a/sys/powerpc/wii/wii_fbreg.h b/sys/powerpc/wii/wii_fbreg.h deleted file mode 100644 index 24a7cdf63486..000000000000 --- a/sys/powerpc/wii/wii_fbreg.h +++ /dev/null @@ -1,40 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _POWERPC_WII_WII_FBREG_H -#define _POWERPC_WII_WII_FBREG_H - -/* - * Memory addresses for the I/O and the framebuffer. - */ -#define WIIFB_REG_ADDR 0x0c002000 -#define WIIFB_REG_LEN 0x100 -#define WIIFB_FB_ADDR 0x01698000 /* at the end of 1T SRAM */ -#define WIIFB_FB_LEN 0x168000 - -#endif /* _POWERPC_WII_WII_FBREG_H */ diff --git a/sys/powerpc/wii/wii_fbvar.h b/sys/powerpc/wii/wii_fbvar.h deleted file mode 100644 index 53e71dfa5b81..000000000000 --- a/sys/powerpc/wii/wii_fbvar.h +++ /dev/null @@ -1,857 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _POWERPC_WII_WIIFB_H -#define _POWERPC_WII_WIIFB_H - -#define WIIFB_FONT_HEIGHT 8 - -enum wiifb_format { - WIIFB_FORMAT_NTSC = 0, - WIIFB_FORMAT_PAL = 1, - WIIFB_FORMAT_MPAL = 2, - WIIFB_FORMAT_DEBUG = 3 -}; - -enum wiifb_mode { - WIIFB_MODE_NTSC_480i = 0, - WIIFB_MODE_NTSC_480p = 1, - WIIFB_MODE_PAL_576i = 2, - WIIFB_MODE_PAL_480i = 3, - WIIFB_MODE_PAL_480p = 4 -}; - -struct wiifb_mode_desc { - const char *fd_name; - unsigned int fd_width; - unsigned int fd_height; - unsigned int fd_lines; - uint8_t fd_flags; -#define WIIFB_MODE_FLAG_PROGRESSIVE 0x00 -#define WIIFB_MODE_FLAG_INTERLACED 0x01 -}; - -struct wiifb_softc { - video_adapter_t sc_va; - struct cdev *sc_si; - int sc_console; - - intptr_t sc_reg_addr; - unsigned int sc_reg_size; - - intptr_t sc_fb_addr; - unsigned int sc_fb_size; - - unsigned int sc_height; - unsigned int sc_width; - unsigned int sc_stride; - - unsigned int sc_xmargin; - unsigned int sc_ymargin; - - boolean_t sc_component; - enum wiifb_format sc_format; - struct wiifb_mode_desc *sc_mode; - - unsigned int sc_vtiming; - unsigned int sc_htiming; - - unsigned char *sc_font; - int sc_initialized; - int sc_rrid; -}; - -/* - * Vertical timing - * 16 bit - */ -#define WIIFB_REG_VTIMING 0x00 -struct wiifb_vtiming { - uint8_t vt_eqpulse; - uint16_t vt_actvideo; -}; - -static __inline void -wiifb_vtiming_read(struct wiifb_softc *sc, struct wiifb_vtiming *vt) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMING); - - vt->vt_eqpulse = *reg & 0xf; - vt->vt_actvideo = (*reg >> 4) & 0x3ff; -} - -static __inline void -wiifb_vtiming_write(struct wiifb_softc *sc, struct wiifb_vtiming *vt) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMING); - - *reg = ((vt->vt_actvideo & 0x3ff) << 4) | - (vt->vt_eqpulse & 0xf); - powerpc_sync(); -} - -/* - * Display configuration - * 16 bit - */ -#define WIIFB_REG_DISPCFG 0x02 -struct wiifb_dispcfg { - uint8_t dc_enable; - uint8_t dc_reset; - uint8_t dc_noninterlaced; - uint8_t dc_3dmode; - uint8_t dc_latchenb0; - uint8_t dc_latchenb1; - enum wiifb_format dc_format; -}; - -static __inline void -wiifb_dispcfg_read(struct wiifb_softc *sc, struct wiifb_dispcfg *dc) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_DISPCFG); - - dc->dc_enable = *reg & 0x1; - dc->dc_reset = (*reg >> 1) & 0x1; - dc->dc_noninterlaced = (*reg >> 2) & 0x1; - dc->dc_3dmode = (*reg >> 3) & 0x1; - dc->dc_latchenb0 = (*reg >> 4) & 0x3; - dc->dc_latchenb1 = (*reg >> 6) & 0x3; - dc->dc_format = (*reg >> 8) & 0x3; -} - -static __inline void -wiifb_dispcfg_write(struct wiifb_softc *sc, struct wiifb_dispcfg *dc) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_DISPCFG); - - *reg = ((dc->dc_format & 0x3) << 8) | - ((dc->dc_latchenb1 & 0x3) << 6) | - ((dc->dc_latchenb0 & 0x3) << 4) | - ((dc->dc_3dmode & 0x1) << 3) | - ((dc->dc_noninterlaced & 0x1) << 2) | - ((dc->dc_reset & 0x1) << 1) | - (dc->dc_enable & 0x1); - powerpc_sync(); -} - -/* - * Horizontal Timing 0 - * 32 bit - */ -#define WIIFB_REG_HTIMING0 0x04 -struct wiifb_htiming0 { - uint16_t ht0_hlinew; /* half line width */ - uint8_t ht0_hcolourend; - uint8_t ht0_hcolourstart; -}; - -static __inline void -wiifb_htiming0_read(struct wiifb_softc *sc, struct wiifb_htiming0 *ht0) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_HTIMING0); - - ht0->ht0_hlinew = *reg & 0x1ff; - ht0->ht0_hcolourend = (*reg >> 16) & 0x7f; - ht0->ht0_hcolourstart = (*reg >> 24) & 0x7f; -} - -static __inline void -wiifb_htiming0_write(struct wiifb_softc *sc, struct wiifb_htiming0 *ht0) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_HTIMING0); - - *reg = ((ht0->ht0_hcolourstart & 0x7f) << 24) | - ((ht0->ht0_hcolourend & 0x7f) << 16) | - (ht0->ht0_hlinew & 0x1ff); - powerpc_sync(); -} -/* - * Horizontal Timing 1 - * 32 bit - */ -#define WIIFB_REG_HTIMING1 0x08 -struct wiifb_htiming1 { - uint8_t ht1_hsyncw; - uint16_t ht1_hblankend; - uint16_t ht1_hblankstart; -}; - -static __inline void -wiifb_htiming1_read(struct wiifb_softc *sc, struct wiifb_htiming1 *ht1) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_HTIMING1); - - ht1->ht1_hsyncw = *reg & 0x7f; - ht1->ht1_hblankend = (*reg >> 7) & 0x3ff; - ht1->ht1_hblankstart = (*reg >> 17) & 0x3ff; -} - -static __inline void -wiifb_htiming1_write(struct wiifb_softc *sc, struct wiifb_htiming1 *ht1) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_HTIMING1); - - *reg = ((ht1->ht1_hblankstart & 0x3ff) << 17) | - ((ht1->ht1_hblankend & 0x3ff) << 7) | - (ht1->ht1_hsyncw & 0x7f); - powerpc_sync(); -} - -/* - * Vertical Timing Odd - * 32 bit - */ -#define WIIFB_REG_VTIMINGODD 0x0c -struct wiifb_vtimingodd { - uint16_t vto_preb; /* pre blanking */ - uint16_t vto_postb; /* post blanking */ -}; - -static __inline void -wiifb_vtimingodd_read(struct wiifb_softc *sc, struct wiifb_vtimingodd *vto) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMINGODD); - - vto->vto_preb = *reg & 0x3ff; - vto->vto_postb = (*reg >> 16) & 0x3ff; -} - -static __inline void -wiifb_vtimingodd_write(struct wiifb_softc *sc, struct wiifb_vtimingodd *vto) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMINGODD); - - *reg = ((vto->vto_postb & 0x3ff) << 16) | - (vto->vto_preb & 0x3ff); - powerpc_sync(); -} - -/* - * Vertical Timing Even - * 32 bit - */ -#define WIIFB_REG_VTIMINGEVEN 0x10 -struct wiifb_vtimingeven { - uint16_t vte_preb; /* pre blanking */ - uint16_t vte_postb; /* post blanking */ -}; - -static __inline void -wiifb_vtimingeven_read(struct wiifb_softc *sc, struct wiifb_vtimingeven *vte) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMINGEVEN); - - vte->vte_preb = *reg & 0x3ff; - vte->vte_postb = (*reg >> 16) & 0x3ff; -} - -static __inline void -wiifb_vtimingeven_write(struct wiifb_softc *sc, struct wiifb_vtimingeven *vte) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_VTIMINGEVEN); - - *reg = ((vte->vte_postb & 0x3ff) << 16) | - (vte->vte_preb & 0x3ff); - powerpc_sync(); -} - -/* - * Burst Blanking Odd Interval - * 32 bit - */ -#define WIIFB_REG_BURSTBLANKODD 0x14 -struct wiifb_burstblankodd { - uint8_t bbo_bs1; - uint16_t bbo_be1; - uint8_t bbo_bs3; - uint16_t bbo_be3; -}; - -static __inline void -wiifb_burstblankodd_read(struct wiifb_softc *sc, - struct wiifb_burstblankodd *bbo) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BURSTBLANKODD); - - bbo->bbo_bs1 = *reg & 0x1f; - bbo->bbo_be1 = (*reg >> 5) & 0x7ff; - bbo->bbo_bs3 = (*reg >> 16) & 0x1f; - bbo->bbo_be3 = (*reg >> 21) & 0x7ff; -} - -static __inline void -wiifb_burstblankodd_write(struct wiifb_softc *sc, - struct wiifb_burstblankodd *bbo) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BURSTBLANKODD); - - *reg = ((bbo->bbo_be3 & 0x7ff) << 21) | - ((bbo->bbo_bs3 & 0x1f) << 16) | - ((bbo->bbo_be1 & 0x7ff) << 5) | - (bbo->bbo_bs1 & 0x1f); - powerpc_sync(); -} - -/* - * Burst Blanking Even Interval - * 32 bit - */ -#define WIIFB_REG_BURSTBLANKEVEN 0x18 -struct wiifb_burstblankeven { - uint8_t bbe_bs2; - uint16_t bbe_be2; - uint8_t bbe_bs4; - uint16_t bbe_be4; -}; - -static __inline void -wiifb_burstblankeven_read(struct wiifb_softc *sc, - struct wiifb_burstblankeven *bbe) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BURSTBLANKEVEN); - - bbe->bbe_bs2 = *reg & 0x1f; - bbe->bbe_be2 = (*reg >> 5) & 0x7ff; - bbe->bbe_bs4 = (*reg >> 16) & 0x1f; - bbe->bbe_be4 = (*reg >> 21) & 0x7ff; -} - -static __inline void -wiifb_burstblankeven_write(struct wiifb_softc *sc, - struct wiifb_burstblankeven *bbe) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BURSTBLANKEVEN); - - *reg = ((bbe->bbe_be4 & 0x7ff) << 21) | - ((bbe->bbe_bs4 & 0x1f) << 16) | - ((bbe->bbe_be2 & 0x7ff) << 5) | - (bbe->bbe_bs2 & 0x1f); - powerpc_sync(); -} - -/* - * Top Field Base Left - * 32 bit - */ -#define WIIFB_REG_TOPFIELDBASEL 0x1c -struct wiifb_topfieldbasel { - uint32_t tfbl_fbaddr; - uint8_t tfbl_xoffset; - uint8_t tfbl_pageoffbit; -}; - -static __inline void -wiifb_topfieldbasel_read(struct wiifb_softc *sc, - struct wiifb_topfieldbasel *tfbl) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_TOPFIELDBASEL); - - tfbl->tfbl_fbaddr = *reg & 0xffffff; - tfbl->tfbl_xoffset = (*reg >> 24) & 0xf; - tfbl->tfbl_pageoffbit = (*reg >> 28) & 0x1; -} - -static __inline void -wiifb_topfieldbasel_write(struct wiifb_softc *sc, - struct wiifb_topfieldbasel *tfbl) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_TOPFIELDBASEL); - - *reg = ((tfbl->tfbl_pageoffbit & 0x1) << 28) | - ((tfbl->tfbl_xoffset & 0xf) << 24) | - (tfbl->tfbl_fbaddr & 0xffffff); - powerpc_sync(); -} - -/* - * Top Field Base Right - * 32 bit - */ -#define WIIFB_REG_TOPFIELDBASER 0x20 -struct wiifb_topfieldbaser { - uint32_t tfbr_fbaddr; - uint8_t tfbr_pageoffbit; -}; - -static __inline void -wiifb_topfieldbaser_read(struct wiifb_softc *sc, - struct wiifb_topfieldbaser *tfbr) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_TOPFIELDBASER); - - tfbr->tfbr_fbaddr = *reg & 0xffffff; - tfbr->tfbr_pageoffbit = (*reg >> 28) & 0x1; -} - -static __inline void -wiifb_topfieldbaser_write(struct wiifb_softc *sc, - struct wiifb_topfieldbaser *tfbr) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_TOPFIELDBASER); - - *reg = ((tfbr->tfbr_pageoffbit & 0x1) << 28) | - (tfbr->tfbr_fbaddr & 0xffffff); - powerpc_sync(); -} - -/* - * Bottom Field Base Left - * 32 bit - */ -#define WIIFB_REG_BOTTOMFIELDBASEL 0x24 -struct wiifb_bottomfieldbasel { - uint32_t bfbl_fbaddr; - uint8_t bfbl_xoffset; - uint8_t bfbl_pageoffbit; -}; - -static __inline void -wiifb_bottomfieldbasel_read(struct wiifb_softc *sc, - struct wiifb_bottomfieldbasel *bfbl) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BOTTOMFIELDBASEL); - - bfbl->bfbl_fbaddr = *reg & 0xffffff; - bfbl->bfbl_xoffset = (*reg >> 24) & 0xf; - bfbl->bfbl_pageoffbit = (*reg >> 28) & 0x1; -} - -static __inline void -wiifb_bottomfieldbasel_write(struct wiifb_softc *sc, - struct wiifb_bottomfieldbasel *bfbl) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BOTTOMFIELDBASEL); - - *reg = ((bfbl->bfbl_pageoffbit & 0x1) << 28) | - ((bfbl->bfbl_xoffset & 0xf) << 24) | - (bfbl->bfbl_fbaddr & 0xffffff); - powerpc_sync(); -} - -/* - * Bottom Field Base Right - * 32 bit - */ -#define WIIFB_REG_BOTTOMFIELDBASER 0x28 -struct wiifb_bottomfieldbaser { - uint32_t bfbr_fbaddr; - uint8_t bfbr_pageoffbit; -}; - -static __inline void -wiifb_bottomfieldbaser_read(struct wiifb_softc *sc, - struct wiifb_bottomfieldbaser *bfbr) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BOTTOMFIELDBASER); - - bfbr->bfbr_fbaddr = *reg & 0xffffff; - bfbr->bfbr_pageoffbit = (*reg >> 28) & 0x1; -} - -static __inline void -wiifb_bottomfieldbaser_write(struct wiifb_softc *sc, - struct wiifb_bottomfieldbaser *bfbr) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_BOTTOMFIELDBASER); - - *reg = ((bfbr->bfbr_pageoffbit & 0x1) << 28) | - (bfbr->bfbr_fbaddr & 0xffffff); - powerpc_sync(); -} - -/* - * Display Position Vertical - * 16 bit - */ -#define WIIFB_REG_DISPPOSV 0x2c -static __inline uint16_t -wiifb_dispposv_read(struct wiifb_softc *sc) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_DISPPOSV); - - return (*reg & 0x7ff); -} - -static __inline void -wiifb_dispposv_write(struct wiifb_softc *sc, uint16_t val) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_DISPPOSV); - - *reg = val & 0x7ff; - powerpc_sync(); -} - -/* - * Display Position Horizontal - * 16 bit - */ -#define WIIFB_REG_DISPPOSH 0x2e -static __inline uint16_t -wiifb_dispposh_read(struct wiifb_softc *sc) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_DISPPOSH); - - return (*reg & 0x7ff); -} - -static __inline void -wiifb_dispposh_write(struct wiifb_softc *sc, uint16_t val) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_DISPPOSH); - - *reg = val & 0x7ff; - powerpc_sync(); -} - -/* - * Display Interrupts. - * There are 4 display interrupt registers, all 32 bit. - */ -#define WIIFB_REG_DISPINT0 0x30 -#define WIIFB_REG_DISPINT1 0x34 -#define WIIFB_REG_DISPINT2 0x38 -#define WIIFB_REG_DISPINT3 0x3c -struct wiifb_dispint { - uint16_t di_htiming; - uint16_t di_vtiming; - uint8_t di_enable; - uint8_t di_irq; -}; - -static __inline void -wiifb_dispint_read(struct wiifb_softc *sc, int regno, struct wiifb_dispint *di) -{ - volatile uint32_t *reg = (uint32_t *)(sc->sc_reg_addr + - WIIFB_REG_DISPINT0 + regno * 4); - - di->di_htiming = *reg & 0x3ff; - di->di_vtiming = (*reg >> 16) & 0x3ff; - di->di_enable = (*reg >> 28) & 0x1; - di->di_irq = (*reg >> 31) & 0x1; -} - -static __inline void -wiifb_dispint_write(struct wiifb_softc *sc, int regno, struct wiifb_dispint *di) -{ - volatile uint32_t *reg = (uint32_t *)(sc->sc_reg_addr + - WIIFB_REG_DISPINT0 + regno * 4); - - *reg = ((di->di_irq & 0x1) << 31) | - ((di->di_enable & 0x1) << 28) | - ((di->di_vtiming & 0x3ff) << 16) | - (di->di_htiming & 0x3ff); - powerpc_sync(); -} - -/* - * Display Latch 0 - * 32 bit - */ -#define WIIFB_REG_DISPLAYTCH0 0x40 - -/* - * Display Latch 1 - * 32 bit - */ -#define WIIFB_REG_DISPLAYTCH1 0x44 - -/* - * Picture Configuration - * 16 bit - */ -#define WIIFB_REG_PICCONF 0x48 -struct wiifb_picconf { - uint8_t pc_strides; /* strides per line (words) */ - uint8_t pc_reads; /* reads per line (words */ -}; - -static __inline void -wiifb_picconf_read(struct wiifb_softc *sc, struct wiifb_picconf *pc) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_PICCONF); - - pc->pc_strides = *reg & 0xff; - pc->pc_reads = (*reg >> 8) & 0xff; -} - -static __inline void -wiifb_picconf_write(struct wiifb_softc *sc, struct wiifb_picconf *pc) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_PICCONF); - - *reg = ((pc->pc_reads & 0xff) << 8) | - (pc->pc_strides & 0xff); - powerpc_sync(); -} - -/* - * Horizontal Scaling - * 16 bit - */ -#define WIIFB_REG_HSCALING 0x4a -struct wiifb_hscaling { - uint16_t hs_step; - uint8_t hs_enable; -}; - -static __inline void -wiifb_hscaling_read(struct wiifb_softc *sc, struct wiifb_hscaling *hs) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HSCALING); - - hs->hs_step = *reg & 0x1ff; - hs->hs_enable = (*reg >> 12) & 0x1; -} - -static __inline void -wiifb_hscaling_write(struct wiifb_softc *sc, struct wiifb_hscaling *hs) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HSCALING); - - *reg = ((hs->hs_step & 0x1ff) << 12) | - (hs->hs_enable & 0x1); - powerpc_sync(); -} - -/* - * Filter Coeficient Table 0-6 - * 32 bit - */ -#define WIIFB_REG_FILTCOEFT0 0x4c -#define WIIFB_REG_FILTCOEFT1 0x50 -#define WIIFB_REG_FILTCOEFT2 0x54 -#define WIIFB_REG_FILTCOEFT3 0x58 -#define WIIFB_REG_FILTCOEFT4 0x5c -#define WIIFB_REG_FILTCOEFT5 0x60 -#define WIIFB_REG_FILTCOEFT6 0x64 -static __inline void -wiifb_filtcoeft_write(struct wiifb_softc *sc, unsigned int regno, - uint32_t coeft) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_FILTCOEFT0 + 4 * regno); - - *reg = coeft; - powerpc_sync(); -} - -/* - * Anti-aliasing - * 32 bit - */ -#define WIIFB_REG_ANTIALIAS 0x68 -static __inline void -wiifb_antialias_write(struct wiifb_softc *sc, uint32_t antialias) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_ANTIALIAS); - - *reg = antialias; - powerpc_sync(); -} - -/* - * Video Clock - * 16 bit - */ -#define WIIFB_REG_VIDEOCLK 0x6c -static __inline uint8_t -wiifb_videoclk_read(struct wiifb_softc *sc) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_VIDEOCLK); - - return (*reg & 0x1); -} - -static __inline void -wiifb_videoclk_write(struct wiifb_softc *sc, uint16_t clk54mhz) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_VIDEOCLK); - - *reg = clk54mhz & 0x1; - powerpc_sync(); -} - -/* - * DTV Status - * 16 bit - * - * DTV is another name for the Component Cable output. - */ -#define WIIFB_REG_DTVSTATUS 0x6e -static __inline uint16_t -wiifb_dtvstatus_read(struct wiifb_softc *sc) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_DTVSTATUS); - - return (*reg & 0x1); -} - -static __inline uint16_t -wiifb_component_enabled(struct wiifb_softc *sc) -{ - - return wiifb_dtvstatus_read(sc); -} - -/* - * Horizontal Scaling Width - * 16 bit - */ -#define WIIFB_REG_HSCALINGW 0x70 -static __inline uint16_t -wiifb_hscalingw_read(struct wiifb_softc *sc) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HSCALINGW); - - return (*reg & 0x3ff); -} - -static __inline void -wiifb_hscalingw_write(struct wiifb_softc *sc, uint16_t width) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HSCALINGW); - - *reg = width & 0x3ff; - powerpc_sync(); -} - -/* - * Horizontal Border End - * For debug mode only. Not used by this driver. - * 16 bit - */ -#define WIIFB_REG_HBORDEREND 0x72 -static __inline void -wiifb_hborderend_write(struct wiifb_softc *sc, uint16_t border) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HBORDEREND); - - *reg = border; - powerpc_sync(); -} - -/* - * Horizontal Border Start - * 16 bit - */ -#define WIIFB_REG_HBORDERSTART 0x74 -static __inline void -wiifb_hborderstart_write(struct wiifb_softc *sc, uint16_t border) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_HBORDERSTART); - - *reg = border; - powerpc_sync(); -} - -/* - * Unknown register - * 16 bit - */ -#define WIIFB_REG_UNKNOWN1 0x76 -static __inline void -wiifb_unknown1_write(struct wiifb_softc *sc, uint16_t unknown) -{ - volatile uint16_t *reg = - (uint16_t *)(sc->sc_reg_addr + WIIFB_REG_UNKNOWN1); - - *reg = unknown; - powerpc_sync(); -} - -/* - * Unknown register - * 32 bit - */ -#define WIIFB_REG_UNKNOWN2 0x78 -static __inline void -wiifb_unknown2_write(struct wiifb_softc *sc, uint32_t unknown) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_UNKNOWN2); - - *reg = unknown; - powerpc_sync(); -} - -/* - * Unknown register - * 32 bit - */ -#define WIIFB_REG_UNKNOWN3 0x7c -static __inline void -wiifb_unknown3_write(struct wiifb_softc *sc, uint32_t unknown) -{ - volatile uint32_t *reg = - (uint32_t *)(sc->sc_reg_addr + WIIFB_REG_UNKNOWN3); - - *reg = unknown; - powerpc_sync(); -} - -#endif /* _POWERPC_WII_WIIFB_H */ diff --git a/sys/powerpc/wii/wii_gpio.c b/sys/powerpc/wii/wii_gpio.c deleted file mode 100644 index e6d76b8c2ab1..000000000000 --- a/sys/powerpc/wii/wii_gpio.c +++ /dev/null @@ -1,353 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "gpio_if.h" - -struct wiigpio_softc { - device_t sc_dev; - struct resource *sc_rres; - bus_space_tag_t sc_bt; - bus_space_handle_t sc_bh; - int sc_rrid; - struct mtx sc_mtx; - struct gpio_pin sc_pins[WIIGPIO_NPINS]; -}; - - -#define WIIGPIO_PINBANK(_p) ((_p) / (WIIGPIO_NPINS / 2)) -#define WIIGPIO_PINMASK(_p) (1 << ((_p) % (WIIGPIO_NPINS / 2))) -#define WIIGPIO_LOCK(sc) mtx_lock(&(sc)->sc_mtx) -#define WIIGPIO_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) - -static int wiigpio_probe(device_t); -static int wiigpio_attach(device_t); -static int wiigpio_detach(device_t); -static int wiigpio_pin_max(device_t, int *); -static int wiigpio_pin_getname(device_t, uint32_t, char *); -static int wiigpio_pin_getflags(device_t, uint32_t, uint32_t *); -static int wiigpio_pin_setflags(device_t, uint32_t, uint32_t); -static int wiigpio_pin_getcaps(device_t, uint32_t, uint32_t *); -static int wiigpio_pin_get(device_t, uint32_t, unsigned int *); -static int wiigpio_pin_set(device_t, uint32_t, unsigned int); -static int wiigpio_pin_toggle(device_t, uint32_t); -static void wiigpio_shutdown(void *, int); - -static device_method_t wiigpio_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, wiigpio_probe), - DEVMETHOD(device_attach, wiigpio_attach), - DEVMETHOD(device_detach, wiigpio_detach), - - /* GPIO protocol */ - DEVMETHOD(gpio_pin_max, wiigpio_pin_max), - DEVMETHOD(gpio_pin_getname, wiigpio_pin_getname), - DEVMETHOD(gpio_pin_getflags, wiigpio_pin_getflags), - DEVMETHOD(gpio_pin_setflags, wiigpio_pin_setflags), - DEVMETHOD(gpio_pin_getcaps, wiigpio_pin_getcaps), - DEVMETHOD(gpio_pin_get, wiigpio_pin_get), - DEVMETHOD(gpio_pin_set, wiigpio_pin_set), - DEVMETHOD(gpio_pin_toggle, wiigpio_pin_toggle), - - DEVMETHOD_END -}; - -static driver_t wiigpio_driver = { - "wiigpio", - wiigpio_methods, - sizeof(struct wiigpio_softc) -}; - -static devclass_t wiigpio_devclass; - -DRIVER_MODULE(wiigpio, wiibus, wiigpio_driver, wiigpio_devclass, 0, 0); - -static __inline uint32_t -wiigpio_read(struct wiigpio_softc *sc, int n) -{ - - return (bus_space_read_4(sc->sc_bt, sc->sc_bh, n * 0x20)); -} - -static __inline void -wiigpio_write(struct wiigpio_softc *sc, int n, uint32_t reg) -{ - - bus_space_write_4(sc->sc_bt, sc->sc_bh, n * 0x20, reg); -} - -static __inline uint32_t -wiigpio_dir_read(struct wiigpio_softc *sc, int n) -{ - - return (bus_space_read_4(sc->sc_bt, sc->sc_bh, n * 0x20 + 4)); -} - -static __inline void -wiigpio_dir_write(struct wiigpio_softc *sc, int n, uint32_t reg) -{ - - bus_space_write_4(sc->sc_bt, sc->sc_bh, n * 0x20 + 4, reg); -} - -static int -wiigpio_probe(device_t dev) -{ - device_set_desc(dev, "Nintendo Wii GPIO"); - - return (BUS_PROBE_NOWILDCARD); -} - -static int -wiigpio_attach(device_t dev) -{ - struct wiigpio_softc *sc; - int i; - uint32_t d; - - sc = device_get_softc(dev); - sc->sc_dev = dev; - sc->sc_rrid = 0; - sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->sc_rrid, RF_ACTIVE); - if (sc->sc_rres == NULL) { - device_printf(dev, "could not alloc mem resource\n"); - return (ENXIO); - } - sc->sc_bt = rman_get_bustag(sc->sc_rres); - sc->sc_bh = rman_get_bushandle(sc->sc_rres); - mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); -#ifdef WIIGPIO_DEBUG - device_printf(dev, "dir bank0=0x%08x bank1=0x%08x\n", - wiigpio_dir_read(sc, 0), wiigpio_dir_read(sc, 1)); - device_printf(dev, "val bank0=0x%08x bank1=0x%08x\n", - wiigpio_read(sc, 0), wiigpio_read(sc, 1)); -#endif - for (i = 0; i < WIIGPIO_NPINS; i++) { - sc->sc_pins[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; - sc->sc_pins[i].gp_pin = i; - d = wiigpio_dir_read(sc, WIIGPIO_PINBANK(i)); - if (d & WIIGPIO_PINMASK(i)) - sc->sc_pins[i].gp_flags = GPIO_PIN_OUTPUT; - else - sc->sc_pins[i].gp_flags = GPIO_PIN_INPUT; - snprintf(sc->sc_pins[i].gp_name, GPIOMAXNAME, "PIN %d", i); -#ifdef WIIGPIO_DEBUG - device_printf(dev, "PIN %d state %d flag %s\n", i, - wiigpio_read(sc, WIIGPIO_PINBANK(i)) >> - (i % (WIIGPIO_NPINS / 2)) & 1, - sc->sc_pins[i].gp_flags == GPIO_PIN_INPUT ? - "GPIO_PIN_INPUT" : "GPIO_PIN_OUTPUT"); -#endif - } - device_add_child(dev, "gpioc", -1); - device_add_child(dev, "gpiobus", -1); - /* - * We will be responsible for powering off the system. - */ - EVENTHANDLER_REGISTER(shutdown_final, wiigpio_shutdown, dev, - SHUTDOWN_PRI_LAST); - - return (bus_generic_attach(dev)); -} - -static int -wiigpio_detach(device_t dev) -{ - struct wiigpio_softc *sc; - - sc = device_get_softc(dev); - bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres); - mtx_destroy(&sc->sc_mtx); - - return (0); -} - -static int -wiigpio_pin_max(device_t dev, int *maxpin) -{ - - *maxpin = WIIGPIO_NPINS - 1; - - return (0); -} - -static int -wiigpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) -{ - struct wiigpio_softc *sc; - - if (pin >= WIIGPIO_NPINS) - return (EINVAL); - sc = device_get_softc(dev); - *caps = sc->sc_pins[pin].gp_caps; - - return (0); -} - -static int -wiigpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) -{ - struct wiigpio_softc *sc; - uint32_t reg; - - if (pin >= WIIGPIO_NPINS) - return (EINVAL); - sc = device_get_softc(dev); - WIIGPIO_LOCK(sc); - reg = wiigpio_read(sc, WIIGPIO_PINBANK(pin)); - *val = !!(reg & WIIGPIO_PINMASK(pin)); - WIIGPIO_UNLOCK(sc); - - return (0); -} - -static int -wiigpio_pin_set(device_t dev, uint32_t pin, unsigned int value) -{ - struct wiigpio_softc *sc; - uint32_t reg, pinbank, pinmask; - - if (pin >= WIIGPIO_NPINS) - return (EINVAL); - sc = device_get_softc(dev); - pinbank = WIIGPIO_PINBANK(pin); - pinmask = WIIGPIO_PINMASK(pin); - WIIGPIO_LOCK(sc); - reg = wiigpio_read(sc, pinbank) & ~pinmask; - if (value) - reg |= pinmask; - wiigpio_write(sc, pinbank, reg); - WIIGPIO_UNLOCK(sc); - - return (0); -} - -static int -wiigpio_pin_toggle(device_t dev, uint32_t pin) -{ - struct wiigpio_softc *sc; - uint32_t val, pinbank, pinmask; - - if (pin >= WIIGPIO_NPINS) - return (EINVAL); - sc = device_get_softc(dev); - pinbank = WIIGPIO_PINBANK(pin); - pinmask = WIIGPIO_PINMASK(pin); - WIIGPIO_LOCK(sc); - val = wiigpio_read(sc, pinbank); - if (val & pinmask) - wiigpio_write(sc, pinbank, val & ~pinmask); - else - wiigpio_write(sc, pinbank, val | pinmask); - WIIGPIO_UNLOCK(sc); - - return (0); -} - -static int -wiigpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) -{ - struct wiigpio_softc *sc; - uint32_t reg, pinbank, pinmask; - - if (pin >= WIIGPIO_NPINS) - return (EINVAL); - sc = device_get_softc(dev); - pinbank = WIIGPIO_PINBANK(pin); - pinmask = WIIGPIO_PINMASK(pin); - WIIGPIO_LOCK(sc); - reg = wiigpio_dir_read(sc, WIIGPIO_PINBANK(pin)); - if (flags & GPIO_PIN_OUTPUT) - wiigpio_dir_write(sc, pinbank, reg | pinmask); - else - wiigpio_dir_write(sc, pinbank, reg & ~pinmask); - sc->sc_pins[pin].gp_flags = flags; - WIIGPIO_UNLOCK(sc); - - return (0); -} - -static int -wiigpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) -{ - struct wiigpio_softc *sc; - - if (pin >= WIIGPIO_NPINS) - return (EINVAL); - sc = device_get_softc(dev); - WIIGPIO_LOCK(sc); - *flags = sc->sc_pins[pin].gp_flags; - WIIGPIO_UNLOCK(sc); - - return (0); -} - -static int -wiigpio_pin_getname(device_t dev, uint32_t pin, char *name) -{ - struct wiigpio_softc *sc; - - if (pin >= WIIGPIO_NPINS) - return (EINVAL); - sc = device_get_softc(dev); - WIIGPIO_LOCK(sc); - memcpy(name, sc->sc_pins[pin].gp_name, GPIOMAXNAME); - WIIGPIO_UNLOCK(sc); - - return (0); -} - -static void -wiigpio_shutdown(void *xdev, int howto) -{ - device_t dev; - - if (!(howto & RB_POWEROFF)) - return; - dev = (device_t)xdev; - wiigpio_pin_setflags(dev, WIIGPIO_POWEROFF_PIN, GPIO_PIN_OUTPUT); - wiigpio_pin_set(dev, WIIGPIO_POWEROFF_PIN, 1); -} diff --git a/sys/powerpc/wii/wii_gpioreg.h b/sys/powerpc/wii/wii_gpioreg.h deleted file mode 100644 index 45527f5ab603..000000000000 --- a/sys/powerpc/wii/wii_gpioreg.h +++ /dev/null @@ -1,38 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _POWERPC_WII_WII_GPIOREG_H -#define _POWERPC_WII_WII_GPIOREG_H - -#define WIIGPIO_NPINS 64 -#define WIIGPIO_POWEROFF_PIN 33 - -#define WIIGPIO_REG_ADDR 0x0d8000c0 -#define WIIGPIO_REG_LEN 0x40 - -#endif /* _POWERPC_WII_WII_GPIOREG_H */ diff --git a/sys/powerpc/wii/wii_ipc.c b/sys/powerpc/wii/wii_ipc.c deleted file mode 100644 index 7f49d31f586a..000000000000 --- a/sys/powerpc/wii/wii_ipc.c +++ /dev/null @@ -1,102 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/* - * Driver to interface with the Wii's IOS. IOS are small "microkernels" that run - * on the Broadway GPU and provide access to system services like USB. - */ -static int wiiipc_probe(device_t); -static int wiiipc_attach(device_t); - -struct wiiipc_softc { -}; - -static device_method_t wiiipc_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, wiiipc_probe), - DEVMETHOD(device_attach, wiiipc_attach), - - DEVMETHOD_END -}; - -static driver_t wiiipc_driver = { - "wiiipc", - wiiipc_methods, - sizeof(struct wiiipc_softc) -}; - -static devclass_t wiiipc_devclass; - -DRIVER_MODULE(wiiipc, wiibus, wiiipc_driver, wiiipc_devclass, 0, 0); - -static int -wiiipc_probe(device_t dev) -{ - device_set_desc(dev, "Nintendo Wii IOS IPC"); - - return (BUS_PROBE_NOWILDCARD); -} - -static int -wiiipc_attach(device_t dev) -{ - struct wiiipc_softc *sc; - - sc = device_get_softc(dev); -#ifdef notyet - sc->sc_dev = dev; - - sc->sc_rrid = 0; - sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->sc_rrid, RF_ACTIVE); - if (sc->sc_rres == NULL) { - device_printf(dev, "could not alloc mem resource\n"); - return (ENXIO); - } - sc->sc_bt = rman_get_bustag(sc->sc_rres); - sc->sc_bh = rman_get_bushandle(sc->sc_rres); -#endif - - return (0); -} diff --git a/sys/powerpc/wii/wii_ipcreg.h b/sys/powerpc/wii/wii_ipcreg.h deleted file mode 100644 index 86b3e1f49598..000000000000 --- a/sys/powerpc/wii/wii_ipcreg.h +++ /dev/null @@ -1,102 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _POWERPC_WII_WII_IPCREG_H -#define _POWERPC_WII_WII_IPCREG_H - -#define WIIIPC_REG_ADDR 0x0d000000 -#define WIIIPC_REG_LEN 0x40 -#define WIIIPC_IOH_ADDR 0x133e0000 -#define WIIIPC_IOH_LEN 0xc20000 - -#define WIIIPC_TXBUF 0x00 -#define WIIIPC_CSR 0x04 -#define WIIIPC_CSR_TXSTART 0x01 -#define WIIIPC_CSR_TBEI 0x02 -#define WIIIPC_CSR_RBFI 0x04 -#define WIIIPC_CSR_RXREADY 0x08 -#define WIIIPC_CSR_RBFIMASK 0x10 -#define WIIIPC_CSR_TBEIMASK 0x20 -#define WIIIPC_RXBUF 0x08 -#define WIIIPC_ISR 0x30 -#define WIIIPC_ISR_MAGIC 0x40000000 - -enum wiiipc_cmd { - WIIIPC_CMD_OPEN = 1, - WIIIPC_CMD_CLOSE = 2, - WIIIPC_CMD_READ = 3, - WIIIPC_CMD_WRITE = 4, - WIIIPC_CMD_SEEK = 5, - WIIIPC_CMD_IOCTL = 6, - WIIIPC_CMD_IOCTLV = 7, - WIIIPC_CMD_ASYNCRESP = 8 -}; - -struct wiiipc_ipc_msg { - uint32_t ipc_cmd; - int32_t ipc_result; - int32_t ipc_fd; /* WIIIPC_CMD_ASYNCRESP - the original cmd */ - union { - struct { - intptr_t pathname; - uint32_t mode; - } _ipc_open; - struct { - intptr_t data; - uint32_t len; - } _ipc_read, _ipc_write; - struct { - int32_t offset; - int32_t whence; - } _ipc_seek; - struct { - uint32_t request; - intptr_t ibuf; - uint32_t ilen; - intptr_t obuf; - uint32_t olen; - } _ipc_ioctl; - struct { - uint32_t request; - uint32_t argin; - uint32_t argout; - intptr_t iovec; - } _ipc_ioctlv; - uint32_t _ipc_argv[5]; - } args; -} __attribute__((packed)); - -CTASSERT(sizeof(struct wiiipc_ipc_msg) == 32); - -#define ipc_open args._ipc_open -#define ipc_read args._ipc_read -#define ipc_write args._ipc_write -#define ipc_ioctl args._ipc_ioctl -#define ipc_ioctlv args._ipc_ioctlv - -#endif /* _POWERPC_WII_WII_IPCREG_H */ diff --git a/sys/powerpc/wii/wii_pic.c b/sys/powerpc/wii/wii_pic.c deleted file mode 100644 index 0844a00d3627..000000000000 --- a/sys/powerpc/wii/wii_pic.c +++ /dev/null @@ -1,244 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "pic_if.h" - -static int wiipic_probe(device_t); -static int wiipic_attach(device_t); -static void wiipic_dispatch(device_t, struct trapframe *); -static void wiipic_enable(device_t, unsigned int, unsigned int); -static void wiipic_eoi(device_t, unsigned int); -static void wiipic_mask(device_t, unsigned int); -static void wiipic_unmask(device_t, unsigned int); -static void wiipic_intr(void *); - -struct wiipic_softc { - device_t sc_dev; - struct resource *sc_rres; - bus_space_tag_t sc_bt; - bus_space_handle_t sc_bh; - int sc_rrid; - int sc_irqid; - struct resource *sc_irq; - void *sc_irqctx; - int sc_vector[WIIPIC_NIRQ]; -}; - -static device_method_t wiipic_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, wiipic_probe), - DEVMETHOD(device_attach, wiipic_attach), - - /* PIC interface */ - DEVMETHOD(pic_dispatch, wiipic_dispatch), - DEVMETHOD(pic_enable, wiipic_enable), - DEVMETHOD(pic_eoi, wiipic_eoi), - DEVMETHOD(pic_mask, wiipic_mask), - DEVMETHOD(pic_unmask, wiipic_unmask), - - DEVMETHOD_END -}; - -static driver_t wiipic_driver = { - "wiipic", - wiipic_methods, - sizeof(struct wiipic_softc) -}; - -static devclass_t wiipic_devclass; - -DRIVER_MODULE(wiipic, wiibus, wiipic_driver, wiipic_devclass, 0, 0); - -static __inline uint32_t -wiipic_imr_read(struct wiipic_softc *sc) -{ - - return (bus_space_read_4(sc->sc_bt, sc->sc_bh, WIIPIC_IMR)); -} - -static __inline void -wiipic_imr_write(struct wiipic_softc *sc, uint32_t imr) -{ - - bus_space_write_4(sc->sc_bt, sc->sc_bh, WIIPIC_IMR, imr); -} - -static __inline uint32_t -wiipic_icr_read(struct wiipic_softc *sc) -{ - - return (bus_space_read_4(sc->sc_bt, sc->sc_bh, WIIPIC_ICR)); -} - -static __inline void -wiipic_icr_write(struct wiipic_softc *sc, uint32_t icr) -{ - - bus_space_write_4(sc->sc_bt, sc->sc_bh, WIIPIC_ICR, icr); -} - -static int -wiipic_probe(device_t dev) -{ - device_set_desc(dev, "Nintendo Wii PIC"); - - return (BUS_PROBE_NOWILDCARD); -} - -static int -wiipic_attach(device_t dev) -{ - struct wiipic_softc *sc; - - sc = device_get_softc(dev); - sc->sc_dev = dev; - - sc->sc_rrid = 0; - sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->sc_rrid, RF_ACTIVE); - if (sc->sc_rres == NULL) { - device_printf(dev, "could not alloc mem resource\n"); - return (ENXIO); - } - sc->sc_bt = rman_get_bustag(sc->sc_rres); - sc->sc_bh = rman_get_bushandle(sc->sc_rres); - - /* Turn off all interrupts */ - wiipic_imr_write(sc, 0x00000000); - wiipic_icr_write(sc, 0xffffffff); - - powerpc_register_pic(dev, 0, WIIPIC_NIRQ, 0, FALSE); - - /* - * Setup the interrupt handler. - */ - sc->sc_irqid = 0; - sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid, - RF_ACTIVE); - if (sc->sc_irq == NULL) { - device_printf(dev, "could not alloc IRQ resource\n"); - return (ENXIO); - } - bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, - NULL, wiipic_intr, sc, &sc->sc_irqctx); - - return (0); -} - -static void -wiipic_dispatch(device_t dev, struct trapframe *tf) -{ - struct wiipic_softc *sc; - uint32_t irq; - - sc = device_get_softc(dev); - irq = wiipic_icr_read(sc) & wiipic_imr_read(sc); - if (irq == 0) - return; - irq = ffs(irq) - 1; - KASSERT(irq < WIIPIC_NIRQ, ("bogus irq %d", irq)); - powerpc_dispatch_intr(sc->sc_vector[irq], tf); -} - -static void -wiipic_enable(device_t dev, unsigned int irq, unsigned int vector) -{ - struct wiipic_softc *sc; - - KASSERT(irq < WIIPIC_NIRQ, ("bogus irq %d", irq)); - sc = device_get_softc(dev); - sc->sc_vector[irq] = vector; - wiipic_unmask(dev, irq); -} - -static void -wiipic_eoi(device_t dev, unsigned int irq) -{ - struct wiipic_softc *sc; - uint32_t icr; - - sc = device_get_softc(dev); - icr = wiipic_icr_read(sc); - icr |= (1 << irq); - wiipic_icr_write(sc, icr); -} - -static void -wiipic_mask(device_t dev, unsigned int irq) -{ - struct wiipic_softc *sc; - uint32_t imr; - - sc = device_get_softc(dev); - imr = wiipic_imr_read(sc); - imr &= ~(1 << irq); - wiipic_imr_write(sc, imr); -} - -static void -wiipic_unmask(device_t dev, unsigned int irq) -{ - struct wiipic_softc *sc; - uint32_t imr; - - sc = device_get_softc(dev); - imr = wiipic_imr_read(sc); - imr |= (1 << irq); - wiipic_imr_write(sc, imr); -} - -/* - * Reset button interrupt. - */ -static void -wiipic_intr(void *xsc) -{ - struct wiipic_softc *sc; - - sc = (struct wiipic_softc *)xsc; - if (wiipic_icr_read(sc) & WIIPIC_RBS) - shutdown_nice(RB_AUTOBOOT); -} - diff --git a/sys/powerpc/wii/wii_picreg.h b/sys/powerpc/wii/wii_picreg.h deleted file mode 100644 index 9e0a7e256d2a..000000000000 --- a/sys/powerpc/wii/wii_picreg.h +++ /dev/null @@ -1,42 +0,0 @@ -/*- - * Copyright (C) 2012 Margarida Gouveia - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _POWERPC_WII_WII_PICREG_H -#define _POWERPC_WII_WII_PICREG_H - -#define WIIPIC_REG_ADDR 0x0c003000 -#define WIIPIC_REG_LEN 0x28 - -#define WIIPIC_ICR 0x00 -#define WIIPIC_RBS 0x10000 -#define WIIPIC_IMR 0x04 -#define WIIPIC_RESET 0x24 - -#define WIIPIC_NIRQ 32 - -#endif /* _POWERPC_WII_WII_PICREG_H */